property: -- 将装饰过的函数(方法)变成类属性,这样的属性需要通过 - @函数(方法).setter 才能够直接修改这个属性
class A: @property # 将fun函数变成了类的属性 def fun(self): # 这儿只能有self参数 return self._a
@fun.setter # 这个属性需要被setter才能直接修改属性值 def fun(self, n): self._a = n
staticmethod: 将类的方法变成静态方法 -- 将类中的函数参数self 变成普通参数
应用场景:当把一个模块导入时,需要用到模块中的某个类和某个函数 from module import cls, fun 这样使用比较繁琐
可以将fun写进cls类中,加上staticmethod装饰器,就能通过cls.fun(argv) 调用,而又不会影响fun的功能
class A: @staticmethod def fun(self): # 这儿self不在是实例化属性,变成普通参数了 print(self) a = A() a.fun(2) # 2被self接收
classmethod: 类装饰器 -- 将类本身当作参数传入函数中
class B: @classmethod def fun(cls): # cls = B本身 pass
自己构建的装饰器
import functools def log(fn): @functools.wraps(fn) # 将fn的相关属性复制到wrap def wrap(*args, **kwargs): print(f"decorator {fn}") return fn(*args, **kwargs) print(f"wrap: {id(wrap)}") print(f"fn: {id(fn)}") return wrap @log def guai(x: int, y: int): print(x + y) guai(1,5)
>>>
wrap: 4328403560 fn: 4328403424 decorator <function guai at 0x101fe31e0> 6
类型装饰器
def log(cls): class wraper: def __init__(self, *args, **kwargs): self.__dict__['inst'] = cls(*args, **kwargs)def __getattr__(self, item): print('here') print(item) return getattr(self.inst, item) def __setattr__(self, key, value): # 拦截x.a的复制操作 print('k:v', key, value) setattr(self.inst, key, value) #拦截后储存到self.inst, 那么查询x.a也只能在self.inst中查到(通过__getattr__) return wraper @log class X: pass x = X() x.a = 100 print(x.__dict__) print(x.a)
>>>
k:v a 100 {'inst': <__main__.X object at 0x10cd704a8>} here a 100
装饰器的应用场景:辅助开发工具(调用跟踪,性能测试,内存检测等任务),类可以实现单例模式
简单的统计调用次数:
def log(fn): def counter(*args, **kwargs): counter.__count__ += 1 return fn(*args, **kwargs) counter.__count__ = 0 return counter @log def run():pass for i in range(4): run() print(f"调用次数{run.__count__}") >>> 调用次数4
属性管理:为目标添加额外的属性
def add_somethings(cls): cls.something = 1 cls.something1 = lambda x: [1,2,3,] return cls @add_somethings class A: pass print(A().something) print(A().something1()) >>> 1 [1, 2, 3]