python decorator的理解

本文深入探讨了Python装饰器的两种等价形式,并介绍了一种优雅的装饰器使用方式,允许装饰器既可以接受参数也能不接受参数。通过双层装饰器的设计,文章详细解释了如何根据不同调用情况返回合适的装饰器函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. python的decorator语法有两种等价形式,分别如下:

第一种形式
@dec2
@dec1
def func(arg1, arg2, ...):
    pass

This is equivalent to:

def func(arg1, arg2, ...):
    pass
func = dec2(dec1(func))

第二种形式:
@decomaker(argA, argB, ...)
def func(arg1, arg2, ...):
    pass

This is equivalent to:

func = decomaker(argA, argB, ...)(func)

2. 本文主要是介绍一种比较优雅的python decorator的使用方式

即对于一个decorator即要能够给予参数,又能不给予参数.如果使用它的第二种形式则对于没有参数时也必须用@decomaker()这种形式,通过本文的这种方法可以实现对于没有参数时使用@decomaker即可,对于有参数时使用@decomaker(argA,argB,..)的形式使用.解决这个问题的方法是对与decorator再使用一层decorator.对于被修饰的decorator有无参数返回两种不同的函数,从而实现该功能.即使用一个decoratordecorator函数修饰decorator函数,使得它在被修饰函数按等价语法调用decorator函数时,根据它的参数个数生成不同函数,从而实现该功能. 对于decorator被采用无参数的格式调用是,它的等价形式是被修饰的函数f应该等价于decorator(f),所以此时的decoratordecorator应该返回decorator(f).对于decoartor采用@decoartor(argA,argB,..)调用时,此时的decoratordecorator应该返回decorator(argA,argB,..)(f).对于这种连着的调用函数的形式我们可以使用闭包来实现,从左到右的括号内的参数对应则从里到外的函数的实参.decoratordecorator对于decorator的修饰肯定是用无参的形式.即等价形式是decorator=decoratordecorator(decorator)具体的代码如下:

def wrapper(function):
    def fun(*args, **kwargs):
        print('in wrapper, you add to do something')
        return function(*args, **kwargs)

    return fun


@wrapper
def decoratored(*args, **kwargs):
    print('in fun, args is {0}, kwargs is {1}'.format(str(args), str(kwargs)))

def test_wrapper():
    decoratored(1,2, a=2)

def double_wrapper(function):
    def decorator(*args, **kwargs):
        if len(args)==1 and len(kwargs)==0 and callable(args[0]):
            return function(args[0])
        else:
            def fn( decoratedFn):
                # print('in double_wrapper fn decorator, args is {0}, kwargs is {1}'.format(str(args1), str(kwargs1)))
                return function(decoratedFn, *args, **kwargs)
            return fn
    return decorator

@double_wrapper
def first_double_wrapper(function, *args, **kwargs):

    def decorator(*args1, **kwargs2):
        print('in first_double_wrapper decorator, args is {0}, kwargs is {1}'.format(str(args), str(kwargs)))
        print('in first_double_wrapper decorator, args is {0}, kwargs is {1}'.format(str(args1), str(kwargs2)))
        return function(*args1, **kwargs2)
    return decorator




def first_wrapper(*args, **kwargs):

    def decorator(function):
        print('this is execute only once')
        def func(*args1, **kwargs1):
            print('wrapper argments is ' + str(args) + " kwargs is " + str(kwargs))
            print('in wrapper, you add to do something')
            return function(*args1, **kwargs1)

        return func

    return decorator





def test_first_wrapper():
    @first_wrapper(1, 2, c=12)
    def decoratored2(*args, **kwargs):
        print('in fun, args is {0}, kwargs is {1}'.format(str(args), str(kwargs)))

    decoratored2(2,3,4, b=5)
    decoratored2(2, 3, 4, b=5)


def test_second_wrapper():
    @first_double_wrapper(2,3) #此处实现了可以采用@first_double_wrapper的调用方式
    def decoratored2(*args, **kwargs):
        print('in fun, args is {0}, kwargs is {1}'.format(str(args), str(kwargs)))
    decoratored2(2,3,5, b=7)

if __name__ == "__main__":
    # test_wrapper()
    # test_first_wrapper()
    test_second_wrapper()

在上面的用另一个wraper来包装一个wrapper,使得@wrappe()这种格式可以用不要括号的第一种
wrapper格式来表示,则需要修改first_double_wrapper如上面的样子,然后使用另一个wrapper来
修改first_double_wrapper,其中主要的是将first_double_wrapper中的一个闭包函数移到double_wrapper
中,可以通过上面的first_double_wrapper与first_wrapper的代码可知道。
要想清楚的理解闭包,需要根据它的等价形式,然后通过闭包函数来构建相应的函数调用形式。
而对于本文提到的两个wrapper的改造形式,则要注意first_double_wrapper的抽象,以及将带参数的
wrapper的一个闭包移动到double_wrapper中,而使得将一个统一的处理过程放入到了first_double_wrapper中。

我认为在使用decorator的过程中,可以叠加的使用decorator,但是在构建decorator的过程中,可以从
最底层的靠近decorator的部分开始构造,然后在保证函数功能的基础上一步步的修改decorator函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值