python 装饰器 学习

1、装饰器的介绍

#usr bin python  17:40
# coding=utf-8
'''装饰器本质是函数(装饰其他函数)
为其他函数添加附加功能
原则:不修改原函数代码,及调用方式
'''

#例子一
# 2、对foo()函数装饰  #附加日志打印功能
def add_to_foo(fun):
    print('This is a decorator')
    return  fun

# 3、运行foo()函数,先调用装饰器函数
@add_to_foo  #装饰器函数要写在原函数前面,再原函数上方@装饰器函数,最后调用原函数才行。
def foo():  # 1、原函数 无参
    print('I am %s running'%foo.__name__)
#foo()



#例子二
import  time
#2.现在写装饰器

def timmer2(func):
    def warpoer(*args,**kwargs):
        start_time=time.time()
        func()
        stop_time=time.time()
        print('the func run %s s'%(stop_time-start_time))
#       return  warpoer  这样写不会
    return warpoer #最外层函数要有返回值


'''这个情况,完全按装饰器的函数体跑完,就收工。
i am in test1
the func run 3.0000102519989014 s
'''
def timmer1(fun):
    start_time = time.time()
    fun()
    stop_time = time.time()
    print('the func run %s s' % (stop_time - start_time))
    return  fun

'''??????????????????????????????????这个情况,执行了装饰器函数,并再次单独调用了原函数
i am in test1
the func run 3.000021457672119 s
i am in test1
'''
'''
#3.再调用装饰器函数
#1.先写函数
@ timmer1
def test():
    time.sleep(3)
    print('i am in test1')
test() #4.调用原函数
'''

'''
实现装饰器知识储备:
1.函数即‘变量’  √
2.高阶函数
3.嵌套函数

高阶函数+嵌套函数=》装饰器 
'''

2、函数 即 变量

#场景1 先申请函数,再调用函数,能正常运行
def bar():
    print('i am bar')
def foo():
    print('i am foo')
    bar()
#foo()


#场景2 先调用函数,后申请函数,也能正常运行
def foo():
    print('i am foo')
    bar()
def bar():
    print('i am bar')
#foo()


#场景3 先执行函数,后申明函数,要报错
def foo():
    print('i am foo')
    bar()  # name 'bar' is not defined
#foo()
def bar():
    print('i am bar')
'''

'''
''' 上面三个场景,解答如下:
Python是解释语言,即场景1和2中,先后定义了函数,给函数指向了对应内存地址,所以 执行foo()时,函数bar均已申明、存在,顾效果是一样的
'''

 3、Python内存回收机制

* 变量x=1   内存【1】对应门牌号是x ,当x=2时, 内存【1】无对应门牌号,这时在定期清理内存空间时,将被回收;

* 变量x=1  整个程序运行中,x=1,那么得到程序结束,才会释放内存【1】。

4、高阶函数和嵌套函数 

#####高阶函数######################################################################
#1、把一个函数名已实参传给一个参数(在不修改原函数代码的情况,可为其添加功能)
#2、返回值中包含函数名(不修改调用方式)

# 1、函数名作为实参
def foo(func): #计算实参函数的运行时长
    print(func) #打印函数的门牌号
    start_time = time.time()
    func()
    stop_time = time.time()
    print('the func run %s s' % (stop_time - start_time))
def bar():
    pass
#foo(bar)
#打印结果  <function bar at 0x00000000006F3A60>

# 2、返回值中包含函数名
def test(func):
    print(func)
    return func
def bar():
    pass
#test(bar) #运行结果 <function bar at 0x0000000000A63B70>
#print('函数返回值包含了函数,打印返回值',test(bar))
'''
<function bar at 0x0000000000743B70>
函数返回值包含了函数,打印返回值 <function bar at 0x0000000000743B70>
'''
# bar=test(bar)  #让bar重新指向 装饰过的函数体, 且调用方式保持不变;Python中对于这类装饰函数的调用有专门的符号@

#嵌套函数
def foo():
    print('in the foo')
    def bar():       #这是定义了一个局部‘变量’ 要想使用它,只能在函数内部使用, 或许可以通过return bar这个函数地址,在函数外访问
        print('in the bar')

    bar()
#foo() #运行结果 in the foo  \n  in the bar

#这样似乎就能看出 高阶函数+嵌套函数, 在装饰器的应用了。
# 1、要装饰old()函数,可能修改重新定义一个局部函数,
# 2、在局部函数中,调用old()函数,也新增功能
# 3、再return局部函数的地址 ,且old=》指向这个地址

 

5、装饰器的应用

