主要内容
- 装饰器的定义
- 装饰器的重要性
- 装饰器的原则
- 装饰器理解以及操作
装饰器的定义
本质是函数。(装饰其他函数) 它可以让其他函数在不需要做任何代码变动的前提下增加额外功能。
装饰器的重要性
比如:已经上线的生产环境上有100个函数,需要增加新功能,新增功能不能修改源代码,也不能修改原函数的,这个时候就用到了装饰器。
装饰器经常有切面需求的场景,比如:插入日志,性能测试,事务处理,缓存,权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。 概括的讲,装饰的作用就是为已经存在的对象添加额外的功能。
例子:
import timedef timmer(func): def warpper(*args,**kwargs): start_time = time.time() func() stop_time = time.time() print('the func run time os %s' %(stop_time-start_time)) return warpper() @timmer def test1(): time.sleep(3) print('in the test1') test1()
装饰器的原则
-
不能修改被装饰函数的源代码.
-
不能修改被装饰得函数的调用方式.
-
不修改返回结果.
装饰器都函数来说是透明的。
装饰器理解以及操作
函数即“变量”
def test(): pass
相当于将函数体赋值给test的变量。 变量直接调用变量名,函数是函数名调用 test='函数体' test()
例子1:
将foo()函数体放入房间,然后通过foo()这个门牌号调用函数体,函数体按顺序执行, 当执行到bar()时候,没有门牌号对应。
例子2:
def bar(): print('in the bar') def foo(): print('in the foo') bar() foo() ####### def foo(): print('in the foo') bar() def bar(): print('in the bar') foo()
上面两个时没有区别的,上面即可正常执行。 函数先定义后调用。调用之前已经解释器解释过了。就能调用成功。 将def bar() def foo()看成函数体。
高阶函数
-
把一个函数名当做实参转给另外一个函数 (在不修改被装饰函数源代码的情况下为其添加功能)。
-
返回值中包含函数名(不修改函数的调用方式)。
-
例子. 把一个函数名当做实参转给另外一个函数
bar 相当于门牌号,调用内存地址。
import timedef bar(): time.sleep(3) print('in the bar') def test1(func): start_time = time.time() func() #run bar stop_time = time.time() print('the func run time is %s' %(stop_time-start_time)) test1(bar) 运行结果: in the bar the func run time is 3.0036139488220215
相对于装饰器,调用方式被改变了,这要是在生产环境上功能上是不允许的。
- 返回值中包含函数名 例如:
import timedef bar(): time.sleep(3) print('in the bar') def test2(func): print(func) return func #print(test2(bar)) t=test2(bar) t() bar=test2(bar) bar() 运行结果:in the bar in the bar
没有改变调用方式。
嵌套函数
顾名思义就是函数里面套函数。 函数嵌套,在一个函数体内用def定义而不是调用另外一个函数。
例如:
def foo(): print('in the foo') def bar(): print('in the bar') bar() foo() 运行结果: in the foo in the bar
局部作用域和全局作用域
在函数外,一段代码最始开所赋值的变量,它可以被多个函数引用,这就是全局变量; 在函数内定义的变量名,只能被函数内部引用,不能在函数外引用这个变量名,这个变量的作用域就是局部的,也叫它为局部变量;
如果函数内的变量名与函数外的变量名相同,也不会发生冲突。好比下面这种情况:
x =0def grandpa(): x=1 def dad(): x=2 def son(): x=3 print(x) son() dad() grandpa() 运行结果为: 3
x = 0这个赋值语句所创建的变量X,作用域为全局变量; x = 3这个赋值语句所创建的变量X,它的作用域则为局部变量,只能在函数son()内使用。
x = 2这个赋值语句所创建的变量X,它的作用域则为局部变量,只能在函数dad()内使用。
x = 1这个赋值语句所创建的变量X,它的作用域则为局部变量,只能在函数grandpa()内使用。
尽管这两个变量名是相同的,但它的作用域为它们做了区分。作用域在某种程度上也可以起到防止程序中变量名冲突的作用,但如果做为玩蛇网python初学者来说,尽量避免这种情况发生比较好。
高阶函数+嵌套函数=》装饰器
简单装饰器例子
@语法糖
import timedef timer(func): #timer(test1) func=test1 def deco(): start_time = time.time() func() stop_time = time.time() print('the func run time %s' % (stop_time - start_time)) return deco @timer #timer(test1) func=test1 def test1(): time.sleep(3) print('in the test1') @timer def test2(): time.sleep(3) print('in the test2') #test1=timer(test1) #返回的是deco的内存地址 test1() #相当于运行test1 #test2=timer(test2) #返回的是deco的内存地址 test2() #相当于运行test2 运行结果: in the test1 the func run time 7.023896217346191 in the test2 the func run time 7.066271066665649
传参数的装饰器例子
import timedef timer(func): #timer(test1) func=test1 def deco(*args,**kwargs): start_time = time.time() func(*args,**kwargs) stop_time = time.time() print('the func run time %s' % (stop_time - start_time)) return deco @timer #test1= timer(test1) def test1(): time.sleep(3) print('in the test1') @timer #test2=timer(test2) = deco test2(name)=deco(name) def test2(name,age): print('test2', name,age) test1() test2('cathy',22) 运行结果: in the test1 the func run time 3.003638982772827 test2 cathy 22 the func run time 3.409385681152344e-05
用户验证场景装饰器
#!/usr/bin/env python# -*- coding:utf-8 -*-# Author:Cathy Wuuser,passwd='cathy','abc123' def auth(auth_type): print('auth fucn:',auth_type) def outer_warpper(func): def wrapper(*args, **kwargs): print('wrapper func args:',*args, **kwargs) if auth_type == 'local': username = input('username:').strip() password = input('password:').strip() if user == username and passwd == password: print('\033[32;1m User has passed authenticaiton\033[0m') res = func(*args, **kwargs) print('after authenticaiton') return res else: exit('\033[32;1m Invalid passwodr or username\033[0m') elif auth_type == 'ldap': print('ldap authenticaiton') return wrapper return outer_warpper def index(): print('welcome to the index') @auth(auth_type='local') def home(): print('welcome to the home') return "from home" @auth(auth_type='ldap') def bbs(): print('welcome to the bbs') index() print(home()) bbs() 运行结果: auth fucn: local auth fucn: ldap welcome to the index wrapper func args: username:cathy password:abc123 User has passed authenticaiton welcome to the home after authenticaiton from home wrapper func args: ldap authenticaiton