Python装饰器

  1. 装饰器
    1. 自定义装饰器
    2. 返回装饰器
    3. 两种装饰器的不同点
    4. 装饰器类
    5. functools.warp

装饰器

装饰器本质上就是扩展原本函数功能的一种函数,通过函数闭包实现

函数闭包

定义在一个函数中的函数称为函数闭包

闭包三要素

  • 函数嵌套,即存在内函数和外函数
  • 内函数使用了外函数的变量或者参数
  • 外函数需要return内函数

自定义装饰器

def my_decorate(func):
    def method(a,b,*args):
        print("前置...")
        func(a,b) #调用
        print("后置...")
        print("其它参数:")
        for arg in args:
            print(arg)
    return method

@my_decorate
def add(a,b):
    print(f"a + b = {a+b}")


add(1,2,"arg1")
print("\n\n")
#使用@my_decorate等同于,不加装饰器将下面的调用格式转换为add(1,2,"arg1")
#my_decorate(add)(1,2,"arg1")

装饰器的功能增强了原有函数的功能

接收的func参数为@下一行的函数

返回装饰器

第二种装饰器是一种高阶装饰器,它返回另一个装饰器。这种装饰器可以接受参数,使得装饰器的行为可以根据传入的参数进行调整。在这个例子中,return_decorate函数接受一个参数flag,并返回一个装饰器decorate。这个装饰器再返回一个包装函数inner,它在调用原始函数之前打印flag的值。

def return_decorate(flag):
    def decorate(func):
        def inner(a, b):
            print(f"flag is {flag}")
            func(a, b)  # 调用
        return inner
    return decorate


@return_decorate("+")
def add(a,b):
    print(f"a + b = {a+b}")


add(1,2)

不同场景返回不同装饰器

def return_decorate(flag):
    if flag == '+':
        def decorate(func):
            def inner(a, b):
                print("add!")
                func(a, b)  # 调用
            return inner
        return decorate
    if flag == '-':
        def decorate(func):
            def inner(a, b):
                print("sub!")
                func(a, b) 
            return inner
        return decorate


@return_decorate("+")
def add(a,b):
    print(f"a + b = {a+b}")



add(1,2)

两种装饰器的不同点

  1. 参数传递:第一种装饰器不接受任何参数,它对所有被装饰的函数都是一样的行为。第二种装饰器接受参数,可以根据参数的不同改变装饰器的行为。
  2. 灵活性:第二种装饰器因为可以接受参数,所以更加灵活。你可以根据需要创建多个具有不同行为的装饰器,而不需要为每种行为编写一个新的装饰器函数。
  3. 使用方式:第一种装饰器直接应用于函数上,而第二种装饰器需要先调用(传入参数),然后再应用到函数上。
  4. 装饰器的装饰器:第二种装饰器展示了装饰器的装饰器(即高阶装饰器)的概念,这是Python装饰器的一个高级用法。

装饰器类

使用对象调用被修饰的函数

class MyDecorate(object):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("前置:装饰器类被调用了")
        self.func(*args, **kwargs)
        print("后置:装饰器类被调用了")

@MyDecorate
def add(a,b):
    print(f"a + b = {a + b}")

add(1,2)

这里的装饰器类,可以大大的增加的代码的通用性,同时需要注意,当类中出现__call__魔法方法时,该类大概率为装饰器类。

functools.warp

Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。写一个decorator的时候,最好在实现之前加上functools的wrap,它能保留原有函数的名称和函数属性

不加wraps

def my_decorator(func):
    def wrapper(*args, **kwargs):
        '''decorator'''
        print('Calling decorated function...')
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def example():
    """Docstring"""
    print('Called example function')

print(example.__name__, example.__doc__) #wrapper decorator

加上warp以后

import functools
def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        '''decorator'''
        print('Calling decorated function...')
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def example():
    """Docstring"""
    print('Called example function')

print(example.__name__, example.__doc__) #example Docstring

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 1300452403@qq.com

文章标题:Python装饰器

字数:1k

本文作者:Os467

发布时间:2024-12-03, 12:14:02

最后更新:2024-12-04, 15:51:49

原始链接:https://os467.github.io/2024/12/03/Python%E8%A3%85%E9%A5%B0%E5%99%A8/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

×

喜欢就点赞,疼爱就打赏