Python 装饰器(Decorator)是一种允许在不修改函数或方法代码的情况下,动态地为其添加额外功能的设计模式。装饰器常用于对函数的输入或输出进行处理、增加日志记录、性能监控、访问控制等。理解装饰器的关键在于理解 Python 函数是“第一类对象”(First-class objects),即函数可以作为参数传递,也可以作为返回值返回。
1. 基本原理 装饰器本质上是一个函数 ,它接收一个函数作为参数,并返回一个新的函数(可以是原函数或修改后的函数)。这个新函数通常包含了附加的功能逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 def decorator_function (original_function ): def wrapper_function (*args, **kwargs ): print ("Before executing the function." ) result = original_function(*args, **kwargs) print ("After executing the function." ) return result return wrapper_function
2. 基本装饰器的实现和使用 我们可以通过 @decorator_name 的方式来使用装饰器,它会将 decorator_function 应用到目标函数上。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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()
1 2 3 4 5 输出 Something is happening before the function is called. Hello! Something is happening after the function is called.
在这个例子中,my_decorator 是装饰器函数,它接收 say_hello 作为参数并返回 wrapper。当 say_hello 被调用时,实际调用的是 wrapper 函数,这样可以在原函数的前后增加功能。
3. 带参数的装饰器 装饰器可以接收参数。要实现这一点,我们需要再嵌套一层函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 def repeat (num_times ): def decorator_repeat (func ): def wrapper (*args, **kwargs ): for _ in range (num_times): func(*args, **kwargs) return wrapper return decorator_repeat @repeat(num_times=3 ) def greet (name ): print (f"Hello {name} " ) greet("Alice" )
1 2 3 4 5 输出 Hello Alice Hello Alice Hello Alice
在这里,repeat 是一个带参数的装饰器。repeat(num_times) 返回 decorator_repeat,然后 decorator_repeat 装饰 greet 函数。每次调用 greet(“Alice”),它会根据 num_times 重复执行。
4. 装饰器的应用场景 • 日志记录 :记录函数的执行时间、参数和返回值等。
• 性能测试 :计算函数执行时间,判断性能。
• 访问控制 :验证用户权限。
• 缓存 :将函数结果缓存起来,避免重复计算。
使用装饰器后,原函数的元数据(如函数名和文档字符串)会被覆盖。为了解决这个问题,可以使用 functools.wraps 来保持原函数的信息。
1 2 3 4 5 6 7 8 import functoolsdef my_decorator (func ): @functools.wraps(func ) def wrapper (*args, **kwargs ): print ("Calling decorated function" ) return func(*args, **kwargs) return wrapper
这样,装饰器 wrapper 会保留被装饰函数的元数据。
6. 类方法的装饰器 装饰器也可以用于类的方法,特别是在需要对实例方法或类方法应用通用功能(如日志记录或权限检查)时。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def method_decorator (method ): @functools.wraps(method ) def wrapper (self, *args, **kwargs ): print (f"Calling method {method.__name__} with args {args} and kwargs {kwargs} " ) return method(self , *args, **kwargs) return wrapper class MyClass : @method_decorator def display (self, value ): print (f"Display: {value} " ) obj = MyClass() obj.display("Test" )
7. 总结 装饰器是非常强大的工具,可以在函数前后添加额外逻辑。使用装饰器可以有效提升代码的可复用性和可维护性。掌握装饰器可以帮助开发者在实际项目中更加优雅地管理代码。