python的装饰器

引子:

  我以为我会了,看了看flask路由的源码,大概一看能看懂,仔细推敲发现还是理解的浅显,写篇博客压压惊吧。

 

代码:

  普通写法 装饰器不传参数

def warp3(f):
     ''' 这个f 是形参数 哪怕你传个 x,y,z 它也是被装饰的函数 有点像类方法中的 第一个参数self'''
    print(f)
    def inner(*args,**kwargs):
        print("in warp3")
        ret=f(*args,**kwargs)
        return ret
    return inner

@warp3
def func4(*args,**kwargs):
    return 444

func4 ====这个时候 func4 已经重新指向了装饰器中的 inner 不信打印下结果

  带参数的写法

test_dict={}

def warp(rule,**options):
    def inner(f):
        print(13)
        enpoint=options.pop("enpoint",None) or f.__name__
        test_dict[enpoint]=f
        return f
    return inner



@warp('uuuu')
def func(*args,**kwargs):
    return 1


if __name__ == '__main__':
    pass 即使没有调用func 这里其实已经执行了装饰器
    装饰器本身也是个函数 @warp('uuuu')  这里等于执行了inner函数
    # func()
    # print(test_dict)

  对应的flask route部分源码

    def route(self, rule, **options):
        
        print("route===>",rule,options)
        def decorator(f):
            print("route=decorator==>", f)
            endpoint = options.pop("endpoint", None)
            self.add_url_rule(rule, endpoint, f, **options)
            return f

        return decorator

      打印结果

route===> / {'methods': ['GET', 'POST'], 'endpoint': 'test_index'}
route=decorator==> <function index at 0x7fb60dfac0d0>

  其实等同于 ret= decoator 然后 decoator又去装饰的 视图函数 

 

  其他写法:

def warp3(rule): 同样这里 rule 还是 形参
    def inner(*args,**kwargs):
        print("in warp3")
        ret=rule(*args,**kwargs)
        return ret
    return inner

@warp3
def func4(*args,**kwargs):
    return 444

  上述写法中并不会报错 因为rule 默认是 被装饰函数 ,并且下方也引用了,但是下方写法会报错

test_dict={}

def warp(rule,**options):
    print(12)
    def inner(f):
        print(13)
        enpoint=options.pop("enpoint",None) or f.__name__
        test_dict[enpoint]=f
        return f
    return inner

@warp  # 本质 也是 函数 不加 () 不调用  下方在直接调用的时候 会报错 
def func2(*args,**kwargs):
    return 2

if __name__ == '__main__':
    func2()

报错的原因是 在装饰器执行的时候rule 形参 就是 被装饰函数 实际返回的是inner
inner需要 一个参数 f 也是形参 但是下方调用的时候没有传

   改下写法就不会报错

test_dict={}

def warp(rule,**options):
    print(12)
    def inner(f):
        print(13)
        enpoint=options.pop("enpoint",None) or f.__name__
        test_dict[enpoint]=f
        return f
    return inner

@warp
def func2(*args,**kwargs):
    return 2

if __name__ == '__main__':
    这里需要传一个 可调用对象 否则 装饰器中  f.__name__报错 程序中断
    func2(lambda a:1) 

  正经写法推理

def warp2(f):
    def inner(*args,**kwargs):
        print("in warp2 ")
        ret=f(*args,**kwargs)
        return ret
    return inner


@warp2
def func3(*args,**kwargs):
    return func3.__name__

if __name__ == '__main__':
    # print(func3())


1 装饰只接受了 被装饰函数 没有其他参数 这时候实际返回的是  inner
2 func3() 调用的时候 实际上 是执行的inner 

  再次证明 装饰器第一个参数 是 被装饰函数

def warp5(args,**options):
    print(args, options)
    def inner(name):
        print(args,options)
        ret=args(name)
        return ret
    return inner

@warp5
def func5(name,**kwargs):
    print(name)
    return func5.__name__



if __name__ == '__main__':
   #print(func5('rrr'))

1 同上 这里 装饰器没加括号 返回的依然是inner 虽然第一个参数是args 依然是形参数
如果你传了 *args 。。。。
2 同样又给inner传参数 name = ‘rrr’

  

总结:

  1 python的gc机制 引用归零 

      2 装饰器内参数的引用,以及使用时传参数的顺序

  3 装饰器本身就是个闭包函数

      4 多看框架源码 无论知识体系还是代码风格都是一种加强,并且不是一星半点

  

上一篇:python--闭包


下一篇:Typroa 编辑器的 SM.MS 免费图床上传器