python装饰器--原来如此简单,python 类方法装饰器

  python装饰器--原来如此简单,python 类方法装饰器

  本文通过实例详细介绍了Python中的decorator和类decorator。学习装饰器可以让我们更好、更灵活地使用函数,也可以让我们的代码更优雅。有兴趣的可以学习一下。

  00-1010 Decorator Decorator的定义Decorator类的用法Decorator类-类方法的Decorator-静态方法类的Decorator-property通过学习装饰,我们可以更好、更灵活地使用函数,通过学习如何使用装饰,我们也可以使我们的代码更加优雅。

  在我们的实际工作中,很多场景会用到decorators,比如记录一些日志或者屏蔽一些非法程序,让我们的代码更加安全。

  

目录

  什么是装饰品?虽然我是新来的,但我完全不需要担心。

  首先,装饰器也是一个函数;然而,装饰器可以接收函数作为参数。

  你可以通过return返回一个函数。装饰器可以接收一个函数,在装饰器内部处理和调用它,并返回一个新函数。同时可以动态增强传入函数的功能。

  装裱师的整个流程如下:

  a函数是decorator,b函数是a函数传入的参数。B函数在A函数中执行,可以执行也可以不执行,也可以对B函数的结果进行两次处理。接下来,我们来看看装修工长什么样。

  def a():

  定义b():

  打印(helloworld)

  乙()

  答()

  乙()

  在A()函数中编写一个B()函数,在A()函数中调用B()函数。是不是很像在类中定义局部函数并调用它的例子?实际上,装饰器是这样的,只是装饰器调用的函数作为参数传入,并在b()函数中执行。

  我们在定义好a()函数后调用它,就可以正常处理了。但是b()函数是a()函数的一个局部函数,如果外部调用,就会出错。(与上面的第十行一样,将会报告一个错误)

  

装饰器

  例子如下:

  DEF (func_args) 3360 # decorator的第一层函数叫做外围函数,‘func _ args’就是要处理的函数。

  def inter (* args,* * kwargs) 3360 #外围函数的函数体中定义的函数称为嵌入式函数;传入的参数是要处理的func_args函数的参数。

  #这里我们不知道func_args函数需要传入什么参数,所以目前写在变量参数里比较合理。

  Return func_args (* args,* * kwargs) #调用嵌入函数体中的func_args函数,传入变量参数

  #其实在这里我们可以处理更多的逻辑;

  #我们可以选择执行或者不执行,甚至可以用func_args函数的执行结果做二次处理。

  返回inter #写完内嵌函数业务,我们在外围函数体中返回内嵌函数。

  #需要注意的是,这里不执行(因为没有括号),这是decorator的定义规则,也是必不可少的。

  #只有外围函数返回嵌入函数,才能被后续代码执行;(因为所有业务都在嵌入式函数中,所以不返回就不能执行调用)

  

装饰器的定义

  在我们的日常工作中,有两种方式使用装修工。

  第一,被调用的函数直接作为参数传入装饰器外围函数的括号内;例子如下:

  定义a(函数):

  def b(*args,**kwargs):

  return func(*args,**kwargs)

   return b

  def c(name):

   print(name)

  a(c)(Neo)

  # >>> 执行结果如下:

  # >>> Neo

  

  第二种:将装饰器与被调用函数绑定在一起, @ 符号 + 装饰器函数放在被调用函数的上一行,被调用的函数正常定义,只需要直接调用被执行函数即可。示例如下:

  

def a(func):

   def b(*args, **kwargs):

   return func(*args, **kwargs)

   return b

  @a

  def c(name):

   print(name)

  c(Neo)

  # >>> 执行结果如下:

  # >>> Neo

  

  最常用的装饰器用法为第二种。

  现在我们构建一个 检查字符串类型的装饰器,加深一下对装饰器的理解。

  

def check_ok(func):

   def inner(*args, **kwargs):

   result = func(*args, **kwargs)

   if result == OK:

   return 传入的参数数据为:\%s\ % result

   else:

   return 传入的参数数据不为:\OK\

   return inner

  @check_ok

  def test_str(data):

   return data

  result = test_str(OK)

  print(result)

  # >>> 执行结果如下:

  # >>> 传入的参数数据为:OK

  result = test_str(NO)

  print(result)

  # >>> 执行结果如下:

  # >>> 传入的参数数据不为:OK

  

  以上就是一个装饰器的简单用法,后续的学习内容会接触到更多的高级用法。

  

  

类中的装饰器

  

  

类的装饰器 - classmethod

  classmethod 的功能:可以将类函数不经过实例化即可直接被调用

  classmethod 的用法:示例如下

  

