引子:
我以为我会了,看了看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’
三层装饰器:
def three_warp(*args,**kwargs):
"""
three_warp 参数可以 用来做判断条件也可以扩展 用在内层函数 或者 内内层函数
这里 只是推到
"""
print("in three_warp",args, kwargs)
def inner_warp(f):
print("in inner_warp",args,kwargs)
def inner(name,id=1):
print("三层开始")
ret=f(name,id=id)
print("三层结束")
return ret
return inner
return inner_warp
@three_warp(1,2,3,ttt=999)
def func6(name,id=None):
print("in func6 name id======",name,id)
return name,id
if __name__ == ‘__main__‘:
print(func6(77,id=88))
打印结果:
in three_warp (1, 2, 3) {‘ttt‘: 999}
in inner_warp (1, 2, 3) {‘ttt‘: 999}
三层开始
in func6 name id 77 88
三层结束
(77, 88)
过程: 1 @three_warp(1,2,3,ttt=999) 实际执行inner_warp(f) 返回 inner 这时候func6=inner 2 func6(77,id=88) 执行 inner(77,id=88)
总结:
1 python的gc机制 引用归零
2 装饰器内参数的引用,以及使用时传参数的顺序
3 装饰器本身就是个闭包函数
4 多看框架源码 无论知识体系还是代码风格都是一种加强,并且不是一星半点
原文:https://www.cnblogs.com/yuan-x/p/14725940.html