Python装饰器(decorator)是一种高阶函数,用于在不修改原函数代码的情况下,动态地为函数添加额外的功能。它本质上是一个接受函数作为输入并返回新函数的函数,常用于日志记录、性能测试、权限验证等场景。以下是关于Python装饰器的详细讲解:
装饰器是一个函数,它接受一个函数作为参数,并返回一个新的函数。新函数通常会在调用原函数前后执行一些额外的逻辑。装饰器的语法糖是 @decorator_name
,放在函数定义的上方。
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()
输出:
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
my_decorator
是一个装饰器,接受函数 func
作为参数。wrapper
是内部定义的包装函数,扩展了 func
的行为。@my_decorator
等价于 say_hello = my_decorator(say_hello)
。如果被装饰的函数有参数,装饰器需要处理这些参数。可以使用 *args
和 **kwargs
来支持任意参数。
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Before the function call.")
result = func(*args, **kwargs) # 调用原函数并保存返回值
print("After the function call.")
return result # 返回原函数的结果
return wrapper
@my_decorator
def greet(name):
return f"Hello, {name}!"
print(greet("Alice"))
输出:
Before the function call.
Hello, Alice!
After the function call.
Hello, Alice!
有时装饰器本身需要接受参数,这需要再加一层函数来处理装饰器的参数。
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3) # 重复执行3次
def say_hello():
print("Hello!")
say_hello()
输出:
Hello!
Hello!
Hello!
repeat(n)
是装饰器工厂,返回一个装饰器。@repeat(3)
表示函数 say_hello
将被重复调用3次。默认情况下,装饰器会覆盖原函数的元信息(如 __name__
和 __doc__
)。为了保留这些信息,可以使用 functools.wraps
。
from functools import wraps
def my_decorator(func):
@wraps(func) # 保留原函数的元信息
def wrapper(*args, **kwargs):
print("Before the function call.")
result = func(*args, **kwargs)
print("After the function call.")
return result
return wrapper
@my_decorator
def greet(name):
"""Greet someone."""
return f"Hello, {name}!"
print(greet.__name__) # 输出:greet
print(greet.__doc__) # 输出:Greet someone.
@wraps(func)
确保 wrapper
的元信息与原函数一致。装饰器在实际开发中有许多用途,例如:
def log(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned {result}")
return result
return wrapper
@log
def add(a, b):
return a + b
add(2, 3)
输出:
Calling add with (2, 3), {}
add returned 5
import time
from functools import wraps
def timer(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} took {end - start:.4f} seconds")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
slow_function()
输出:
slow_function took 1.0023 seconds
def require_permission(permission):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
if permission in user_permissions: # 假设 user_permissions 是全局变量
return func(*args, **kwargs)
else:
raise PermissionError("Permission denied")
return wrapper
return decorator
user_permissions = ["admin"]
@require_permission("admin")
def delete_user(user_id):
print(f"User {user_id} deleted")
delete_user(123)
输出:
User 123 deleted
除了函数装饰器,类也可以用作装饰器。类装饰器通常通过实现 __call__
方法来包装函数。
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("Before the function call.")
result = self.func(*args, **kwargs)
print("After the function call.")
return result
@MyDecorator
def greet(name):
return f"Hello, {name}!"
print(greet("Alice"))
输出:
Before the function call.
Hello, Alice!
After the function call.
Hello, Alice!
一个函数可以应用多个装饰器,执行顺序是从内到外(从靠近函数的装饰器开始)。
def deco1(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Decorator 1")
return func(*args, **kwargs)
return wrapper
def deco2(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Decorator 2")
return func(*args, **kwargs)
return wrapper
@deco1
@deco2
def say_hello():
print("Hello!")
say_hello()
输出:
Decorator 1
Decorator 2
Hello!
deco2
先执行(离函数最近),然后是 deco1
。Python 提供了一些内置装饰器,常用的有:
@staticmethod
:定义静态方法,不需要实例化即可调用。@classmethod
:定义类方法,第一个参数是类本身(通常命名为 cls
)。@property
:将方法转换为属性,方便访问和设置。class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
p = Person("Alice")
print(p.name) # 输出:Alice
p.name = "Bob"
print(p.name) # 输出:Bob
functools.wraps
可以缓解元信息丢失问题。Python装饰器是函数式编程的强大工具,能够优雅地扩展函数功能。掌握装饰器的核心在于理解闭包和高阶函数。通过合理使用装饰器,可以写出更简洁、可维护的代码,尤其在需要复用逻辑时(如日志、计时、权限控制等)。