likes
comments
collection
share

关于 python 装饰器,你了解多少?

作者站长头像
站长
· 阅读数 8

一、装饰器介绍

装饰器是 Python 中的一种语法,它可以在不改变源代码的前提下,修改或增强函数或类的功能。装饰器本质上是一个函数或类,它接受一个函数或类作为参数,并返回一个新的函数或类。在 Python 中,装饰器通常使用 @ 符号来应用。

装饰器可以用于很多场景,例如:

  • 记录函数执行时间
  • 缓存函数的返回值
  • 检查函数参数的类型和取值范围
  • 给函数添加日志记录
  • 给函数添加权限验证
  • 给函数添加重试机制
  • 等等

二、装饰器使用

2.1 函数的装饰器

下是一个简单的装饰器示例,它可以用来记录函数的执行时间:

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} took {end_time - start_time:.2f} seconds to run.")
        return result
    return wrapper

@timer
def my_function():
    time.sleep(1)

my_function()

输出

my_function took 1.00 seconds to run.

在上面的代码中,timer 是一个装饰器函数,它接受一个函数作为参数,并返回一个新的函数 wrapperwrapper 函数记录了函数的执行时间,并返回函数的结果。@timer 表示将 my_function 函数应用 timer 装饰器,从而在调用 my_function 函数时自动记录函数的执行时间。

2.2类的装饰器

类装饰器通过将装饰器逻辑封装到一个类中,使得装饰器更加灵活和可复用。 要创建一个类装饰器,我们需要定义一个类,并实现以下两个方法之一:__init____call__

  • __init__方法会在装饰器创建时调用,可以用来初始化装饰器的参数。
  • __call__方法会在装饰器应用于被装饰的函数时被调用,可以用来包装并修改函数的行为
class Logger:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f"Logging: Calling function {self.func.__name__}")
        return self.func(*args, **kwargs)

@Logger
def say_hello():
    print("Hello, world!")

say_hello()

输出

Logging: Calling function say_hello
Hello, world!

特别是如果有多个函数或者多个类需要计算执行时间的话,这种方式避免大量代码的冗余


三、 扩展:Python的装饰器和Java Spring的面向切面编程 区别

用过 Spring 的同学,应该会好奇这个问题。

Python的装饰器是一种语法糖,它允许在不修改被装饰函数源代码的情况下,通过在函数定义前添加一个装饰器函数来修改函数的行为。装饰器函数接受被装饰函数作为参数,并返回一个新的函数对象,该函数对象可以替代原始函数。装饰器可以用于实现缓存、日志记录、性能分析等功能。

Java Spring的AOP是一种编程范式,它允许在不修改原始代码的情况下,通过在运行时动态地将代码切入到方法调用中来实现横切关注点的功能。AOP通过将横切关注点(如日志记录、事务管理、安全性检查等)从业务逻辑中分离出来,使得代码更加模块化和可维护。

虽然Python的装饰器和Java Spring的AOP都可以用于实现横切关注点的功能,但它们的实现方式有所不同。Python的装饰器是一种语法糖,它只能修改函数的行为,而Java Spring的AOP是一种更加通用的编程范式,它可以用于修改任何对象的行为。此外,Java Spring的AOP还提供了更加灵活的切入点表达式,可以根据方法名、参数类型、注解等多种条件来选择切入点。