Decorator
简单装饰器
装饰器其实有点类似游戏中的Buff
,红蓝Buff
,红Buff
可以减速、攻击附带,蓝Buff
可以法术加成。
也可以类比于各种特效加成,比如仙剑四中武器的各种注灵加成,不同注灵方式可以加成不同的效果,比如冰冻、中毒、灼烧等等。 在python
中,装饰器就是为了给原有函数加上额外的特效。
下面举例说明:
现在有个新的需求,要在执行函数后打印log,显示当前执行的函数是哪个,那可以这样:
一个函数好办,要是有多个函数都要呢,每个函数都加的话就太冗余了。那么另外写个函数:
这样虽然可以,但是每次调用函数都要外加个壳子logged,显然是不合情理的,破坏了原有的代码逻辑。那怎么解决呢,这就是装饰器的出场时间了:
使用语法糖@
, 在业务方法外层添加@logged
即可
带参装饰器
由于装饰器本身也是一个函数,那么带参也是被允许的,那么如何实现呢?
可以看出来,在上面简单装饰器的基础上又加了一层封装,同时返回了一个装饰器decorator
,Python
解释器在解析到@logged(level='info')
的时候,能够发现这层封装,并将参数level
传入装饰器中。
保留原函数元信息
使用装饰器有个缺陷,就是会丢失原函数的元信息,比如函数的__name__
、docstring、注解和参数签名等。
解决方法是使用另一个装饰器functools.wraps
类装饰器
内置装饰器
@staticmethod
静态函数staticmethod
原本是可以在类外定义的,如:
但是呢,如果foo
这个函数仅仅被类A
内部函数调用,或者仅仅与类A
相关的操作需要用到函数foo
,那么放在外面就显得不太合适了,容易污染命名空间。此时既想把foo
与类A
关联起来,同时又想通过类名直接快捷访问,就可以通过@staticmethod
来实现:
可以看出,staticmethod
就是普普通通的函数,只不过刚好某个类需要用到它,就把它扔进去了,这个函数本身最好不去调用类的属性或成员函数。
@classmethod
@classmethod
有个必要的首参,用于指向当前所在类,所以通常有类似这样的定义:
在上面的例子中,函数f1
通过类对象cls
定义并返回了一个A类的实例对象。
在爬虫框架Scrapy
源码中,有个很常用的@classmethod
, 就是crawl.py
中的from_crawler
函数:
该函数继承于Spider
类中的from_crawler
函数,最终返回的是一个spider
实例对象。
@classmethod
主要用于返回实例对象,同时可以直接访问类中属性及函数。
@staticmethod & @classmethod
@staticmethod
与@classmethod
的对比随处可见。
先说共同点,两种装饰器对应的函数都可以通过以下两种方式调用:
ClassName.function()
Instance.function()
再看看不同点,从定义和调用方面区分:
@staticmethod
对应函数通常只是与类有所关联,但与其对象属性关联不大或没有关联,要想访问类的方法和属性,需要通过类名或者self
访问。@classmethod
第一个参数必须是自身类参数cls
,名称随意,可以是self;而且因为持有类参数,所以可以通过cls
直接访问类的方法和属性。
大部分情况下,添加这两个装饰器的目的就是为了方便通过类名直接访问,而无需实例化对象。
在应用场景方面,
@staticmethod
适用于普通函数,就是那种放不放类中都可以用,只不过恰好在这个类中而已。@classmethod
适用于创建实例对象,即通过这个函数返回一个类的实例对象
@property
至于属性装饰器@property
就比较简单了,通常用于实现类内部某个属性的set
,get
操作,将被装饰的函数模拟成一个类的属性,然后可以对其进行直接读取和赋值。
参考资料
Last updated
Was this helpful?