你好,我是你们的老朋友,zhenguo!
这篇文章来自同学的提问,问题就是如何系统理解Python装饰器,我在此总结如下。
1 装饰器就是函数
Python 中的装饰器是一种高阶函数,可以在不修改函数的情况下将新的功能添加到函数中。
装饰器使用 @
语法糖,并且可以用来装饰函数、类和方法。
在本质上,装饰器是一个函数,它必须是接受一个函数作为参数,并返回一个函数。
返回的函数包含了原来函数的功能,并额外添加了新的功能。
2 装饰器案例一:实现翻倍
例如,假设你有一个函数 add,它接受两个参数并返回它们的和:
代码语言:javascript复制def add(x, y):
return x y
你可以使用装饰器来创建一个新的函数 add_twice,它将原来的加法函数包装在自己的功能中。
代码语言:javascript复制def add_twice(func):
def wrapper(x, y):
return func(x, y) func(x, y)
return wrapper
# 使用 @ 语法糖装饰函数
@add_twice
def add(x, y):
return x y
print(add(1, 2)) # 输出: 6
上面的代码使用了装饰器语法,这样你就可以在不修改 add 函数的情况下添加新的功能了。
当你调用 add(1, 2) 时,实际上是调用了 add_twice 函数返回的新函数,这个新函数会调用原来的 add 函数两次,并将结果相加。
3 装饰器案例二:实现结果缓存
装饰器的一个常见用途是用来缓存函数结果。
例如,假设你有一个函数 expensive_func,它需要花费大量时间计算结果,你希望能够缓存这个函数的结果,避免重复计算。你可以使用装饰器来实现这个功能:
代码语言:javascript复制def cache(func):
# 创建一个缓存字典
cache = {}
# 创建包装器函数
def wrapper(*args):
# 如果缓存字典中有对应的值,则直接返回
if args in cache:
return cache[args]
# 否则调用原函数并将结果缓存起来
result = func(*args)
cache[args] = result
return result
return wrapper
# 使用 @ 语法糖装饰函数
@cache
def expensive_func(x, y):
# 这里是计算代码...
pass
print(expensive_func(1, 2)) # 计算并缓存结果
print(expensive_func(1, 2)) # 直接使用缓存的结果
print(expensive_func(3, 4)) # 计算并缓存新的结果
4 装饰器案例三:接受参数的装饰器
装饰器还可以接受参数。要实现这个功能,你需要创建一个函数,这个函数接受参数并返回装饰器函数。
例如,假设你想创建一个装饰器,它可以在函数调用之前和之后打印消息:
代码语言:javascript复制def log(prefix):
def log_decorator(func):
def wrapper(*args, **kwargs):
print(prefix, "before calling", func.__name__)
result = func(*args, **kwargs)
print(prefix, "after calling", func.__name__)
return result
return wrapper
return log_decorator
# 使用 @ 语法糖装饰函数,并提供参数
@log("DEBUG")
def add(x, y):
return x y
print(add(1, 2))
上面的代码会输出:
代码语言:javascript复制DEBUG before calling add
DEBUG after calling add
注意,log 函数返回了另一个函数 log_decorator,而 log_decorator 函数又返回了另一个函数 wrapper。这个过程称为装饰器嵌套。
装饰器是 Python 中的一个强大特性,它可以让你在不修改函数代码的情况下为函数添加额外的功能。若你是使用Python多年的老司机,应该会比较偏爱装饰器,所以刚入门的朋友,大家慢慢来。
一起加油!