类和对象-类装饰器-上
>>> # 新的概念——类装饰器。类装饰器就是将装饰器作用在类上面,在类被实例化对象之前对其进行拦截和干预,用法与装饰函数的装饰器非常相似。
函数可以用来装饰类(类装饰器),反过来,类也可以用作装饰器来装饰函数,
使函数成为类的实例化对象,调用函数便会触发类的__call__()等一系列魔法方法。
由此,类与函数的“亲密”关系也得以进一步发展!
类装饰器也有容易踩到的“坑”:当类作装饰器用于装饰另一个类时,被装饰类的多次实例化对象实则为装饰类的同一个对象,
不过是将其作为函数调用了若干次,因而会导致属性覆盖问题。
解决方法是将装饰器类“套一层外壳”,放在一个函数中,由函数返回该类,再将该函数用作装饰器来装饰被装饰类即可。
>>> def report(cls):
... def oncall(*args, **kwargs):
... print('开始实例化对象')
... _ = cls(*args, **kwargs)
... print('实例化对象完成')
... return _
... return oncall
...
>>> @report
... class C:
... pass
...
>>> c = C()
开始实例化对象
实例化对象完成
>>> @report
... class C:
... def __init__(self, x, y, z):
... self.x = x
... self.y = y
... self.z = z
... print('构造函数调用')
...
>>> c = C(1, 2, 3)
开始实例化对象
构造函数调用
实例化对象完成
>>> print(c.__dict__)
{'x': 1, 'y': 2, 'z': 3}
>>> # 类装饰器的作用就是在类被实例化对象之前对其进行拦截和干预
>>> # 让类做装饰器来装饰函数
>>> class Counter:
... def __init__(self):
... self.count = 0
... def __call__(self, *args, **kwargs):
... self.count += 1
... print(f'已经被调用了{self.count}次')
...
>>> c = Counter()
>>> c()
已经被调用了1次
>>> c()
已经被调用了2次
>>> c()
已经被调用了3次
>>> class Counter:
... def __init__(self, func):
... self.count = 0
... self.func = func
... def __call__(self, *args, **kwargs):
... self.count += 1
... print(f'已经被调用了{self.count}次')
... return self.func(*args, **kwargs)
...
>>> @Counter
... def say_hi():
... print('Hi')
...
>>> print(say_hi)
<__main__.Counter object at 0x0164E4D8>
>>> # 函数say_hi已经被掉包成Counter的对象
>>> say_hi()
已经被调用了1次
hi~
>>> say_hi()
已经被调用了2次
hi~
>>> say_hi()
已经被调用了3次
hi~
>>>
页:
[1]