读懂 Python 装饰器
更新时间:2023-11-30什么是装饰器?
装饰器是Python中一种很重要且强大的语言结构,它可以动态的改变一个函数、方法或类的行为,而不需要修改它们的源代码。
一般来讲,装饰器是一个函数或类,它接收一个对象并返回另一个对象,同时该对象具备被装饰对象的所有特性,或者添加新的功能。装饰器实际上是调用函数或类,使用这种方式能够避免改变原始函数或类的基本行为,而是在不改变源码的情况下对其进行改进。因此,装饰器被广泛应用于实现横向逻辑切面。
def deco(f): def wrap(): print('start...') f() print('end...') return wrap @deco def foo(): print('test') foo()
上面的代码中,我们定义了一个装饰器 @deco。该装饰器定义了一个内部函数 wrap,它输出一个开始信息并且调用原始函数 foo,最后输出结束信息。在定义完装饰器后,我们使用@deco装饰器来装饰原始函数 foo,这意味着将 foo 作为 deco 函数的参数并将结果重新赋值给 foo。最后调用 foo 函数时,实际上执行的是 wrap 函数。
装饰器的分类
根据装饰器的特性和应用场景,可以将装饰器分为几类。
修饰符装饰器
修饰符装饰器是一种特殊的装饰器,它们被用来修改函数的行为或实现特殊的功能。这种装饰器不需要在函数或方法前使用 @ 符号。
def with_logging(func): def wrapper(): print("级别: 日志") return func() return wrapper def prinlog(): print('开始...') with_logging(prinlog)()
这个例子使用了一个修饰符装饰器,即 with_logging 函数。该函数以一个函数作为参数,并返回一个修饰后的函数 wrapper。实际上,该函数调用原始 prinlog 函数,其前加了一行文本,指示该代码模块的当前日志级别,并且返回修改后的结果。
类装饰器
除了函数,在Python中还可以使用类作为装饰器。使用类装饰器可以在不使用函数闭包的情况下实现装饰器的功能。
class myDecorator(object): def __init__(self, f): self.f = f def __call__(self, *argc): print("Call entry...") self.f(*argc) print("Call exit.") @myDecorator def test(foo): print(foo) test("Hello World!")
上面的示例使用了一个类装饰器。类装饰器包含了两个方法,其中 init 函数定义了一个默认的构造函数,它以 func 作为参数,并将其保存为 self.f 变量。call 函数是每次调用实例时调用的函数,它将在实例调用时修改函数的输出行为。
参数化装饰器
参数化装饰器是指装饰器函数本身具有参数的功能。这种装饰器类型的作用与普通装饰器类似,不过增加了一些参数的控制环节。
def logger(level): def decor(func): def wrapper(*args, **kwargs): print("log Level: ", level) func(*args, **kwargs) return wrapper return decor @logger(level="DEBUG") def say(something): print("say {}!".format(something)) say("Hello World!")
在这个示例中,我们定义了一个带有参数的装饰器 logger,该装饰器接收一个字符串参数 level。logger是一个高阶函数,它的代码逻辑如下:
- 接收 level 参数
- 定义一个 decor 函数,它接收一个 func 参数作为原函数,同时它也是一个高阶函数。
- 定义一个 wrapper 函数,对 func 函数进行了日志记录。
- 返回 wrapper 函数
调用函数时,使用 @logger(level="DEBUG") 的方式将装饰器和函数联系在一起。这将使我们的 say 函数刚调用时输出一个 DEBUG 级别的日志信息。
总结
Python装饰器是Python编程语言的一个强大特性,它可以动态地修改函数、方法或类的行为,而不需要修改这些对象的源代码。Python装饰器提供了一种方便的方法来实现横向逻辑切面。装饰器可以分为修饰符装饰器、类装饰器和参数化装饰器等。通过装饰器,我们可以在不改变原有设计实现的情况下,对其进行扩展、修改和优化。