引子:
我以为我会了,看了看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 多看框架源码 无论知识体系还是代码风格都是一种加强,并且不是一星半点