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() #运行结果正常
-----------------------------------------Have a good day!---------------------------------------------------------------------------------------------------

浙公网安备 33010602011771号