函数定义的decorator
(参看语言手册8.6节)

decorator(修饰符)

在函数或者类的定义的前面可以加上一个或几个以 @ 符号开头的名字,这种描述称为紧随其后的函数或类的 decorator(修饰符)。

实际上,能作为修饰符的名字必须是一个有定义的函数的名字,而这个函数应该是一个 "高阶函数"。具体说:写在函数定义前面的修饰符的名字应该约束到一个函数对象,相应的函数应该以函数对象为参数,其返回值也是一个函数对象;写在类定义前面的名字应表示一个函数对象,它以类对象为参数,其返回值也应该是一个类对象。

例如有函数定义

@decor
def func (...) :
    ... ...
就相当于写
def func (...) :
    ... ...
func = decor(func)
也就是说,先定义函数 func,然后在给 func 赋以其原来的定义经过 decor 加工之后得到的那个函数对象。至于怎么加工,完全是 decor 函数的事情,可以根据需要定义。

我们把这种加工函数的函数称为 "修饰函数",这种函数通常是在原函数的基础上增加一些通用的功能。当然,Python 提供了这种机制,怎么使用完全是程序员自己的事情。

Python 里的函数也是对象,定义函数就是构造出所需的函数对象并将其是作为相应函数名的值。这种对象完全可以作为参数送给函数使用,函数也完全可以返回另一个函数作为它的执行结果。

与此类似,类也是对象。定义类就是构造一个类对象,并将其作为相应类名的值。给类定义加修饰符,就是允许定义用函数去加工程序里定义的类。

当然,这种加工的意义是程序员自己的事情。例如可以定义下面的无用加工函数

def void (obj) :
    def void0 (*args) :
        pass
    return void0

@void
def func (x) :
    return x+1
void 把任何函数都加工成什么也不做,也不返回值的函数。

文档 PIP 318 包含有关 decorator 的详细说明和一些实例,见 Python 文档里 What is new 部分中的 What is new in Python2.3。

自定义 decorator

下面是一个自己定义的 decorator 函数,用它装饰的函数将输出运行时间。后面是个例子:
def timefunc (func) :
    def __decorator(*args) :
        begin = time()
        x = func(*args)
        print(time() - begin)
        return x
    
    return __decorator

@timefunc
def testfunc () :
    print('test begin')
    for i in range(10000000) :
        pass
    print('test end')
执行 testfunc(),就会看到它在正常完成其工作外,还输出自己的执行时间。

这个 decorator 可以用于装饰具有任意的参数和返回值的函数。

几个有定义的 decorator

@classmethod:这个标注只用在类定义里,用于说明被标注和函数是一个类方法。classmethod(function) 是一个内置函数。类方法以其定义所在的类对象作为隐含的第一个实参(就像实例方法以实例对象作为隐含的第一个实参)。类方法定义里的第一个形参在调用时将引用这个类的类对象本身,也可以有更多的形参。

类方法可以从其定义所在的类出发去调用,也可以从该类的实例对象出发其调用。假设在 C 类里定义类类方法 fun,c 的值是 C 类的实例对象,可以写 C.fun(...) 或者 c.f(...)。

@staticmethod:这个标注只用在类定义里,用于说明被标注和函数是一个静态方法。staticmethod(function) 是一个内置函数。与类方法不同的是静态方法没有隐含的第一个参数。同样可以通过类名或类实例调用它。

本页及相关页面(除另声明者外)由裘宗燕创建维护,可自由用于各种学习活动。其他使用需得到作者许可。