zoukankan      html  css  js  c++  java
  • 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



  • 相关阅读:
    学习:HelloWorld项目目录
    学习:java设计模式—Adapter模式
    学习:java设计模式—Decorator模式
    MyEclipse8.5/8.6不能安装ADT
    学习:Android框架
    笔记:代码整洁之道
    JVM常用启动参数
    春雷第一声初入博客
    在Winform中更改控件导致designer中代码自动移除解决方法
    C#生成灰度图片:拖动图片到picturebox显示,拖动picturebox图片到资源管理器 (Drag & drop )
  • 原文地址:https://www.cnblogs.com/yum777/p/6771403.html
Copyright © 2011-2022 走看看