@classmethod

  def func(cls, ...):

   todo

  # >>> cls 替代普通类函数中的 self ;

  # >>> 变更为 cls ,表示当前的类

  # >>> self 代表的是 实例化对象,所以只有通过实例化后,才可以调用

  # >>> cls 代表的是 类 ,所以即使不通过实例化,也可以调用

  # *****************************************************

  class Test(object):

   @classmethod

   def add(cls, a, b):

   return a + b

  print(Test.add(1, 3))

  # >>> 执行结果如下:

  # >>> 4

  

  演示案例:

  

class Cat(object):

   def __init__(self, name):

   self.name = name

   def eat(self):

   print(self.name, 喜欢吃鱼)

   @classmethod

   def work(cls):

   print(会抓老鼠)

  dragonLi = Cat(狸花猫)

  print(dragonLi.eat(), dragonLi.work())

  # >>> 执行结果如下:

  # >>> 狸花猫 喜欢吃鱼

  # >>> 会抓老鼠

  

  接下来我们不使用 类的实例化 ,直接使用 类 调用 eat() 函数 与 work() 函数

  

class Cat(object):

   def __init__(self, name):

   self.name = name

   def eat(self):

   print(self.name, 喜欢吃鱼)

   @classmethod

   def work(cls):

   print(会抓老鼠)

  dragonLi = Cat(狸花猫)

  Cat.eat()

  # >>> 执行结果如下:

  # >>> TypeError: Cat.eat() missing 1 required positional argument: self

  # >>> 报错缺少重要参数 self (没有进行实例化的类,类无法直接调用类函数)

  Cat.work()

  # >>> 执行结果如下:

  # >>> 会抓老鼠

  # >>> 绑定了 classmethod 装饰器 的 work() 函数,即使没有实例化,也可以直接被 类 调用

  

  再尝试一下看看 没有装饰器的 eat() 函数 与 使用了 classmethod 装饰器 work() 之间可不可以互相调用

  

class Cat(object):

   def __init__(self, name):

   self.name = name

   def eat(self):

   print(self.name, 喜欢吃鱼)

   @classmethod

   def work(cls):

   print(会抓老鼠)

   cls.eat() # 在 classmethod 装饰器的 work() 函数内 调用 eat() 函数

  dragonLi = Cat(狸花猫)

  dragonLi.work()

  # >>> 执行结果如下:

  # >>> TypeError: Cat.eat() missing 1 required positional argument: self

  # >>> 同样报错缺少重要参数 self

  

  

class Cat(object):

   def __init__(self, name):

   self.name = name

   def eat(self):

   print(self.name, 喜欢吃鱼)

   self.work()

   @classmethod

   def work(cls):

   print(会抓老鼠)

  dragonLi01 = Cat(狸花猫)

  dragonLi01.eat()

  # >>> 执行结果如下:

  # >>> 执行结果如下:

  # >>> 狸花猫 喜欢吃鱼

  # >>> 会抓老鼠

  

  综合以上两个场景,我们得出以下结论:

  

  • 在带有 classmethod 装饰器 的 函数 内,是无法调用普通的 带有 self 的函数的
  • 但是在普通的带有 self 的类函数内,是可以调用带有 classmethod 装饰器 的 函数的

  

  

类的装饰器 - staticmethod

  staticmethod 的功能:可以将 类函数 不经过实例化而直接被调用,被该装饰器调用的函数不需要传入 self 、cls 参数,并且无法在该函数内调用其他 类函数 或 类变量

  staticmethod 的用法:参考如下

  

@staticmethod

  def func(...):

   todo

  # >>> 函数内无需传入 cls 或 self 参数

  # *****************************************************

  class Test(object):

   @staticmethod

   def add(a, b):

   return a + b

  print(Test.add(1, 3))

  # >>> 执行结果如下:

  # >>> 4

  

  接下来我们在上文的 Cat() 类基础演示一下 staticmethod 装饰器 (新建一个 color() 函数,使用 staticmethod 装饰器 )

  

class Cat(object):

   def __init__(self, name):

   self.name = name

   def eat(self):

   print(self.name, 喜欢吃鱼)

   self.work()

   @classmethod

   def work(cls):

   print(会抓老鼠)

   @staticmethod

   def color():

   print(黄棕色)

  dragonLi = Cat(狸花猫)

  print(dragonLi.eat(), dragonLi.color())

  # >>> 执行结果如下:

  # >>> 狸花猫 喜欢吃鱼

  # >>> 会抓老鼠

  # >>> 黄棕色

  # >>> 从执行结果来看, staticmethod 装饰器的 color() 函数可以被实例化后的对象 dragonLi 调用。

  # >>> 那么可以被 Cat() 类 直接调用么?我们往下看

  print(Cat.color())

  # >>> 执行结果如下:

  # >>> 黄棕色

  # >>> 可以看到,staticmethod 装饰器构造的 color() 函数,即使没有被实例化,依然可以直接被 类 调用

  

  同样的,也尝试一下 staticmethod 装饰器构造的 color() 函数 是否能够在类函数中互相调用。

  

