上一章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 + 1
def dec(x):
return x - 1
def 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_returned
new = is_called()
#输出 "Hello"
new()
在这里,is_returned()是一个嵌套函数,它是在每次调用is_called()时定义并返回的。
最后,我们必须了解Python中的闭包。
回到装饰器
函数和方法被称为可调用的。
事实上,任何实现了特殊方法_call__()的对象都被称为可调用的,因此,从最基本的意义上说,decorator是一个返回callable的callable。
基本上,decorator接受一个函数,添加一些功能并返回它。
def make_pretty(func):
def inner():
print("我有装饰")
func()
return inner
def 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("不能计算!")
return
return 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 inner
def 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))
我们链接装饰的顺序很重要,如果我们把顺序反过来:
@percent
@star
def printer(msg):
print(msg)
评论前必须登录!
注册