跳至主要內容

装饰器

blacklad大约 2 分钟PythonPython

装饰器

装饰器(Decorator)是Python中的一个重要特性,它可以在不修改函数代码的前提下,增强改变函数的行为。

装饰器通常用于日志记录、性能测试、事务处理、缓存、权限校验等场景。

一、实现

装饰器本质上是一个高阶函数,它接受一个函数作为参数并返回一个新的函数。装饰器可以通过@语法糖方便地应用于任何函数。

def my_decorator(func):
    def wrapper():
        print("Calling the function")
        func()
        print("Function has been called")
    return wrapper

@my_decorator
def greet():
    print("Greetings!")

greet()
Calling the function
Greetings!
Function has been called

可以看到通过装饰器,可以很方便的在函数前后加入一些通用的代码。

耗时统计

比如你想统计写的一些函数的耗时。如果没有装饰器就需要在每个函数的入口处记录开始时间,在函数返回前记录与开始时间的差值得到函数的耗时,但是当函数比较多的时候,需要给每个函数都做同样的修改。

而使用装饰器,只需要定义一个计算耗时的装饰器,在想要统计耗时的函数上加一个注解就可以实现,即简介,也避免了修改函数导致的bug。

import time

def timeit(func):
    def wrapper():
        start_time = time.time()  # 记录开始时间
        result = func()
        end_time = time.time()    # 记录结束时间
        elapsed_time = end_time - start_time  # 计算耗时
        print(f"Function {func.__name__} took {elapsed_time:.4f} seconds to execute.")
        return result
    return wrapper

@timeit
def slow_function():
    print("Method greet has been called.")
    time.sleep(2)
    print("Function has finished execution.")

slow_function()
Method greet has been called.
Function has finished execution.
Function slow_function took 2.0037 seconds to execute.

二、带参数的装饰器

有时,我们需要向装饰器传递额外的参数。为了实现这一点,我们可以编写一个返回装饰器的工厂函数。

def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

greet("Bob")
Hello, Bob!
Hello, Bob!
Hello, Bob!

在这个例子中,repeat函数是一个装饰器工厂,它生成一个装饰器,该装饰器使被装饰的函数重复执行n次。

三、类的装饰器

装饰器不仅可以用于函数,也可以用于类。类装饰器可以用于修改类的行为或在类创建时进行一些初始化操作。

def method_decorator(method):
    def wrapper(*args, **kwargs):
        print(f"Calling method: {method.__name__}")
        result = method(*args, **kwargs)
        print(f"Method {method.__name__} has been called")
        return result
    return wrapper

# 遍历类中的每一个方法
def class_method_decorator(cls):
    for attr_name, attr_value in cls.__dict__.items():
        if callable(attr_value):
            setattr(cls, attr_name, method_decorator(attr_value))
    return cls

@class_method_decorator
class MyClass:
    def greet(self, name):
        print(f"Hello, {name}!")

instance = MyClass()
instance.greet("Charlie")
Calling method: greet
Hello, Charlie!
Method greet has been called

class_method_decoratorMyClass中的所有方法添加了日志打印功能。

上次编辑于:
贡献者: blacklad