Python 装饰器
Python 装饰器
装饰器让你可以在不改变函数代码的情况下,为函数添加额外的行为。
一个装饰器是一个函数,它接受另一个函数作为输入,并返回一个新的函数。
基本装饰器
先定义装饰器,然后在函数上方应用它。@decorator_name
示例
一个基本的装饰器,将装饰函数的返回值转换为大写。
def changecase(func):
def myinner():
return func().upper()
return myinner
@changecase
def myfunction():
return "Hello Sally"
print(myfunction())
通过将 @changecase直接放在函数定义的上方, 函数 myfunction 被 changecase 函数 "装饰" 了。
该函数changecase是装饰器。
函数myfunction是被装饰的函数。
多个装饰器调用
一个装饰器可以被多次调用。只需将装饰器放在你想要装饰的函数上方。
示例
使用 @changecase 装饰器装饰两个函数:
def changecase(func):
def myinner():
return func().upper()
return myinner
@changecase
def myfunction():
return "Hello Sally"
@changecase
def otherfunction():
return "I am speed!"
print(myfunction())
print(otherfunction())
装饰函数中的参数
需要参数的函数也可以被装饰,只需确保将参数传递给包装函数:
示例
带参数的函数也可以被装饰:
def changecase(func):
def myinner(x):
return func(x).upper()
return myinner
@changecase
def myfunction(nam):
return "Hello " + nam
print(myfunction("John"))
*参数和**参数
有时装饰器函数无法控制从装饰函数传递的参数,为了解决这个问题, 在包装函数中添加,这样包装函数可以接受任意数量和任意类型的参数,并将它们传递给装饰函数。([*args](https://www.w3schools.com/python/gloss_python_function_arbitrary_arguments.asp), [**kwargs](https://www.w3schools.com/python/gloss_python_function_keyword_arguments.asp))
示例
使用 [*args] 和 [**kwargs] 来保护函数:
def changecase(func):
def myinner(*args, **kwargs):
return func(*args, **kwargs).upper()
return myinner
@changecase
def myfunction(nam):
return "Hello " + nam
print(myfunction("John"))
带参数的装饰器
装饰器可以通过添加另一层包装来接受自己的参数。
示例
一个装饰器工厂,接受一个参数,并根据参数值改变外壳。
def changecase(n):
def changecase(func):
def myinner():
if n == 1:
a = func().lower()
else:
a = func().upper()
return a
return myinner
return changecase
@changecase(1)
def myfunction():
return "Hello Linus"
print(myfunction())
多个装饰器
您可以在一个函数上使用多个装饰器。
这是通过将装饰器调用堆叠在一起完成的。
装饰器按照指定的顺序调用。
示例
一个用于大写字母的装饰器,一个用于添加问候语:
def changecase(func):
def myinner():
return func().upper()
return myinner
def addgreeting(func):
def myinner():
return "Hello " + func() + " Have a good day!"
return myinner
@changecase
@addgreeting
def myfunction():
return "Tobias"
print(myfunction())
保留函数元数据
Python 中的函数具有元数据,可以通过 __name__ 和 __doc__ 属性进行访问。
示例
通常,函数的名称可以通过 __name__ 属性返回:
def myfunction():
return "Have a great day!"
print(myfunction.name)
但是,当一个函数被装饰时,原始函数的元数据丢失了。
示例
尝试从一个装饰函数中返回名称,你将不会得到相同的结果:
def changecase(func):
def myinner():
return func().upper()
return myinner
@changecase
def myfunction():
return "Have a great day!"
print(myfunction.name)
为了修复这个问题,Python 有一个内置函数叫做 functools.wraps,可以用来保持原始函数的名称和文档字符串。
示例
导入functools.wraps以保留原始函数名称和文档字符串。
import functools
def changecase(func):
@functools.wraps(func)
def myinner():
return func().upper()
return myinner
@changecase
def myfunction():
return "Have a great day!"
print(myfunction.name)