#函数的嵌套是在函数体内,再申明一个函数(而在函数体外申明的函数,再被其他函数体调用,这种不算嵌套)
# 说明:作用域是从里往外,一层一层的找,如下例子
x=1
def bar():
    x=2
    def foo():
        x=3
        def test():
            x=5
            print('x=',x)
        test()
    foo()
#bar()  #运行结果 x= 5
###装饰器的应用1
import  time
def foo(func):
    def deco():
        start_time=time.time()
        func()
        end_time=time.time()
        print('the func run time:',end_time-start_time)
    return deco
#只需要在函数定义的位置,加上装饰器调用的代码
@foo #等同于 bar=foo(bar) 将装饰器的嵌套函数地址重新赋值给原函数  实现了目标【不修改原函数代码和调用方式,同时附加功能】
def bar():
    time.sleep(3)
#bar()  #运行结果:已实现装饰功能+原功能

#装饰器的应用2 原函数带参数
def foo(func):
    def deco():
        start_time = time.time()
        func()
        end_time = time.time()
        print('the func run time:', end_time - start_time)
    return  deco

@foo
def test2(name):
    print('test2:',name)
#test2('blog') #deco('blog')运行结果deco() takes 0 positional arguments but 1 was given(因deco定义时不带参数)
#【改进】 ,装饰时,局部函数使用非固定参数
def foo(func):
    def deco(*args,**kwargs):          #加上不固定参数
        start_time = time.time()
        func(*args,**kwargs)            #加上不固定参数
        end_time = time.time()
        print('the func run time:', end_time - start_time)
    return  deco
@foo
def test2(name):
    print('test2:',name)
@foo
def test1():
    print('in test1')
#test2('blog')
#test1()
#运行结果正确

'''
非固定参数的作用:可以传不固定个数的参数进去,为以后的扩展准备。
在函数中,加了名字的非固定函数输出是会显示为字典形式,没有加名字的非固定函数输出时会显示为元组形式。
 #*args 会把多传入的参数变成一个元组形式显示;**kwargs 会把多传入的参数变成一个字典的形式显示
 '''
def sud(name,age,*args,**kwargs):
    print(name,age,args,kwargs)
#sud("zhangsan",20,"beijing","shanghai",year="2018",date="1210")

'''执行结果:
('zhangsan', 20, ('beijing', 'shanghai'), {'date': '0102', 'year': '2018'})
'''
### 装饰器又叫语法糖
#上述例子中,原函数均未设置return值,若有return值时,看下
def foo(func):
    def deco(*args,**kwargs):          #加上不固定参数
        start_time = time.time()
        func(*args,**kwargs)            #加上不固定参数
        end_time = time.time()
        print('the func run time:', end_time - start_time)
    return  deco
@foo
def test2(name):
    time.sleep(3)
    print('test2:',name)
    return 'from test2……'
#print(test2('python 12010'))
''' 运行结果如下:#可以看到return值没有返回
test2: python 12010
the func run time: 3.0001633167266846
None
'''
#【改进,在装饰器中,调用fun()后,在装饰器中return它的结果
def foo(func):
    def deco(*args,**kwargs):
        start_time = time.time()
        res=func(*args,**kwargs)
        end_time = time.time()
        print('the func run time:', end_time - start_time)
        return  res #在嵌套函数末尾增加原函数的返回值
    return  deco
@foo
def test2(name):
    time.sleep(3)
    print('test2:',name)
    return 'from test2……'
print(test2('python 1215'))
'''#这样能使用原函数return
test2: python 1215
the func run time: 3.000087022781372
from test2……
'''

 #上面的例子中,装饰器都不带参数,下面是装饰器带参数的例子:

 

#4、在外层再嵌套,用来传参数,实现:按不同方式认证后决定调用哪个分支。例子也许不贴切,但能帮助理解
username,password='wlwei','123456'
def outer(auth_type):

    def foo(func):
        def deco(*args, **kwargs):               ##开始
            if auth_type=='index':
                print('这是index 分支')
                user = input('请输入你的姓名:')
                pwd = input('请输入你的密码:')
                if user == username and pwd == password:
                    print('验证通过')
                    res = func(*args, **kwargs)
                    return res
                else:
                    print('验证失败')
            elif auth_type == 'home':
                print('这是home 分支')
        return deco                               ##结束,从开始-到结束这里,就是原不参的装饰器写法,带参时,直接再套一层


    return  foo


@outer(auth_type='index')      ##待学习,使用装饰器的参数时,先判断参数类型,再使用。
def index_page():
    print('welcom to index page')
@outer(auth_type='home')
def home_page():
    print('welcom to home page')

#index_page()  #运行结果正常

 

posted @ 2018-12-07 18:47  幸福在今天  阅读(244)  评论(0)    收藏  举报