匠心精神 - 良心品质腾讯认可的专业机构-IT人的高薪实战学院

咨询电话:4000806560

Python高级技巧:装饰器详解

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语言中一项非常强大的特性,可以为函数、方法、类等添加额外的功能,而不需要对原代码进行任何修改。通过使用装饰器,我们可以轻松地实现日志记录、接口认证、性能分析等功能,提高代码的可读性和可维护性。