装饰器是一种特殊类型的函数,可以修改其他函数的功能或行为。它们通常用于扩展或改变已有函数的行为而不必修改其源代码。
装饰器的基本概念
装饰器本质上是一个接受函数作为参数的函数,返回一个新函数。使用@function形式的语法糖来调用装饰器函数。
装饰器的工作原理
当一个函数被定义时,它不会立即执行。定义后,可以通过装饰器进行包装。装饰器接收这个函数作为参数,并返回一个新的函数。这个新的函数可以对原函数进行增强、修改或包装,然后再返回这个新函数。
// www.javascriptcn.com code example
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()在这个例子中,say_hello 函数被 my_decorator 装饰器所装饰。当调用 say_hello() 时,实际上是调用了 my_decorator(say_hello) 返回的新函数 wrapper。
使用带参数的装饰器
有时候需要传递参数给装饰器,这可以通过嵌套函数实现。
参数化装饰器
参数化装饰器允许你在定义装饰器时传递额外的参数。这些参数可以用来控制装饰器的行为。
// www.javascriptcn.com code example
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f"Hello {name}!")
greet("Alice")在这个例子中,repeat 是一个参数化的装饰器,它接受一个参数 num_times 来指定函数需要重复执行的次数。通过在装饰器上指定参数 @repeat(num_times=3),我们告诉装饰器 greet 函数应该重复执行三次。
类装饰器
类装饰器与函数装饰器类似,但它们接收的是类而不是函数。类装饰器通常用于修改类的属性或方法。
使用类作为装饰器
类装饰器可以用来添加新的方法或修改类的方法和属性。
// www.javascriptcn.com code example
class Decorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("Calling decorated function")
return self.func(*args, **kwargs)
@Decorator
def example():
print("Called example function")
example()在这个例子中,Decorator 类被用作装饰器。当 example 函数被调用时,实际上会调用 Decorator 类的 __call__ 方法。
带有状态的装饰器
有时我们需要装饰器能够记住一些状态信息。这可以通过在装饰器内部创建闭包来实现。
记忆装饰器
记忆装饰器可以用来缓存函数的结果,以便在未来相同的输入下快速返回结果。
// www.javascriptcn.com code example
from functools import wraps
def cache(func):
cached_values = {}
@wraps(func)
def wrapper(*args):
if args not in cached_values:
cached_values[args] = func(*args)
return cached_values[args]
return wrapper
@cache
def fibonacci(n):
if n < 2:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10))在这个例子中,cache 装饰器通过字典 cached_values 来存储已经计算过的值,从而避免了重复计算。
装饰器堆叠
可以将多个装饰器应用于同一个函数。装饰器从内到外依次应用,也就是说,最靠近函数定义的装饰器首先被执行。
多重装饰器
多重装饰器允许你组合不同的功能。
// www.javascriptcn.com code example
def make_bold(func):
def wrapper():
return "<b>" + func() + "</b>"
return wrapper
def make_italic(func):
def wrapper():
return "<i>" + func() + "</i>"
return wrapper
@make_bold
@make_italic
def say():
return "Hello!"
print(say())在这个例子中,say 函数首先被 make_italic 装饰器处理,然后结果又被 make_bold 装饰器处理。
内置装饰器
Python 提供了一些内置的装饰器,如 @staticmethod, @classmethod, 和 @property。
静态方法和类方法
静态方法和类方法是特殊的装饰器,用于定义不依赖于实例或类的特定行为。
// www.javascriptcn.com code example
class MyClass:
@staticmethod
def static_method():
print("Static method has been called.")
@classmethod
def class_method(cls):
print("Class method has been called.")
MyClass.static_method()
MyClass.class_method()在这个例子中,static_method 不需要任何实例或类作为参数,而 class_method 接受类本身作为第一个参数。
属性装饰器
属性装饰器允许你像访问普通属性一样访问类中的方法。
// www.javascriptcn.com code example
class MyClass:
def __init__(self):
self._value = 0
@property
def value(self):
return self._value
@value.setter
def value(self, new_value):
if new_value >= 0:
self._value = new_value
obj = MyClass()
print(obj.value)
obj.value = 10
print(obj.value)在这个例子中,value 属性通过 @property 装饰器被定义为只读属性,而通过 @value.setter 可以设置属性的值。
总结
装饰器是 Python 中非常强大的工具,可以让你以简洁的方式扩展或修改函数或类的行为。通过理解装饰器的工作原理和如何使用它们,你可以编写出更灵活、可维护的代码。