Python高级技巧:装饰器详解
装饰器是Python语言中一个非常强大的特性,可以为函数、方法、类等添加额外的功能,而不需要对原代码进行任何修改。本文将介绍装饰器的概念、使用场景以及常见的实现方式。
什么是装饰器
装饰器是Python函数或类的修饰符,本质上是一个可调用对象,它接受一个函数或类作为参数,并返回一个新的函数或类。通过装饰器,我们可以在不修改原代码的情况下,给函数或类添加新的功能。常见的装饰器有函数装饰器和类装饰器两种。
函数装饰器
函数装饰器是指装饰器接受一个函数作为参数,返回一个新的函数的装饰器。下面是一个简单的例子:
```python
def my_decorator(func):
def wrapper():
print("Before function call")
func()
print("After function call")
return wrapper
@my_decorator
def say_hello():
print("Hello")
say_hello()
```
在上面的例子中,我们定义了一个函数装饰器`my_decorator`,它接受一个函数`func`作为参数,并返回一个新的函数`wrapper`。`wrapper`函数在调用原函数前后输出一些信息。在函数`say_hello`上添加了装饰器`@my_decorator`,这意味着函数`say_hello`将被修饰为`wrapper`函数。最后调用函数`say_hello`,输出的结果为:
```
Before function call
Hello
After function call
```
我们可以看到,通过添加装饰器,我们在不修改函数`say_hello`的情况下,成功地为它添加了额外的功能。
类装饰器
类装饰器是指装饰器接受一个类作为参数,返回一个新的类的装饰器。下面是一个简单的例子:
```python
class my_decorator:
def __init__(self, func):
self.func = func
def __call__(self):
print("Before function call")
self.func()
print("After function call")
@my_decorator
def say_hello():
print("Hello")
say_hello()
```
在上面的例子中,我们定义了一个类装饰器`my_decorator`,它接受一个函数作为参数,在`__init__`方法中保存原函数,在`__call__`方法中添加一些功能,最后返回一个新的函数。在函数`say_hello`上添加了装饰器`@my_decorator`,这意味着函数`say_hello`将被修饰为`my_decorator`类的实例。最后调用函数`say_hello`,输出的结果与之前的例子相同。
装饰器链
在Python中,我们可以使用多个装饰器来修饰一个函数,这就是装饰器链。装饰器链的顺序是从上到下执行的,即先执行最上层的装饰器,再执行下一层的装饰器,以此类推。下面是一个简单的例子:
```python
def my_decorator_1(func):
def wrapper():
print("Before function call 1")
func()
print("After function call 1")
return wrapper
def my_decorator_2(func):
def wrapper():
print("Before function call 2")
func()
print("After function call 2")
return wrapper
@my_decorator_1
@my_decorator_2
def say_hello():
print("Hello")
say_hello()
```
在上面的例子中,我们定义了两个装饰器`my_decorator_1`和`my_decorator_2`,并将它们分别应用于函数`say_hello`。最终调用函数`say_hello`,输出的结果为:
```
Before function call 1
Before function call 2
Hello
After function call 2
After function call 1
```
我们可以看到,装饰器链按照从上到下的顺序依次执行,最终输出的结果与我们预期的一致。
实际应用
在实际应用中,装饰器常用于以下几个场景:
1. 日志记录
在函数或方法调用时记录一些重要的信息,如调用的参数、耗时等。
```python
import logging
import time
def log_decorator(func):
def wrapper(*args, **kwargs):
logging.info(f"Function {func.__name__} called with args: {args}, kwargs: {kwargs}")
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
logging.info(f"Function {func.__name__} finished in {end_time - start_time:.2f} seconds")
return result
return wrapper
@log_decorator
def say_hello(name):
print(f"Hello, {name}")
```
在上面的例子中,我们定义了一个装饰器`log_decorator`,它会记录函数调用的参数和耗时信息,并使用`logging`模块输出到日志文件中。在函数`say_hello`上添加了装饰器`@log_decorator`,这意味着函数`say_hello`将被修饰为`wrapper`函数。最终调用函数`say_hello`,在日志文件中输出以下信息:
```
INFO:root:Function say_hello called with args: ('Alice',), kwargs: {}
INFO:root:Function say_hello finished in 0.00 seconds
```
我们可以看到,通过添加装饰器,我们成功地为函数`say_hello`添加了日志记录的功能。
2. 接口认证
在Web应用中,经常需要对API接口进行认证,以保护数据安全。
```python
import jwt
from flask import request, jsonify
def auth_required(func):
def wrapper(*args, **kwargs):
token = request.headers.get("Authorization")
if not token:
return jsonify({"message": "Authorization required"}), 401
try:
payload = jwt.decode(token, "secret", algorithms=["HS256"])
except jwt.ExpiredSignatureError:
return jsonify({"message": "Token expired"}), 401
except jwt.InvalidTokenError:
return jsonify({"message": "Invalid token"}), 401
return func(*args, **kwargs)
return wrapper
@app.route("/api/data")
@auth_required
def get_data():
data = {"foo": "bar"}
return jsonify(data)
```
在上面的例子中,我们定义了一个装饰器`auth_required`,它会检查请求头中是否包含`Authorization`字段,并对JWT令牌进行验证。如果验证通过,就执行原函数`func`,否则返回401错误响应。在Flask应用中,我们可以使用`@app.route`装饰器为视图函数添加URL路由规则,并使用`@auth_required`装饰器添加认证功能。
3. 性能分析
在调试应用时,经常需要对函数或方法的性能进行分析,以找出性能瓶颈。
```python
import time
def profile_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs)
end_time = time.perf_counter()
print(f"Function {func.__name__} took {end_time - start_time:.6f} seconds")
return result
return wrapper
@profile_decorator
def hard_work():
time.sleep(2)
hard_work()
```
在上面的例子中,我们定义了一个装饰器`profile_decorator`,它会在函数调用前后记录时间,并输出函数的执行时间。在函数`hard_work`上添加了装饰器`@profile_decorator`,这意味着函数`hard_work`将被修饰为`wrapper`函数。最终调用函数`hard_work`,输出的结果为:
```
Function hard_work took 2.000095 seconds
```
我们可以看到,通过添加装饰器,我们成功地对函数`hard_work`的性能进行了分析。
总结
装饰器是Python语言中一项非常强大的特性,可以为函数、方法、类等添加额外的功能,而不需要对原代码进行任何修改。通过使用装饰器,我们可以轻松地实现日志记录、接口认证、性能分析等功能,提高代码的可读性和可维护性。