在Python编程中,装饰器是一个既迷人又强大的工具,它允许我们在不修改原有函数代码的情况下增加额外的功能。这种机制基于Python的闭包和函数作为一等公民的特性,使得装饰器成为可能。
什么是装饰器?
简单地说,装饰器是一个接受函数作为参数并返回一个新函数的可调用对象。在Python中,我们通常使用@符号来应用装饰器。比如,一个记录日志的简单装饰器可以这样实现:
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned {result}")
return result
return wrapper
这个装饰器可以在任何函数上使用,如:
@log_decorator
def add(a, b):
return a + b
当我们调用add(1, 2)
时,会先输出"Calling add",然后执行加法操作,最后输出"add returned 3"。
带参数的装饰器
有时候,我们需要让装饰器更加灵活,能够接受参数。这可以通过创建一个外部函数来实现,该函数接受参数并返回真正的装饰器。例如:
def configurable_log_decorator(prefix=""):
def actual_decorator(func):
def wrapper(*args, **kwargs):
print(f"{prefix}Calling {func.__name__}")
result = func(*args, **kwargs)
print(f"{prefix}{func.__name__} returned {result}")
return result
return wrapper
return actual_decorator
现在,我们可以为装饰器指定不同的前缀:
@configurable_log_decorator("[INFO] ")
def add(a, b):
return a + b
装饰器嵌套
装饰器还可以嵌套使用,以实现更复杂的逻辑。例如,我们可以创建一个缓存装饰器,用来存储函数的结果,避免重复计算:
def cache_decorator(func):
cache = {
}
def wrapper(*args):
if args in cache:
print("Fetching from cache")
return cache[args]
else:
result = func(*args)
cache[args] = result
return result
return wrapper
然后,我们可以将它与其他装饰器结合使用:
@log_decorator
@cache_decorator
def expensive_operation(n):
print("Performing expensive operation...")
return n * n
使用functools.wraps保持原函数信息
有时,使用装饰器后,原函数的一些属性(如名字和文档字符串)会被丢失。为了解决这个问题,我们可以使用functools.wraps
装饰器来更新包装函数的信息:
from functools import wraps
def better_log_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
# ... (省略)
return wrapper
通过这种方式,即使函数被装饰,其原始信息也会被保留。
总结
装饰器是Python中一个非常强大的特性,它允许我们以声明式的方式扩展函数的功能。从简单的日志记录到复杂的逻辑处理,装饰器都能提供一种优雅的解决方案。掌握装饰器的使用,将使你的代码更加简洁、可读性更强,并且功能更加强大。