Python编程技巧 – 装饰器
Python编程技巧 – 装饰器
Python Programming Skills – Decorator
By Jackson@ML
0. 装饰器定义
在 Python编程语言中,有一种设计模式,称为装饰器(Decorator),它允许用户通过将函数包装在另一个函数中来修改函数的功能特性。
根据这个定义,该函数至少会由内外两层函数构成。外部函数称为装饰器,它将原始函数作为参数并返回它的修改过的版本。
1. 先决条件 – 嵌套函数
在了解装饰器之前,我们需要提前了解Python 函数相关的重要概念。
另外,请知晓,Python 中的所有内容(或者叫数据)都是对象,甚至函数也是对象。
1) 普通函数
先来回顾一下Python的普通自定义函数。
假设我们需要创建一个加法函数,传递两个参数 – 即被加数和加数,返回结果两个数相加的和,代码如下所示:
def add(x, y):return x + y
运行函数,如下命令:
add(3, 2)
得到结果为:
5
2) 嵌套函数
我们可以将一个函数包含在另一个函数中,称为嵌套函数。
现在创建一个嵌套函数,假设定义外层函数为outer, 而内层函数为inner。代码如下所示:
def outer(x):def inner(y):return x + yreturn inneradd_five = outer(3)
result = add_five(4)
print(result) # 打印输出为 7
3) 将函数作为参数传递
我们可以将一个函数作为参数传递给 Python 中的另一个函数。代码如下所示:
def add(x, y):return x + ydef calculate(func, x, y):return func(x, y)result = calculate(add, 4, 6)
print(result) # 打印输出为 10
在上面的示例中,calculate()函数将函数func作为参数,另外还有两个参数x, y;在调用calculate()时,将add()函数作为参数进行了传递。
在calculate()函数里,参数func, x, y分别为add, 4和6。因此,func(x, y)变为add(4, 6), 并返回值10。
4) 将函数作为一个值返回
在 Python 中,我们也可以返回一个函数作为返回值。例如以下代码:
def greeting(name):def hello():return "Hello, " + name + "!"return hellogreet = greeting("China")
print(greet()) # 打印输出 "Hello, China!"
输出结果为:
Hello, China!
在上面的示例中,greeting()函数最后一行 - return hello 语句返回内部的 hello() 函数。此函数现在已分配给 greet 变量。
这就是为什么当我们将 greet() 作为函数调用时,我们会得到输出。
2. 装饰器
如前所述,Python 装饰器是一个函数,它接受一个函数并通过添加一些功能来返回它。
事实上,任何实现特殊 _ _ call _ _ ( )方法的对象都被称为可调用对象。因此,从最基本的意义上说,装饰器是一个返回可调用对象的可调用对象。
基本上,装饰器接受一个函数,添加一些功能并返回它。
def make_pretty(func):def inner():print("I got decorated")func()return innerdef ordinary():print("I am ordinary")
输出结果:
I am ordinary
在这里,我们创建了两个函数:
- ordinary() 打印 “I am ordinary”;
- make_pretty() 将一个函数作为其参数,并具有一个名为 inner() 的嵌套函数,并返回内部函数。
我们通常调用 ordinary() 函数,因此我们得到输出“我是普通的”。现在,让我们使用 decorator 函数来调用它。
def make_pretty(func):# define the inner function def inner():# add some additional behavior to decorated functionprint("I got decorated")# call original functionfunc()# return the inner functionreturn inner# define ordinary function
def ordinary():print("I am ordinary")# decorate the ordinary function
decorated_func = make_pretty(ordinary)# call the decorated function
decorated_func()
输出结果为:
I got decorated
I am ordinary
在上面显示的示例中,make_pretty() 是一个装饰器。注意代码,
decorated_func = make_pretty(ordinary)
在这里,我们实际上是在调用 inner() 函数,我们在那里打印输出。
@ (带装饰器的符号)
Python 没有将函数调用分配给变量,而是提供了一种更优雅的方式来使用 @ 符号来实现此功能。例如:
def make_pretty(func):def inner():print("I got decorated")func()return inner@make_pretty
def ordinary():print("I am ordinary")ordinary()
输出结果为:
I got decorated
I am ordinary
在这里,ordinary() 函数使用 @make_pretty 语法用 make_pretty() 装饰器进行修饰,这相当于调用 ordinary = make_pretty(ordinary)。
3. 使用参数装饰函数
上面的装饰器比较简单,它只适用于没有任何参数的函数。
如果我们有接受以下参数的函数会怎样,代码如下:
def divide(a, b):return a/b
此函数有两个参数,a 和 b。我们知道,如果我们将 b 传入为 0,它将给出一个错误。
现在,让我们制作一个装饰器来检查是否存在会导致错误的情况。
def smart_divide(func):def inner(a, b):print("I am going to divide", a, "and", b)if b == 0:print("Whoops! cannot divide")returnreturn func(a, b)return inner@smart_divide
def divide(a, b):print(a/b)divide(2,5)divide(2,0)
输出结果为:
I am going to divide 2 and 5
0.4
I am going to divide 2 and 0
Whoops! cannot divide
在这里,当我们使用参数 (2,5) 调用 divide() 函数时,会调用 smart_divide() 装饰器中定义的 inner() 函数。
这个 inner() 函数使用参数 2 和 5 调用原始 divide() 函数并返回结果,即 0.4。
同样,当我们使用参数 (2,0) 调用 divide() 函数时,inner() 函数会检查 b 是否等于 0,并在返回 None 之前打印错误消息。
4. 在 Python 中链接装饰器
用户可以在 Python 中链接多个装饰器。 为了在 Python 中链接装饰器,我们可以通过将多个装饰器一个接一个地放置来将多个装饰器应用于单个函数,首先应用最内部的装饰器。
def star(func):def inner(*args, **kwargs):print("*" * 15)func(*args, **kwargs)print("*" * 15)return innerdef percent(func):def inner(*args, **kwargs):print("%" * 15)func(*args, **kwargs)print("%" * 15)return inner@star
@percent
def printer(msg):print(msg)printer("Hello")
输出结果为:
***************
%%%%%%%%%%%%%%%
Hello
%%%%%%%%%%%%%%%
***************
下述的相关语法:
@star
@percent
def printer(msg):print(msg)
等同于以下代码:
def printer(msg):print(msg)
printer = star(percent(printer))
*注意:我们链接装饰器的顺序很重要。加入把@的顺序颠倒过来,如下代码所示:
@percent
@star
def printer(msg):print(msg)
那么,输出结果如下所示:
%%%%%%%%%%%%%%%
***************
Hello
***************
%%%%%%%%%%%%%%%
鸣谢
1. Python Tutorial
2. programiz.com
相关阅读
- Python开发实例 - Lambda表达式
- Python编程技巧 - 函数参数
- Python编程技巧 - 使用集合
- Python编程技巧 - 编写单行if条件语句
- Python编程技巧 - format格式化文本
- Python编程技巧 - 使用正则表达式
- Python编程技巧 - 单字符函数
- Python编程技巧 - 使用组合运算符
- Python编程技巧 - 异常处理
- Python编程技巧 - 迭代器
- Python编程技巧 - Lambda函数
- Python编程技巧 - 使用字典
- Python编程技巧 - 使用字符串
- Python编程技巧 - 对象和类
- Python编程技巧 - 使用列表
- Python编程技巧 - 转换二进制、八进制和十六进制的函数
- Python编程技巧 - 函数入门
- 2024最新版PyCharm安装使用指南
- 2024最新版Visual Studio Code安装使用指南