Python装潢类

示例

如引言中所述,装饰器是可以应用于另一个功能以增强其行为的功能。语法糖等效于以下内容:。但是如果不是班级呢?该语法仍然有效,除了现在已被该类的实例替换。如果此类实现了magic方法,那么仍然可以像使用函数一样使用它:my_func = decorator(my_func)decoratormy_funcdecorator__call__()my_func

class Decorator(object):
    """简单的装饰器类。"""

    def __init__(self, func):
       self.func= func

    def __call__(self, *args, **kwargs):
        print('Before the function call.')
        res = self.func(*args, **kwargs)
        print('After the function call.')
        return res

@Decorator
def testfunc():
    print('Inside the function.')

testfunc()
# 在函数调用之前。
# 在函数内部。
# 函数调用后。

请注意,从类型检查的角度来看,用类修饰器修饰的函数将不再被视为“函数”:

import types
isinstance(testfunc, types.FunctionType)
# 假
type(testfunc)
# <class '__main__.Decorator'>

装饰方式

对于装饰方法,您需要定义其他__get__方法:

from types import MethodType

class Decorator(object):
    def __init__(self, func):
       self.func= func
        
    def __call__(self, *args, **kwargs):
        print('Inside the decorator.')
        return self.func(*args, **kwargs)
    
    def __get__(self, instance, cls):
        # 如果在实例上调用了方法,则返回一个方法
        return self if instance is None else MethodType(self, instance)

class Test(object):
    @Decorator
    def __init__(self):
        pass
    
a = Test()

在装饰器内。

警告!

类装饰器仅为特定功能生成一个实例,因此用类装饰器装饰方法将在该类的所有实例之间共享同一装饰器:

from types import MethodType

class CountCallsDecorator(object):
    def __init__(self, func):
       self.func= func
       self.ncalls= 0    # 该方法的调用次数
        
    def __call__(self, *args, **kwargs):
       self.ncalls+= 1   # 增加通话计数器
        return self.func(*args, **kwargs)
    
    def __get__(self, instance, cls):
        return self if instance is None else MethodType(self, instance)

class Test(object):
    def __init__(self):
        pass
    
    @CountCallsDecorator
    def do_something(self):
        return 'something was done'
    
a = Test()
a.do_something()
a.do_something.ncalls   # 1
b = Test()
b.do_something()
b.do_something.ncalls   # 2