理解装饰器的各种执行细节

2017-10-05  本文已影响218人  那未必

当装饰器遇上尾递归函数

如果一个尾递归函数套用了装饰器,那么当一次递归发生后,是尾递归内部的代码先执行,还是装饰器中尾递归函数之后的代码先执行?具体看下面的代码:

def deco(func):
    def handler(*args,**kwargs):
        print 'inside decorator, begin to decorate...'
        # func 内部有打印语句
        # 在递归发生时,究竟是 func内部的打印语句先执行
        # 还是下面的 end of decorate 先执行?
        func(*args,**kwargs)
        print 'end of decorate!'
    return handler

@deco
def adding(count=0):
    print 'count=',count
    if count<3:
        return adding(count+1)
    else:
        print 'count is equal to 3. stop'

adding()
inside decorator, begin to decorate...
count= 0
inside decorator, begin to decorate...
count= 1
inside decorator, begin to decorate...
count= 2
inside decorator, begin to decorate...
count= 3
count is equal to 3. stop
end of decorate!
end of decorate!
end of decorate!
end of decorate!

结论

如果装饰器内部,在尾递归函数的执行代码之后还有其他代码,那么这些代码必须等到尾递归内部的代码执行完毕之后才会执行。

某些使用场景下,可能我们还需要在装饰器内部对于被装饰方法传入的某个参数进行修改,那么该如何获取指定的参数呢?

其实只要打印一下 args 和 kwargs 就明白如何使用了。

def response_validate(func):
    def decorate(*args,**kwargs):
        print 'now decorating...'
        args=list(args)
        args[0]='tell'
        print args
        print 'args 是元组,不能直接修改变量除非修改为 list;kwargs 是字典,可以修改'
        if kwargs.get('count')!=None:
            print 'kwargs[\'count\']=',kwargs['count']
            kwargs['count']+=1
            print '修改后kwargs[\'count\']=',kwargs['count']
        r=func(*args,**kwargs)
        print 'decorated!'
        return r
    return decorate

def main(s,count=0):
    @response_validate
    def test(s,count=0):
        print 'inside decorated func...s=',s
        print 'inside decorated func...count=',count
        return count + 1
    return test(s,count=count)

main('main',count=3)
now decorating...
['tell']
args 是元组,不能直接修改变量除非修改为 list;kwargs 是字典,可以修改
kwargs['count']= 3
修改后kwargs['count']= 4
inside decorated func...s= tell
inside decorated func...count= 4
decorated!

5

类装饰器的创建和使用方法

类装饰器与普通装饰器的差别在于类装饰器可以拦截类内部的方法,在执行诸如 init, getattr 等方法之前或之后植入逻辑代码。

def Tracer(aClass):
    class Wrapper:
        def __init__(self,*args,**kwargs):
            self.fetches=0
            self.wrapped=aClass(*args,**kwargs)
        def __getattr__(self,attr_name):
            print 'Tracer attrname=',attr_name
            self.fetches+=1
            return getattr(self.wrapped,attr_name)
    return Wrapper

@Tracer
class Spam:
    def __init__(self):
        self.name='spamee'
    def display(self):
        print 'Spam class'

sp=Spam()
sp.display()
sp.display()
sp.name

Tracer attrname= display
Spam class
Tracer attrname= display
Spam class
Tracer attrname= name


'spamee'
上一篇下一篇

猜你喜欢

热点阅读