精通 Python 装饰器:专家技巧增强函数
Python 装饰器
装饰器让你用可复用逻辑包装函数,使代码更模块化、可读、可维护。本指南构建、解释并应用装饰器于真实场景。
视频:Python @Decorators
Python 中的装饰器
Python 装饰器是强大的元编程工具,允许在定义时为函数或类添加行为。因 Python 中一切皆对象——包括函数和类——装饰器通过接收一个可调用对象,用另一个包装它,并返回新可调用对象来工作。
学习装饰器的前置知识
深入前,应熟悉 Python 中函数是一等对象。名称只是绑定到对象的引用;同一函数可被多个名称引用。
def first(msg):
print(msg)
first("Hello")
second = first
second("Hello")
输出
Hello Hello
函数可作为参数传递、从其他函数返回、甚至嵌套在其他函数内。这些概念——高阶函数、嵌套函数、闭包——是装饰器的基石。
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()
new()
输出
Hello
理解闭包是关键:嵌套函数保留对外层作用域的访问,这正是装饰器利用的机制来存储元数据或修改行为。
回到装饰器
在 Python 中,装饰器就是接受函数(或其他可调用对象)并返回新可调用对象的可调用对象。返回函数通常包装原函数,在调用前后添加或改变功能。
def make_pretty(func):
def inner():
print("I got decorated")
func()
return inner
def ordinary():
print("I am ordinary")
示例用法:
>>> ordinary()
I am ordinary
>>> pretty = make_pretty(ordinary)
>>> pretty()
I got decorated
I am ordinary
装饰器模式保持原函数语义不变同时增强它。为避免手动重新赋值,Python 提供 @ 语法糖:
@make_pretty
def ordinary():
print("I am ordinary")
这等价于:
def ordinary():
print("I am ordinary")
ordinary = make_pretty(ordinary)
装饰带参数的函数
许多装饰器需处理任意参数。*args 和 **kwargs 语法捕获任意位置或关键字参数并原样转发。
def works_for_all(func):
def inner(*args, **kwargs):
print("I can decorate any function")
return func(*args, **kwargs)
return inner
处理边界情况是装饰器常见用例。例如防除零:
def smart_divide(func):
def inner(a, b):
print("I am going to divide", a, "and", b)
if b == 0:
print("Whoops! cannot divide")
return
return func(a, b)
return inner
@smart_divide
def divide(a, b):
print(a/b)
用法:
>>> divide(2,5)
I am going to divide 2 and 5
0.4
>>> divide(2,0)
I am going to divide 2 and 0
Whoops! cannot divide
Python 中链式装饰器
装饰器可堆叠。应用顺序很重要,因每个装饰器接收下方装饰器返回的函数。
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)
结果:
****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Hello %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ******************************
反转顺序会交换包围模式,演示装饰器堆叠如何影响行为。
Python
- 精通Python数据类型:实战指南
- 精通Python运算符:全面指南
- 精通Python Pass语句:实战指南
- 精通Python函数参数:位置、关键字与默认参数
- Python Lambda匿名函数实战指南
- 精通 Python Lambda 函数:实用示例与最佳实践
- Python abs() 函数:计算数字与复数的绝对值
- Python round() 函数详解与实战示例
- 精通 Python range() 函数:从基础到高级用法
- 精通 Python map() 函数:语法、示例与最佳实践
- 精通 Python yield:生成器 vs return 实战指南
- 精通 Python enumerate():为列表、元组、字符串、字典带索引循环