python中的装饰器

装饰器(Decorators)是一种方便的设计模式,它允许在不修改函数或类的情况下,动态地增加或改变其行为

本质上是一个函数,它接受另一个函数作为参数并返回一个新函数,通常是对原函数的某种增强或修改。

一、基本语法

def decorator_function(original_function):
    def wrapper_function(*args, **kwargs):
        # 在调用原始函数之前可以添加代码
        print("Wrapper executed before {}".format(original_function.__name__))
        
        # 调用原始函数
        result = original_function(*args, **kwargs)
        
        # 在调用原始函数之后可以添加代码
        print("Wrapper executed after {}".format(original_function.__name__))
        
        return result
    return wrapper_function

@decorator_function
def display():
    print("Display function executed.")

# 调用被装饰函数
display()

代码解读 

1. 定义装饰器:

  • decorator_function 是装饰器,它接受一个函数作为参数(original_function)。
  • 在 decorator_function 内部,定义了一个新的函数 wrapper_function,这个函数将在原始函数之前和之后执行额外的代码。

2. 使用装饰器:

  • 使用 @decorator_function 语法将 display 函数装饰为 wrapper_function相当于display 作为original_function传入。
  • 当调用 display() 时,实际上调用的是 wrapper_function

3. 输出结果:

  • 调用 display() 时,输出将是:

 二、工作原理

1. 定义装饰器:定义一个装饰器函数。这个函数将接受一个函数作为参数,并且通常会返回一个新的函数。

def my_decorator(func):
    # 这里是装饰器
    pass

2. 定义包装函数:在装饰器函数内部,定义一个包装函数(wrapper)。这个包装函数会在原始函数执行前后添加额外的功能。

def my_decorator(func):
    def wrapper():
        # 在调用原始函数之前执行的代码
        print("Before the function call")
        
        func()  # 调用原始函数
        
        # 在调用原始函数之后执行的代码
        print("After the function call")
    
    return wrapper

3. 返回包装函数:装饰器函数返回包装函数。这样,当使用这个装饰器时,原始函数会被包装函数所替代。

def my_decorator(func):
    def wrapper():
        print("Before the function call")
        func()
        print("After the function call")
    
    return wrapper

4. 使用@语法:在需要被装饰的函数定义上方使用 @decorator_name 语法。Python 解释器会自动将该函数作为参数传递给装饰器,并将返回的包装函数替代原始函数。

@my_decorator
def say_hello():
    print("Hello!")

# 调用装饰后的函数
say_hello()

三、进阶应用

3.1 带参数的装饰器

带参数的装饰器允许您在装饰器外部传递参数,以便可以根据需要配置装饰器的行为。

带参数的装饰器一般是通过定义一个外层函数(用于接受参数),并在其内部返回一个装饰器函数来实现的。

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")  # 调用函数
  • repeat(num_times): 外层函数,接受参数 num_times
  • decorator_repeat(func): 内层装饰器函数,接受一个函数作为参数。
  • wrapper(*args, **kwargs): 包装函数,负责调用原始函数多次。

输出结果:

3.2 装饰器带参数

装饰器的 "带参数" 意味着我们可以让装饰器接受不同的参数,通过这些参数来影响装饰器的行为。即装饰器中的包装函数(wrapper)需要接收这些参数,通常通过 *args **kwargs 实现。

举例:带参数的日志记录装饰器的示例,可以灵活地根据需要记录不同级别的日志。

def log(level):
    def decorator_log(func):
        def wrapper(*args, **kwargs):
            print(f"[{level.upper()}] Calling function '{func.__name__}' with arguments: {args}, {kwargs}")
            result = func(*args, **kwargs)
            print(f"[{level.upper()}] Function '{func.__name__}' returned: {result}")
            return result
        return wrapper
    return decorator_log

@log(level='info')
def add(a, b):
    return a + b

add(2, 3)  # 调用函数

 输出结果:

3.3 类装饰器

类装饰器是一个函数,它接受一个类作为参数,并返回一个新的类或修改后的同一个类。类装饰器可以用来添加方法、属性,或者修改类的行为。

3.3.1 添加方法

def my_class_decorator(cls):
    # 在类中添加一个新方法
    def new_method(self):
        return "This is a new method added to the class."

    cls.new_method = new_method
    return cls

@my_class_decorator
class MyClass:
    def original_method(self):
        return "This is the original method."

# 创建类的实例
instance = MyClass()
print(instance.original_method())  # 调用原始方法
print(instance.new_method())        # 调用新添加的方法

3.3.2 添加或修改类的属性

def add_class_attribute(cls):
    cls.new_attribute = "This is a new class attribute."
    return cls

@add_class_attribute
class MyClass:
    pass

# 访问新添加的类属性
print(MyClass.new_attribute)  # 输出: This is a new class attribute.

3.3.3 修改类的__init__方法

def modify_init(cls):
    # 保存原始的 __init__ 方法
    original_init = cls.__init__

    def new_init(self, *args, **kwargs):
        # 在初始化时打印消息
        print(f"Initializing an instance of {cls.__name__}")
        # 调用原始的 __init__ 方法
        original_init(self, *args, **kwargs)
        # 添加一个新的属性
        self.extra_info = "This is some extra info."

    # 替换原始的 __init__ 方法
    cls.__init__ = new_init
    return cls

@modify_init
class Person:
    def __init__(self, name):
        self.name = name

    def greet(self):
        return f"Hello, my name is {self.name} and {self.extra_info}."

# 创建 Person 的实例
person = Person("Alice")

# 调用 greet 方法
print(person.greet())

输出:

 

  • 类装饰器 modify_init:修改了 Person 类的 __init__ 方法,以便在实例化时打印消息,并添加一个新的属性 extra_info
  • 使用装饰器:使用 @modify_init 装饰器,使得 Person 类的行为得到了增强。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小老大MUTA️

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值