Python 装饰器
1. 装饰器是什么
装饰器是 Python 中的一种高级函数,用于在不修改原始函数代码的前提下,动态地为函数或类增加功能。它本质上是一个函数,接受另一个函数或类作为参数,并返回一个新的函数或类。
装饰器的基本语法
def decorator(func):
def wrapper(*args, **kwargs):
# 在调用函数之前添加额外的行为
print("Before the function call")
result = func(*args, **kwargs)
# 在调用函数之后添加额外的行为
print("After the function call")
return result
return wrapper
@decorator
def my_function():
print("This is the main function")
# 调用时
my_function()
输出:
Before the function call
This is the main function
After the function call
多个装饰器
多个装饰器可以叠加使用,每个装饰器会按顺序应用:
@decorator1
@decorator2
def my_function():
pass
装饰器的应用顺序是从内到外:首先应用 @decorator2
,然后是 @decorator1
。
自定义装饰器
可以根据需要自定义装饰器,为函数增加日志记录、权限检查、缓存等功能。
def custom_decorator(func):
def wrapper(*args, **kwargs):
print("Custom behavior before the function")
return func(*args, **kwargs)
return wrapper
@custom_decorator
def example():
print("Original function behavior")
2. 常见的装饰器
@property
@property
装饰器将类的方法转化为属性,可以通过点操作符访问,而不是调用它作为一个函数。
class MyClass:
def __init__(self, value):
self._value = value
@property
def value(self):
return self._value
obj = MyClass(10)
print(obj.value) # 直接访问属性,不用加括号
@staticmethod
与 @classmethod
@staticmethod
:定义静态方法,不能访问类的实例或类本身。@classmethod
:定义类方法,第一个参数是类本身cls
,可以访问类的属性和方法。
class MyClass:
@staticmethod
def static_method():
print("This is a static method")
@classmethod
def class_method(cls):
print("This is a class method")
MyClass.static_method()
MyClass.class_method()
3. @contextmanager
@contextmanager
是 Python 标准库中的 contextlib
模块提供的一个装饰器,用于简化上下文管理器的编写,使得我们可以通过 with
语句安全地管理资源(如文件、数据库连接等),确保资源的正确获取与释放。
@contextmanager
的使用
通过 @contextmanager
,可以使用简单的生成器函数代替编写完整的上下文管理类。
from contextlib import contextmanager
@contextmanager
def open_file(file_name):
f = open(file_name, 'r')
try:
yield f # 提供上下文管理的资源
finally:
f.close() # 确保在退出时关闭文件
# 使用上下文管理器
with open_file('test.txt') as f:
content = f.read()
print(content)
with
语句
with
语句是 Python 中管理资源的常用方式,它能够确保在块结束时自动释放资源,不论是否发生异常。
with open('file.txt', 'r') as f:
data = f.read()
with
语句背后的机制是对象实现了上下文管理协议,即实现了 __enter__
和 __exit__
方法。
@contextmanager
的内部原理
@contextmanager
是通过生成器的 yield
语句来切分上下文进入和退出的时机。在 yield
之前的部分相当于 __enter__
,而在 yield
之后的部分相当于 __exit__
,用于管理资源的释放。
自定义上下文管理器的完整类实现
除了 @contextmanager
,你还可以通过类的 __enter__
和 __exit__
方法来实现上下文管理器。
class MyContextManager:
def __enter__(self):
print("Entering the context")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Exiting the context")
with MyContextManager() as manager:
print("Inside the with block")
@contextmanager
与对象初始化的区别
需要注意的是,@contextmanager
仅用于创建上下文管理器,与对象的初始化过程(即类的 __init__
方法)无关。对象的初始化通常不涉及资源管理,因此不需要使用 @contextmanager
。
4. 装饰器与上下文管理器的应用场景
- 装饰器:适用于增强函数功能、添加日志记录、权限控制、缓存等场景。
- 上下文管理器:适用于需要明确资源管理的场景,如文件、数据库连接的打开与关闭。