python3装饰器decorator – Python3教程

上一章Python教程请查看:python3闭包closure
装饰器接受一个函数,添加一些功能并返回它,在本文中,你将了解如何创建装饰器decorator以及为什么要使用它。
Python中的装饰器是什么?Python有一个有趣的特性,称为装饰器,用于向现有代码添加功能。
这也称为元编程,因为程序的一部分试图在编译时修改程序的另一部分。
学习装饰器的先决条件为了理解decorator,我们必须首先了解Python中的一些基本知识。
我们必须接受这样一个事实:Python中的一切(甚至类)都是对象。我们定义的名称只是绑定到这些对象的标识符,函数也不例外,它们也是对象(带有属性),可以将各种不同的名称绑定到同一个函数对象。
这里有一个例子。

def first(msg): print(msg)first("Hello")second = first second("Hello")

当你运行代码时,第一个和第二个函数都给出相同的输出。在这里,第一个和第二个名称引用同一个函数对象。
现在事情变得更奇怪了。
函数可以作为参数传递给另一个函数。
如果你在Python中使用过map、filter和reduce等函数,那么你应该已经知道了。
以其他函数为参数的函数也称为高阶函数,下面就是这样一个函数的例子。
def inc(x): return x + 1def dec(x): return x - 1def operate(func, x): result = func(x) return result

我们按如下方式调用该函数。
>>> operate(inc,3) 4 >>> operate(dec,3) 2

此外,一个函数可以返回另一个函数。
def is_called(): def is_returned(): print("Hello") return is_returnednew = is_called()#输出 "Hello" new()

在这里,is_returned()是一个嵌套函数,它是在每次调用is_called()时定义并返回的。
最后,我们必须了解Python中的闭包。
回到装饰器函数和方法被称为可调用的。
事实上,任何实现了特殊方法_call__()的对象都被称为可调用的,因此,从最基本的意义上说,decorator是一个返回callable的callable。
基本上,decorator接受一个函数,添加一些功能并返回它。
def make_pretty(func): def inner(): print("我有装饰") func() return innerdef ordinary(): print("我是普通的")

在shell中运行以下代码时,
>>> ordinary() 我是普通的 >>> # 我们来装饰一下这个普通的函数 >>> pretty = make_pretty(ordinary) >>> pretty() 我有装饰 我是普通的

在上面的例子中,make_pretty()是一个装饰器。在赋值步骤中。
pretty = make_pretty(ordinary)

函数ordinary()被修饰,返回的函数被命名为pretty。
我们可以看到decorator函数在原来的函数中添加了一些新功能,这类似于包装礼物,装饰器充当包装器,被装饰的物品(里面的礼物)的性质不会改变,但是现在,它看起来很漂亮。
通常,我们修饰一个函数并将其重新赋值为,
ordinary = make_pretty(ordinary).

这是一个常见的构造,因此Python有一个语法来简化它。
我们可以使用@符号和装饰器函数的名称,并将其置于要装饰的函数的定义之上。例如,
@make_pretty def ordinary(): print("我是普通的")

相当于:
def ordinary(): print("我是普通的") ordinary = make_pretty(ordinary)

这只是实现decorator的一种语法糖。
带有参数的装饰函数上面的装饰器很简单,它只对没有任何参数的函数起作用,如果我们有如下参数的函数呢?
def divide(a, b): return a/b

这个函数有两个参数,a和b,我们知道,如果我们把b作为0传递,它会报错。
>>> divide(2,5) 0.4 >>> divide(2,0) Traceback (most recent call last): ... ZeroDivisionError: division by zero

现在让我们创建一个decorator来检查这种会导致错误的情况。
def smart_divide(func): def inner(a,b): print("开始执行除法:",a,"和",b) if b == 0: print("不能计算!") returnreturn func(a,b) return inner@smart_divide def divide(a,b): return a/b

如果出现错误条件,这个新实现将返回None。
>>> divide(2,5) 开始执行除法: 2 和 5 0.4 >>> divide(2,0) 开始执行除法: 2 和 0 不能计算!

通过这种方式,我们可以修饰带有参数的函数。
敏锐的观察者会注意到,装饰器内嵌套的inner()函数的参数与它装饰的函数的参数相同,考虑到这一点,现在我们可以让通用装饰器使用任意数量的参数。
在Python中,这个魔术是作为函数(*args, **kwargs)完成的,这样,args将是位置参数的元组,而kwargs将是关键字参数的字典,这样的装饰器就是一个例子。
def works_for_all(func): def inner(*args, **kwargs): print("我可以装饰任何函数") return func(*args, **kwargs) return inner

Python中的链接装饰器在Python中可以链接多个装饰器decorator。
也就是说,一个函数可以使用不同(或相同)的装饰器进行多次装饰,我们只需将装饰器置于所需的函数之上。
def star(func): def inner(*args, **kwargs): print("*" * 30) func(*args, **kwargs) print("*" * 30) return innerdef percent(func): def inner(*args, **kwargs): print("%" * 30) func(*args, **kwargs) print("%" * 30) return inner@star @percent def printer(msg): print(msg) printer("Hello")

使用上面的语法:
@star @percent def printer(msg): print(msg)

相当于:
def printer(msg): print(msg) printer = star(percent(printer))

【python3装饰器decorator – Python3教程】我们链接装饰的顺序很重要,如果我们把顺序反过来:
@percent @star def printer(msg): print(msg)

    推荐阅读