装饰器:(语法糖)

本质是函数,它是赋予函数新功能,但是不改变函数的源代码及调用方式
 
原则:
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('\033[32;1mwelcome\033[0m')
12                     res = func(*args,**kwargs)
13                     print("after decorator")
14                     return res
15                 else:
16                     print('\033[31;1mwrong info\033[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

 

 

 

 

 

 

 

 

posted on 2018-08-10 19:45  阿橙  阅读(229)  评论(0编辑  收藏  举报