python装饰器
一 什么是装饰器
器指函数 装饰即修饰,意指为其他函数添加新功能 装饰器定义:本质就是函数,功能是为其他函数添加新功能
二 装饰器需要遵循的原则
1.不能修改被修饰函数的源代码 2.不能修改被修饰函数的调用方式
现在有下面一个函数,如果我们要为这个函数添加一个功能:测试程序的运行时间。
import time list=[1,2,3,4,5] def cal(list): for i in list: time.sleep(0.5) print(i) cal(list)
import time list=[1,2,3,4,5] def cal(list): start_time=time.time() for i in list: time.sleep(0.5) print(i) stop_time=time.time() print("运行时间:%s" %(stop_time-start_time)) cal(list)
1
2
3
4
5
运行时间:2.502134323120117
总结:我们虽然实现了功能,但是我们要知道两大原则,现在我们直接修改函数的源代码,这样做是不行的。
三 实现装饰器知识储备
装饰器=高阶函数+函数嵌套+闭包
四 高阶函数
高阶函数定义:
1.函数接收的参数是一个函数名
2.函数的返回值是一个函数名
3.满足上述条件任意一个,都可称之为高阶函数
def foo(): print('我的函数名作为参数传给高阶函数') def gao_jie1(func): print('我就是高阶函数1,我接收的参数名是%s' %func) func() def gao_jie2(func): print('我就是高阶函数2,我的返回值是%s' %func) return func gao_jie1(foo) gao_jie2(foo)
只满足一个条件:函数接收的参数是一个函数名
import time def foo(): print('from the foo') def timmer(func): start_time=time.time() func() stop_time=time.time() print('函数%s 运行时间是%s' %(func,stop_time-start_time)) timmer(foo) #总结:我们确实为函数foo增加了foo运行时间的功能,但是foo原来的执行方式是foo(),现在我们需要调用高阶函数timmer(foo),改变了函数的调用方式
满足两个条件
1.函数接收的参数是一个函数名
2.函数的返回值是一个函数名
import time def foo(): print('from the foo') def timmer(func): start_time=time.time() return func stop_time=time.time() print('函数%s 运行时间是%s' %(func,stop_time-start_time)) foo=timmer(foo) foo() #总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能
高阶函数总结
1.函数接收的参数是一个函数名
作用:在不修改函数源代码的前提下,为函数添加新功能,
不足:会改变函数的调用方式
2.函数的返回值是一个函数名
作用:不修改函数的调用方式
不足:不能添加新功能
五 函数嵌套
def father(name): print('from father %s' %name) def son(): print('from son') def grandson(): print('from grandson') grandson() son() father('aaa')
六 闭包
闭包: 就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁
闭包:闭包是指内部函数调用外部函数的变量
包是指嵌套,闭是指封装
def test1(): a=1 def test2(): print(a) test2() test1()
七 无参装饰器
无参装饰器=高级函数+函数嵌套
基本框架
1 #这就是一个实现一个装饰器最基本的架子 2 def timer(func): 3 def wrapper(): 4 func() 5 return wrapper
加上参数
解决被修饰的函数是有参数的。
1 def timer(func): 2 def wrapper(*args,**kwargs): 3 func(*args,**kwargs) 4 return wrapper
import time def timmer(func):#func=test def wrapper(name,age): start_time = time.time() res=func(name,age) # 就是在运行test() stop_time = time.time() print("函数运行时间的是%s" % (stop_time - start_time)) return res return wrapper # @timmer 等效于 test=timmer(test) @timmer def test(name,age): time.sleep(3) print('test函数运行完毕') return "这是test的返回值" res=test("lingling",20) print(res) @timmer # @timmer 等效于 test1=timmer(test1) def test1(name,age,gender): time.sleep(3) print('test函数运行完毕') return "这是test1的返回值" res=test1("lingling",20) print(res) #@timmer 等效于 test=timmer(test),#在这里一定要注意,我们首先把test函数传入到timmer装饰器,我们下一步返回了wrapper函数的地址(return wrapper)。 #test变量接收到wrapper函数的地址 #test("lingling",20)传入参数,执行wrapper函数,这里test函数有参数,为name,age,所以wrapper函数也应该有两个变量name,age,而执行wrapper函数,实际是要执行test函数,此处也需要两个参数,name,age #res变量接收到test函数执行的结果 # 1.将test函数传入timmer:timmer(test) # 2.执行timmer函数,返回wrapper函数地址(return wrapper) # 3.执行wrapper函数(执行wrapper函数实则是执行test函数),并接收test函数返回值:res=test("lingling",20)
import time def timmer(func):#func=test def wrapper(*wargs,**kwargs): start_time = time.time() res=func(*wargs,**kwargs) # 就是在运行test() stop_time = time.time() print("函数运行时间的是%s" % (stop_time - start_time)) return res return wrapper @timmer def test(name,age): time.sleep(3) print('test函数运行完毕') return "这是test的返回值" res=test("lingling",age=20) print(res) @timmer def test1(name,age,gender): time.sleep(3) print('test1函数运行完毕') return "这是test1的返回值" res=test1("lingling",20,'male') print(res) #解决wrapper不固定接收参数的问题 #如果细心可能会想,这里我们把wrapper参数写死了,你只能传入两个参数,如果有不同的函数需要这个装饰器,那我们不得重新修改装饰器,这真是一个大问题,我们来解决这个问题 #所以我们在wrapper函数中应该接收到test函数的所有参数:*wargs,**kwargs # *wargs:接收所有位置参数 # **kwargs:接收键值对类型的参数 #我们将wrapper函数与内部func函数的参数设置*wargs,**kwargs就可以接收所有传进来的参数 #第二个问题,func接收参数 # 使用*wargs,**kwargs怎么接收参数 # 就使用*wargs,**kwargs怎么传递参数 # 我们可以把*wargs,**kwargs看成一个整体,接收所有的参数
def test2(name,age,gender): #test2(*('alex',18,'male'),**{}) print(name) print(age) print(gender) def test1(*args,**kwargs): test2(*args,**kwargs) #args=('alex',18,'male') kwargs={} test1('alex',18,'male') def test3(*args,**kwargs): print(args) print(kwargs) # test3(1,2,3,4,name="linlin") test3(*(1,2,3,4),**{'name':'linlin'})
加上功能
在装饰器的框架基础上添加被测试函数所需要的功能。
import time def timer(func): def wrapper(*args,**kwargs): start_time=time.time() func(*args,**kwargs) stop_time=time.time() print('函数[%s],运行时间是[%s]' %(func,stop_time-start_time)) return wrapper
import time def timmer(func):#func=test def wrapper(): start_time = time.time() func() # 就是在运行test() stop_time = time.time() print("函数运行时间的是%s" % (stop_time - start_time)) return wrapper # @timmer 等效于 test=timmer(test) @timmer def test(): time.sleep(3) print('test函数运行完毕') test()
import time def timmer(func):#func=test def wrapper(): start_time = time.time() func() # 就是在运行test() stop_time = time.time() print("函数运行时间的是%s" % (stop_time - start_time)) return wrapper def test(): time.sleep(3) print('test函数运行完毕') test=timmer(test)#返回的是wrapper的地址 test()#执行的是wrapper()
加上返回值
解决在测试程序里有返回值的情况。
import time def timer(func): def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('函数[%s],运行时间是[%s]' %(func,stop_time-start_time)) return res return wrapper
import time def timmer(func):#func=test def wrapper(): start_time = time.time() res=func() # 就是在运行test() stop_time = time.time() print("函数运行时间的是%s" % (stop_time - start_time)) return res return wrapper # @timmer 等效于 test=timmer(test) @timmer def test(): time.sleep(3) print('test函数运行完毕') return "这是test的返回值" res=test() print(res)
语法糖@
如果我们需要使用装饰器,只需要在被测试的函数前加上@装饰器函数名
@timmer 等效于 test=timmer(test)
@timer #@timer就等同于cal=timer(cal) def cal(array): res=0 for i in array: res+=i return res cal(range(10))
补充
a,b,c=(1,2,3) print(a) print(b) print(c) a,b,c='hel' print(a) print(b) print(c) #如果我们不使用索引,如何去列表的第一个值与最后一个值 list=[10,4,2,7,2,8,3,8,3,6] a,*d,c=list#这里*代表中间所有的值,*后面的代表为一个变量d接收中间的所有值 print(a) print(c) print(d) #使用索引取第一个和最后一个值 a,c=list[0],list[-1] print(a) print(c) #在python中交换两个值 f1=1 f2=2 f1,f2=f2,f1 print(f1,f2)
装饰器应用示例
user_list=[ {'name':'alex','passwd':'123'}, {'name':'linhaifeng','passwd':'123'}, {'name':'wupeiqi','passwd':'123'}, {'name':'yuanhao','passwd':'123'}, ] current_user={'username':None,'login':False} def auth_deco(func): def wrapper(*args,**kwargs): if current_user['username'] and current_user['login']: res=func(*args,**kwargs) return res username=input('用户名: ').strip() passwd=input('密码: ').strip() for index,user_dic in enumerate(user_list): if username == user_dic['name'] and passwd == user_dic['passwd']: current_user['username']=username current_user['login']=True res=func(*args,**kwargs) return res break else: print('用户名或者密码错误,重新登录') return wrapper @auth_deco def index(): print('欢迎来到主页面') @auth_deco def home(): print('这里是你家') def shopping_car(): print('查看购物车啊亲') def order(): print('查看订单啊亲') print(user_list) # index() print(user_list) home() 无参装饰器
user_list=[ {'name':'alex','passwd':'123'}, {'name':'linhaifeng','passwd':'123'}, {'name':'wupeiqi','passwd':'123'}, {'name':'yuanhao','passwd':'123'}, ] current_user={'username':None,'login':False} def auth(auth_type='file'): def auth_deco(func): def wrapper(*args,**kwargs): if auth_type == 'file': if current_user['username'] and current_user['login']: res=func(*args,**kwargs) return res username=input('用户名: ').strip() passwd=input('密码: ').strip() for index,user_dic in enumerate(user_list): if username == user_dic['name'] and passwd == user_dic['passwd']: current_user['username']=username current_user['login']=True res=func(*args,**kwargs) return res break else: print('用户名或者密码错误,重新登录') elif auth_type == 'ldap': print('巴拉巴拉小魔仙') res=func(*args,**kwargs) return res return wrapper return auth_deco #auth(auth_type='file')就是在运行一个函数,然后返回auth_deco,所以@auth(auth_type='file') #就相当于@auth_deco,只不过现在,我们的auth_deco作为一个闭包的应用,外层的包auth给它留了一个auth_type='file'参数 @auth(auth_type='ldap') def index(): print('欢迎来到主页面') @auth(auth_type='ldap') def home(): print('这里是你家') def shopping_car(): print('查看购物车啊亲') def order(): print('查看订单啊亲') # print(user_list) index() # print(user_list) home() 带参装饰器
import sys,threading,time class KThread(threading.Thread): """A subclass of threading.Thread, with a kill() method. Come from: Kill a thread in Python: http://mail.python.org/pipermail/python-list/2004-May/260937.html """ def __init__(self, *args, **kwargs): threading.Thread.__init__(self, *args, **kwargs) self.killed = False def start(self): """Start the thread.""" self.__run_backup = self.run self.run = self.__run # Force the Thread to install our trace. threading.Thread.start(self) def __run(self): """Hacked run function, which installs the trace.""" sys.settrace(self.globaltrace) self.__run_backup() self.run = self.__run_backup def globaltrace(self, frame, why, arg): if why == 'call': return self.localtrace else: return None def localtrace(self, frame, why, arg): if self.killed: if why == 'line': raise SystemExit() return self.localtrace def kill(self): self.killed = True class Timeout(Exception): """function run timeout""" def timeout(seconds): """超时装饰器,指定超时时间 若被装饰的方法在指定的时间内未返回,则抛出Timeout异常""" def timeout_decorator(func): """真正的装饰器""" def _new_func(oldfunc, result, oldfunc_args, oldfunc_kwargs): result.append(oldfunc(*oldfunc_args, **oldfunc_kwargs)) def _(*args, **kwargs): result = [] new_kwargs = { # create new args for _new_func, because we want to get the func return val to result list 'oldfunc': func, 'result': result, 'oldfunc_args': args, 'oldfunc_kwargs': kwargs } thd = KThread(target=_new_func, args=(), kwargs=new_kwargs) thd.start() thd.join(seconds) alive = thd.isAlive() thd.kill() # kill the child thread if alive: raise Timeout(u'function run too long, timeout %d seconds.' % seconds) else: return result[0] _.__name__ = func.__name__ _.__doc__ = func.__doc__ return _ return timeout_decorator @timeout(5) def method_timeout(seconds, text): print('start', seconds, text) time.sleep(seconds) print('finish', seconds, text) return seconds method_timeout(6,'asdfasdfasdfas')
博文:https://www.cnblogs.com/linhaifeng/articles/6140395.html