BrightXiong 发表于 2023-4-2 19:19:23

类和对象-类装饰器-上

>>> # 新的概念——类装饰器。
        类装饰器就是将装饰器作用在类上面,在类被实例化对象之前对其进行拦截和干预,用法与装饰函数的装饰器非常相似。
        函数可以用来装饰类(类装饰器),反过来,类也可以用作装饰器来装饰函数,
        使函数成为类的实例化对象,调用函数便会触发类的__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]
查看完整版本: 类和对象-类装饰器-上