day6 装饰器总结
装饰器:开放封闭原则,为一个函数加上新的功能,不改变原函数,不改变调用方式
def fun2(wtf):
def fun3():
print('i am pythoner!!! ')
wtf()
return fun3
@fun2
def fun1():
print('this is fun1')
fun1()
输出:
i am pythoner!!!
this is fun1
1 def fun2(wtf): 2 def fun3(*args, **kwargs): 3 print('i am pythoner!!! ') 4 wtf(*args, **kwargs) 5 return fun3 #这里不是fun3()是因为:return作用在于函数赋值,即让fun3指向fun1的函数内存地址 6 7 @fun2 # @fun2 当于fun1 = fun2(fun1) ,把下面的函数传递到装饰器函数里面,相当于 fun1 = fun2(fun1) = fun3(用return令fun1=fun3), 后面再执行fun1() , 相当于执行fun3() 8 def fun1(arg, arg2): 9 print('this is fun1: %s %d' % (arg, arg2)) 10 fun1('tom', 55) #注意此处fun1()调用的实际是fun3(),而不是原来的fun1()了
注意:只要函数应用装饰器,函数就被重新定义,重新定义为:装饰器的内层函数
def runtime(func):
def warpper():
start_time = time.time()
func()
end_time = time.time()
print 'run time is %s' % (end_time-start_time)
return warpper
@runtime
def test1():
time.sleep(3)
print 'in the test1'
test1()
带参数的装饰器举例:
1 def outer(func): 2 def inner(a, b): 3 print('heihei') 4 r = func(a, b) #func即index函数,即inner函数 5 return r 6 return inner 7 8 9 @outer # index = outer(index) = inner 10 def index(a1, a2): 11 print('----------') 12 return a1 + a2 13 14 print(index(1, 2)) 15 16 输出: 17 heihei 18 ---------- 19 3
@outer 作用
1. 执行outer函数,将index作为参数传递
2. 将outer的返回值,重新赋值给index
3. 执行index函数时不再是原来的index函数,而是执行装饰器中的inner函数(由装饰器中的return赋值使index=inner)
带N个参数的装饰器:
应用场景:
当一个装饰器装饰多个函数时,而这些函数的参数个数都不相同时。
原理:
1 #原理: 2 def f1(*args, **kwargs): 3 print(args) 4 print(kwargs) 5 6 f1(1, 2, 3, 4, M1='123') 7 输出: 8 (1, 2, 3, 4) 9 {'M1': '123'} 10 11 dic = {'a': 2, 'b': 23333} 12 tup = (1, 2, 3) 13 f1(*tup, **dic) 14 15 输出: 16 (1, 2, 3) 17 {'a': 2, 'b': 23333}
举例:
1 def outer(func): 2 def inner(*args, **kwargs): 3 print('into inner') 4 print('the arg is :', *args, **kwargs) 5 r = func(*args, **kwargs) 6 return r 7 return inner 8 9 @outer # index = outer(index) = inner 10 def index(a1, a2): 11 print('----------') 12 return a1 + a2 13 14 print(index(1, 2)) 15 16 @outer # f1 = outer(f1) = inner 17 def f1(a1): 18 print('++++++++++++++++++++++++++') 19 return a1 * a1 20 print(f1(2)) 21 22 #输出: 23 into inner 24 the arg is : 1 2 25 ---------- 26 3 27 into inner 28 the arg is : 2 29 ++++++++++++++++++++++++++ 30 4
多个装饰器装饰同一个函数:
1 def outer(func): #func等同于outer2中的inner2 2 def inner(*args, **kwargs): 3 print('first decorate-------------') 4 print('the arg is :', *args, **kwargs) 5 r = func(*args, **kwargs) #func等于outer2中的inner2,r值为inner2中的 return r 6 print('first decorate-------------') 7 return r # r的值最终返回给index 8 return inner 9 10 11 def outer2(func): #func等于index 12 def inner2(*args, **kwargs): #inner2等同于于outer2+被outer2装饰的index函数 13 print('second decorate-----------') 14 r = func(*args, **kwargs) #func等于index,r值为index的return a1 + a2 15 print('second decorate------------') 16 return r #r为inner2的返回值,返回给outer中的func函数 17 return inner2 18 19 20 @outer # outer(inner2) = inner, 作用:将outer2装饰的index,即inner2当作参数传递到第一个装饰器中outer中 21 @outer2 # index = outer2(index) = inner2 22 def index(a1, a2): 23 print('ori func----------') 24 return a1 + a2 25 26 print(index(1, 2)) 27 28 输出: 29 first decorate------------- 30 the arg is : 1 2 31 second decorate----------- 32 ori func---------- 33 second decorate------------ 34 first decorate------------- 35 3
执行顺序说明:
当运行index(1, 2)时,
1.执行第一个装饰器outer中的inner函数
2.由1步中的inner函数中的func函数,执行outer2中的inner2函数
3.执行outer2中inner2中的func函数,即执行最初需要装饰的index函数
4.index的返回值返回给它的调用者,即inner2中的func函数
5。inner2的返回值返回给它的调用者,即inner中的func函数
6.将r返回给index函数
https://segmentfault.com/a/1190000007837364 def decorator_b(func): print ('Get in decorator_b') # 2 def inner_b(*args, **kwargs): print ('Get in inner_b') # 3 return func(*args, **kwargs) return inner_b def decorator_a(func): print ('Get in decorator_a') # 1 def inner_a(*args, **kwargs): print ('Get in inner_a') # 4 return func(*args, **kwargs) return inner_a @decorator_b @decorator_a def f(x): print ('Get in f') # 5 return x * 2 f # 分步骤来,这里很重要。这里会先后打印出Get in decorator_a 和Get in decorator_b 1、输入函数名f,意味着将函数f作为参数,传入装饰器a和b。 1.5、但是并未调用函数f(x),也就是f(x)函数并不会执行,因为没有传入参数。重点也就在这,函数和函数调用是不一样的。 2、f首先传入装饰器a,也就是装饰器a函数获得参数被调用,那么就执行打印,并同时返回函数inner_a。 2.5、当然,此时函数inner_a也没有被调用。因为同样没有参数传入。 3、inner_a传入装饰器b,也就是装饰器b函数获得参数被调用,那么也执行打印,并同时返回函数inner_b。 4、现在就是返回函数inner_b>inner_a>f f(1) # 然后输入这段代码,会先后打印出Get in inner_b和Get in inner_a,以及Get in f 5、此时函数f获得参数1,即函数被调用,由于上面步骤4中最后返回函数是inner_b,那么最先调用最外层的函数,print先行,也就是先打印Get in inner_b,再返回inner_a函数; 6、进而调用inner_a函数,print先行,也就是先打印Get in inner_a,再返回f(1)函数; 7、最后调用f(1)函数,print先行,也就是先打印Get in f,再返回2。 8、这样顺序就理顺了,哈哈,我这么理解的。
装饰器由下到上依次立马执行,之后我们调用的f已经是被装饰器执行了之后的f了,此时是由上到下返回去依次调用。整个过程有点像先上楼梯(装饰过程),再下楼梯(调用函数)
在实际应用的场景中,当我们采用上面的方式写了两个装饰方法比如先验证有没有登录 @login_required
, 再验证权限够不够时 @permision_allowed
时,我们采用下面的顺序来装饰函数:
@login_required
@permision_allowed
def f()
# Do something
return
小结:执行装饰器函数的顺序是由下到上(由内到外),调用f(被装饰的函数)是由上到下
对于装饰器来说,在这里程序从上到下执行,开始记录装饰器1-3,然后读到了函数的时候,装饰器开始装饰,把函数的引用传入装饰器中,从装饰器3开始往上装饰,所以这时候开始执行装饰器3的初始化,并把装饰完的函数当做一个新的函数,再次把新的引用传入到装饰器2,接着装饰器2进行初始化,再次把新的函数的引用传入到装饰器1进行装饰,这时候装饰器1的初始化开始,并开始执行,从而接下来的执行顺序为1-3执行装饰的内容,最后再执行本来的函数,达到一个对原有函数增加功能和特性的要求。 装饰器:从程序开始的顺序,从上到下读取----》从下到上装饰----》从上到下执行
https://www.cnblogs.com/wf-skylark/p/9310448.html
def a(func): print 'Get in decorator_a' def inner_a(*args, **kwargs): print 'Get in inner_a' print "in a, args ", args print "in a, kwargs ", kwargs kwargs.update({"params": "1234"}) return func(*args, **kwargs) return inner_a def b(func): print 'Get in decorator_b' def inner_b(*args, **kwargs): print 'Get in inner_b' print "in b, args ", args print "in b, kwargs ", kwargs return func(*args, **kwargs) return inner_b @b @a def f(x, params): print 'Get in f' print "params: ", params return x * 2 f(*(1, )) # 执行步骤: 执行f(*(1, )),调用装饰器a(即执行a函数:a(f)), a返回一个inner_a (inner_a = a(f)),执行f(*(1, ))等价于inner_a(*(1, )) # 调用装饰器b,并把inner_a(*(1, ))传入b中,inner_a = inner_b ,inner_a(*(1, ))即执行inner_b(*(1, )), # inner_b执行后return并执行inner_a(*(1, )),最后在inner_a中return并执行f(*(1, )) #结果: Get in decorator_a Get in decorator_b Get in inner_b in b, args (1,) in b, kwargs {} Get in inner_a in a, args (1,) in a, kwargs {} Get in f params: 1234
示例:
def decorator_a(func): # print func.func_name print 'in a' def inner_a(*args, **kwargs): print 'Get in inner_a' return func(*args, **kwargs) return inner_a def decorator_b(func): # print func.func_name print 'in b' def inner_b(*args, **kwargs): print 'Get in inner_b' return func(*args, **kwargs) return inner_b @decorator_b # 相当于decorator_b包裹了decorator_a,decorator_a包裹了f(x) ,decorator_a包裹了f(x)等同于 inner_a,同理,decorator_b包裹的函数等于inner_b @decorator_a def f(x): print 'Get in f' return x * 2 print f(1) # 相当于执行f(1) = decorator_b(decorator_a(f(1))) = inner_b(1) # 调用顺序:有内到外,先由f(1)传入装饰器decorator_a,打印“in a”, 返回inner_a, # 执行顺序,先执行decorator_b中的inner_b函数,再执行decorator_a中的inner_a。
https://zhuanlan.zhihu.com/p/26889350
自身带参数的装饰器
例1:
1 user_list=[ 2 {'name':'alex','passwd':'123'}, 3 {'name':'linhaifeng','passwd':'123'}, 4 {'name':'wupeiqi','passwd':'123'}, 5 {'name':'yuanhao','passwd':'123'}, 6 ] 7 current_dic={'username':None,'login':False} 8 9 def auth(auth_type='filedb'): 10 def auth_func(func): 11 def wrapper(*args,**kwargs): 12 print('认证类型是',auth_type) 13 if auth_type == 'filedb': 14 if current_dic['username'] and current_dic['login']: 15 res = func(*args, **kwargs) 16 return res 17 username=input('用户名:').strip() 18 passwd=input('密码:').strip() 19 for user_dic in user_list: 20 if username == user_dic['name'] and passwd == user_dic['passwd']: 21 current_dic['username']=username 22 current_dic['login']=True 23 res = func(*args, **kwargs) 24 return res 25 else: 26 print('用户名或者密码错误') 27 elif auth_type == 'ldap': 28 print('鬼才特么会玩') 29 res = func(*args, **kwargs) 30 return res 31 else: 32 print('鬼才知道你用的什么认证方式') 33 res = func(*args, **kwargs) 34 return res 35 36 return wrapper 37 return auth_func 38 39 @auth(auth_type='filedb') #auth_func=auth(auth_type='filedb')-->@auth_func 附加了一个auth_type --->index=auth_func(index) 40 def index(): 41 print('欢迎来到京东主页') 42 43 @auth(auth_type='ldap') 44 def home(name): 45 print('欢迎回家%s' %name) 46 # 47 @auth(auth_type='sssssss') 48 def shopping_car(name): 49 print('%s的购物车里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃')) 50 51 # print('before-->',current_dic) 52 # index() 53 # print('after--->',current_dic) 54 # home('产品经理') 55 shopping_car('产品经理')
例2:
1 # !/usr/bin/env python 2 # coding:utf-8 3 4 5 def before(request, kargs): 6 print('before') 7 8 9 def after(request, kargs): 10 print('after') 11 12 13 def Filter(before_func, after_func): 14 def outer(main_func): 15 def wrapper(request, kargs): 16 17 before_result = before_func(request, kargs) 18 if before_result: 19 return before_result 20 21 main_result = main_func(request, kargs) 22 if main_result: 23 return main_result 24 25 after_result = after_func(request, kargs) 26 if after_result: 27 return after_result 28 29 return wrapper 30 31 return outer 32 33 # outer = Filter(before, after) ---> 相当于@outer附带参数(before, after) 相当于执行 ==> index = outer(index) 34 @Filter(before, after) 35 def index(request, kargs): 36 print('index') 37 38 index(1,2) 39 40 41 # 带参数的装饰器:利用装饰器的最外层函数传参
装饰器------------自己的理解(持续更新)
1 def fun2(wtf): 2 def fun3(): 3 print('i am pythoner!!! ') 4 wtf() 5 return fun3 6 7 8 @fun2 9 def fun1(): 10 print('this is fun1') 11 fun1() 12 13 输出: 14 i am pythoner!!! 15 this is fun1 16 17 18 19 fun2只是个桥梁: 20 0.把要装饰的函数接收进来,嵌套进包含新功能的函数(这个函数同时包含原函数功能) 21 1.让fun1和fun3内存地址相同 22 23 24 目的:装饰后在fun1()执行前后再执行一些其他的动作 25 26 27 28 def outer(func): # 29 def inner(a, b): # 2 a:1 b:2 30 print('heihei') # 3 31 r = func(a, b) # func即index函数,即inner函数 # 4 32 return r # 如果index有返回值,这里要加上return返回index的返回值 # 7 33 return inner # 作用:让index和inner内存地址相同 34 35 36 @outer # index = outer(index) = inner 37 def index(a1, a2): 38 print('----------') # 5 39 return a1 + a2 # 6 40 41 42 print(index(1, 2)) # 偷梁换柱,相当于直接执行包含原函数功能的函数inner(1, 2) # 1
def write_log(func): def wrapper(a, b): print 'log --------------' return func(a, b) return wrapper # @write_log def bar(a,b): return a + b print write_log(bar)(1, 3) # write_log(bar) 等于 wrapper # write_log(bar)(1, 3) 等于 wrapper(1, 3) #输出: log -------------- 4
def public(f): """" Use a decorator to avoid retyping function/class names. Based on an idea by Duncan Booth: http://groups.google.com/group/comp.lang.python/msg/11cbb03e09611b8a Improved via a suggestion by Dave Angel: http://groups.google.com/group/comp.lang.python/msg/3d400fb22d8a42e1 """ # all = sys.modules[f.__module__].__dict__.setdefault('__all__', []) # if f.__name__ not in all: # Prevent duplicates if run from an IDE. # all.append(f.__name__) print('new feature ---') # return '1123' return f # public(public) # Emulate decorating ourself # @public # public(str_fsize)(10000) def str_fsize(sz): """ Formats file size as string (i.e., 1.2 Mb) """ if sz < 1024: return '%.1f bytes' % sz sz /= 1024.0 if sz < 1024: return '%.1f KB' % sz sz /= 1024.0 if sz < 1024: return '%.1f MB' % sz sz /= 1024.0 if sz < 1024: return '%.1f GB' % sz sz /= 1024.0 return '%.1f TB' % sz a = public(str_fsize)(1000000) print(a) # a = str_fsize(1000000) # print(a)
新的理解:
如果只在函数执行前加某些功能,装饰器可以简化:
import time def decorator(sss): print("begin to run xxx") return sss @decorator def fun(a): time.sleep(1) print(a)
fun(3) # 相当于在执行decorator(fun)(3) => return fun => fun(3) (扒皮,脱壳)
# decorator(fun)(3) # 注意:decorator(fun)和fun完全等价,内存地址相同
# begin to run xxx # 3
def public(f): """" Use a decorator to avoid retyping function/class names. Based on an idea by Duncan Booth: http://groups.google.com/group/comp.lang.python/msg/11cbb03e09611b8a Improved via a suggestion by Dave Angel: http://groups.google.com/group/comp.lang.python/msg/3d400fb22d8a42e1 """ # all = sys.modules[f.__module__].__dict__.setdefault('__all__', []) # if f.__name__ not in all: # Prevent duplicates if run from an IDE. # all.append(f.__name__) def inner(a): print('new feature1 ---') # 要添加的新功能 val = f(a) print('new feature2 ---') # 要添加的新功能 return val # 原函数有返回值这里必须返回 # return '1123' return inner # public(public) # Emulate decorating ourself @public # public(str_fsize)(10000) def str_fsize(sz): """ Formats file size as string (i.e., 1.2 Mb) """ if sz < 1024: return '%.1f bytes' % sz sz /= 1024.0 if sz < 1024: return '%.1f KB' % sz sz /= 1024.0 if sz < 1024: return '%.1f MB' % sz sz /= 1024.0 if sz < 1024: return '%.1f GB' % sz sz /= 1024.0 return '%.1f TB' % sz a = str_fsize(1000000000000000) print(a)
装饰器含参:
import time def decorator(sss): print('aaa', sss) def outer(aaa): print('aaa', sss) def inner(s): print("begin to run xxx") aaa(s) print("run completed") return inner return outer @decorator(123) def fun(a): time.sleep(1) print(a) fun(3)
#输出:
aaa 123
aaa 123
begin to run xxx
3
run completed