目录
在Python中,装饰器是一种非常强大的功能,允许程序员在不修改原有函数定义的情况下,给函数增加额外的功能。这种技术通过一个高阶函数实现,即接受函数作为参数并返回一个新的函数。装饰器广泛应用于日志记录、性能测试、事务处理、缓存、权限校验以及其他场景中。接下来,我们将从几个方面详细介绍Python中的装饰器。
装饰器基础
装饰器的基本思想是,通过一个包装函数(wrapper function)来给原函数增加额外的功能。这个包装函数会替代原函数,它通常会执行一些操作,然后调用原函数,最后返回原函数的返回值,或者根据需要返回一个修改后的值。
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
在上面的例子中,my_decorator
是一个装饰器,它接受一个函数func
作为参数,并定义了一个内部函数wrapper
,在这个内部函数中,我们在调用func()
前后加上了额外的打印操作。通过在say_hello
函数前使用@my_decorator
语法,我们实际上是将say_hello
函数传递给了my_decorator
,并且用my_decorator
返回的函数(在这里是wrapper
函数)来替代原来的say_hello
函数。
装饰器带参数
有时候我们需要装饰器本身能接受参数。这就需要我们创建一个返回装饰器的函数。这样的话,我们就可以在装饰器函数里接受自定义的参数了。
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f"Hello {name}")
greet("World")
在这个例子中,repeat
是一个接受参数num_times
的装饰器工厂函数。它返回一个装饰器,该装饰器再返回实际的包装函数。这样我们就可以控制打印次数了。
类装饰器
Python中的装饰器不仅仅可以是函数,也可以是类。类装饰器主要依赖于类的__call__
方法。当一个类的实例被当作函数调用时,__call__
方法就会被执行。
class CountCalls:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f"Call {self.num_calls} of {self.func.__name__!r}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello!")
say_hello()
say_hello()
在这个例子中,我们定义了一个CountCalls
类作为装饰器来统计函数被调用的次数。每次调用被装饰的函数时,__call__
方法都会被执行,它增加调用次数的计数,然后调用原始函数。
使用functools.wraps保留元信息
当使用装饰器时,你会发现被装饰的函数的一些重要的元信息,比如函数的名字__name__
和文档字符串__doc__
,会被改变。为了解决这个问题,我们可以使用functools
模块中的wraps
装饰器,它能帮助我们保留原函数的元信息。
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""Wrapper function"""
print("Something is happening before the function is called.")
return func(*args, **kwargs)
return wrapper
@my_decorator
def say_hello():
"""Say hello function"""
print("Hello!")
print(say_hello.__name__) # 输出 'say_hello'
print(say_hello.__doc__) # 输出 'Say hello function'
总结
装饰器是Python中一个非常强大和灵活的特性,它允许开发者在不修改原始代码的基础上,给函数或方法增加额外的功能。无论是简单的日志记录、性能测试,还是复杂的事务处理、权限校验,装饰器都能提供优雅的解决方案。理解和掌握装饰器的使用,可以帮助Python开发者写出更加简洁、高效和可维护的代码。通过functools.wraps
的使用,还能确保装饰过的函数保持其原有的元信息,使得代码更加清晰可读。总之,装饰器是Python中不可或缺的一个高级特性,值得每一位Python开发者深入学习和掌握。