zoukankan      html  css  js  c++  java
  • Python—装饰器详解

    装饰器:(语法糖)

    本质是函数,它是赋予函数新功能,但是不改变函数的源代码及调用方式
     
    原则:
    1.不能修改被装饰函数的源代码
    2.不能修改被装饰函数的调用方式
    3.函数的返回值也不变
    这两点简而言之,就是装饰器对被装饰函数来说是透明的
     
    知识储备
    1.函数即变量
         比如定义了一个变量  x = ‘gkx’   python是一门解释性语言,解释了‘gkx’,并给它分配了内存地址,而 x 就是这个内存地址的一个索引,类似门牌号。
    同理可得 def test():print('gkx') 定义了一个函数  test是它的门牌号,print('gkx')分配了一个内存地址。故可以理解为函数即变量。
    2.高阶函数
        a.把一个函数名当作实参传递给另外一个函数(在不改变函数源代码的情况
    为其添加新功能)
        b.返回值中包含函数名(不改变函数调用方式
    3.嵌套函数
    1 嵌套函数  在一个函数的函数体内,用def声明一个新函数
    2 def foo():
    3     print('in the foo.')
    4     def bar():
    5         print('in the bar.')
    6     bar()        #要调用bar需要在在函数体内调用,类似局部变量
    7 foo()

    装饰器例子:仅针对注释的几段,对其进行排序,如下红字

     1 import time       #python的debug都是先读取最外层框架(最外层没有缩进),最外层中如果涉及到调用,再接着运行调用内容。  第一步
     2                                     
     3 def timer(func): #当读取到 @timer的时候,相当于运行 test1 = timer(test1),所以会返回来读取 warpper  第三步
     4     def warpper(*args,**kwargs):
     5         start_time = time.time()
     6         func(*args,**kwargs)  #此时才是真正意义上运行 test1函数  第六步
           return func(*args,**kwargs) #保证fun()返回值也不变
    7 stop_time = time.time() 8 print('in the test1() %s'%(stop_time-start_time)) 9 return warpper #把test1当作实参传递给 timer,timer(test1),此时返回的是 函数warpper的内存地址 第四步 10 11 #然后此时运行到 python里的语法【@timer】 12 @timer #相当于 test1 = timer(test1),返回warpper的内存地址,此时如果运行 test1(),相当于 warpper(),warpper就开始执行其函数体内的语句 第二步 13 def test1(): 14 time.sleep(1) 15 print('in the test1')
        return ‘from test1’
    16 test1() #此时运行的 test1()已经不是直接运行 test1函数了,是经过@timer,转换成运行 warpper()了 第五步

     装饰器进阶版,装饰器本身带参数

     1 user = 'gkx'
     2 pass_1 = '123'
     3 def decorator(auth_type):
     4     print("auth type",auth_type)
     5     def outer_warpper(func):
     6         def warpper(*args,**kwargs):
     7             if auth_type == 'local':
     8                 username = input("id")
     9                 password = input("password")
    10                 if username == user and password == pass_1:
    11                     print('33[32;1mwelcome33[0m')
    12                     res = func(*args,**kwargs)
    13                     print("after decorator")
    14                     return res
    15                 else:
    16                     print('33[31;1mwrong info33[0m')
    17             elif auth_type == 'ldap':
    18                 print('我不会')
    19         return  warpper
    20     return outer_warpper    #当访问到这里的返回值时候,会继续执行 warpper,然后执行逻辑就和上面提到的timer一样了
    21 
    22 
    23 
    24 @decorator(auth_type='local')  #这里分成两部分看,第一部分是 调用decorator(auth_type = 'local'),此时返回outer_wrapper的内存地址
                        #在第一部分的基础上,此时加上@,变成了 @outer_wrapper,相当于 homepage = outer_wrapper(wrapper),再返回了wrapper的内存地址

    25 def homepage():
    26   print('home page')
    27   return 'from home'

    29 @decorator(auth_type='ldap') 30 def bbs(): 31 print('in bbs') 32 33 print(homepage()) 34 bbs()

    装饰器三个重要补充:

    #一共有三个
    
    # 第一个
    from functools import wraps
    
    def outer(func):
        @wraps(func)    #wraps模块
        def inner(*args,**kwargs):
            print('装饰前')
            ret = func(*args,**kwargs)
            print('装饰后')
            return ret
        return inner
    
    @outer
    def holiday(day):
        '''
    
        :param day: days of vacation
        :return:
        '''
        print("放假%s"%day)
        return '好开心'
    
    print(holiday.__name__)   #import wraps后此时打印holiday函数名,否则是 inner函数名
    print(holiday.__doc__)
    ret = holiday(3)
    print(ret)
    
    # 第二个,当装饰器带参数
    import time
    FLAG = False
    def out_timmer(flag):
        def timmer(func):
            def inner(*args,**kwargs):
                if flag:
                    start = time.time()
                    ret = func()
                    end = time.time()
                    print(start-end)
                    return ret
                else:
                    ret = func()
                    return ret
            return inner
        return timmer
    @out_timmer(FLAG)   #可以看成两部 1,  timmer = out_timmer(FLAG)     2,  @timmer
    def shop1():
        time.sleep(0.01)
        print('buy first thing')
    
    @out_timmer(FLAG)
    def shop2():
        time.sleep(0.01)
        print('buy second thing')
    
    shop1()
    shop2()
    
    
    #第三个    函数被多个装饰器调用
    def wrapper1(func):  #func-----> f
        def inner1():
            print('wrapper1,befor func')
            ret = func()
            print('wrapper1,after func')   #这一句运行完,但是inner2还没结束,要返回inner2继续运行【print('wrapper2,after func')】
            return ret
        return inner1
    
    def wrapper2(func):   #func-----> inner1  inner1传给了wrapper2
        def inner2():
            print('wrapper2,befor func')  #运行完这一句,下一句运行inner1,故返回到wrapper1继续运行
            ret = func()           #inner1
            print('wrapper2,after func')
            return ret
        return inner2
    
    @wrapper2          #wrapper1 执行完后,执行wrapper2   但是此时传入的不是f,是 inner1,相当于  wrapper(inner1)  == inner2 然后继续运行warpper2
    @wrapper1          #先执行到这里,因为语法糖要找离它最近的函数。wrapper2没找到,故往下运行。此时函数 f传给wrapper1   相当于  f = wrapper1(f)  即为 inner1
    def f():
        print('in the f')
    f()          #--------->>调用inner2
    View Code
  • 相关阅读:
    Python class static methods
    学习MySQL出现问题Not allowed to return a result set from a t
    MySQL创样例表(MySQL必知必会B.2)
    无重复字符的最长字串(C++,python实现)
    softmax详解
    为什么要使用logistic函数
    两个栈实现队列的插入和删除(C++实现)
    用数组实现队列(C++)
    C++ memset函数
    两数之和(C++实现)
  • 原文地址:https://www.cnblogs.com/gkx0731/p/9457050.html
Copyright © 2011-2022 走看看