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}
View Code
举例:
 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



原文地址:https://www.cnblogs.com/yum777/p/6771403.html