class Cat(object):

   def __init__(self, name):

   self.name = name

   def eat(self):

   print(self.name, 喜欢吃鱼)

   self.work()

   self.color()

   @classmethod

   def work(cls):

   print(会抓老鼠)

   @staticmethod

   def color():

   print(黄棕色)

  dragonLi = Cat(狸花猫)

  dragonLi.eat()

  # >>> 执行结果如下:

  # >>> 狸花猫 喜欢吃鱼

  # >>> 会抓老鼠

  # >>> 黄棕色

  # >>> 结合执行结果得出结论:staticmethod 装饰器构造的 color() 函数 可以在 eat() 类函数中被调用

  

  与带有 classmethod 装饰器 的 函数 一样,staticmethod 装饰器构造的 函数也是无法调用普通的 带有 self 的函数的,这里就不再书写演示代码进行演示了。(staticmethod 装饰器构造的 函数也是无法调用普通的 带有 self 的函数会报错 : NameError: name 'self' is not defined )

  

  

类的装饰器 - property

  property 的功能:可以将类函数的执行免去小括号,类似于直接调用类的变量(属性)

  staticmethod 的用法:参考如下

  

@property

  def func(self):

   todo

  # >>> 不能传入参数,无重要函数说明

  # *************************示例如下*************************

  class Test(object):

   def __init__(self, name):

   self.name = name

   @property

   def call_name(self):

   return Hello {}.format(self.name)

  test = Test(Neo)

  result = test.call_name # 不需要添加 小括号 即可调用 call_name 函数;

   # 关于 staticmethod 不可传入参数,其实并不是不可以传入参数,而是传入的方法比较另类,我们继续往下看

  print(result)

  # >>> 执行结果如下:

  # >>> Hello Neo

  

  重新创建一个 Dog 类 ,然后我们继续演示。

  

class Dog(object):

   def __init__(self, name):

   self.__name = name

   @property

   def type(self):

   if self.__name in [哈士奇, 萨摩耶, 阿拉斯基]:

   return self.__name, 是雪橇犬,\雪橇三傻\之一

   elif self.__name in [吉娃娃, 博美犬, 约克夏]:

   return self.__name, 是小型犬

   else:

   return self.__name, 我暂时不知道这是什么犬种,也许它是\泰日天\的亲戚

  dog = Dog(name=哈士奇)

  print(dog.type) # 这里我们并不需要 dog.type + () 小括号,即可调用 type() 函数

  # >>> 执行结果如下:

  # >>> (哈士奇, "是雪橇犬,雪橇三傻之一")

  # >>> 这里我们看到 当 Dog 类 实例化 dog 变量之后,我们传入的 哈士奇 参数是不可更改的,如果我们尝试利用赋值的方式修改传入的参数呢?

  dog = Dog(name=哈士奇)

  dog.type = 约克夏

  print(dog.type)

  # >>> 执行结果如下:

  # >>> AttributeError: cant set attribute

  # >>> 报错:属性错误,不可以设置这个属性

  # >>> 其实,property 装饰器绑定的函数的参数并不是不可以更改,只是更改的方式比较特殊,并不是不能通过赋值的形式传入参数,我们继续往下看。

  

  首先,我们已经使用了 @property 绑定了我们的 type 函数,这是一个返回值的方法。 所以我们要如何给 type() 函数赋值呢?其实很简单,我们可以通过 @type 对应上 type() 函数,在它的函数内部有一个函数 setter ;然后再定义一个 type 函数,在这个新定义的 type() 函数内定义一个值 value (可以是任意的名字,但这里需要注意,只能定义一个值)。然后再通过设置一个 self.__name = value ,如此就可以达到修改传入参数的目的。废话不多说了,看下方的示例:

  

class Dog(object):

   def __init__(self, name):

   self.__name = name

   @property

   def type(self):

   if self.__name in [哈士奇, 萨摩耶, 阿拉斯基]:

   return self.__name, 是雪橇犬,\雪橇三傻\之一

   elif self.__name in [吉娃娃, 博美犬, 约克夏]:

   return self.__name, 是小型犬

   else:

   return self.__name, 我暂时不知道这是什么犬种,也许它是\泰日天\的亲戚

   @type.setter

   def type(self, value):

   self.__name = value

  dog = Dog(name=哈士奇)

  dog.type = 约克夏

  print(dog.type)

  # >>> 执行结果如下:

  # >>> (约克夏, 是小型犬)

  

  附:使用最广泛的装饰器为 classmethod

  以上就是Python学习之装饰器与类的装饰器详解的详细内容,更多关于Python装饰器的资料请关注盛行IT软件开发工作室其它相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: