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