- 什么是装饰器?
装饰器是装饰其它函数,为其它函数增加特定功能。在原来的函数上,增加一些限制或制约的条件,称为装饰器。
使用装饰器不会修改原函数的源码,也不会修改原函数的调用方式。
装饰器的基础知识有,函数也是变量,高阶函数,嵌套函数。
函数名和变量名一样只是一个变量的标识符,指向函数定义的内存地址。在函数定义中取调用其它函数时,不会立即调用调用该函数。
高阶函数的两个要求为,在函数形参中可以传递函数,函数的返回值包含函数名。
1 import time 2 def timer(func): #定义装饰器函数 3 def gcf(): #定义一个嵌套函数 4 start_time=time.time() 5 func() #调用作为参数传入的函数名 6 end_time=time.time() 7 print('程序运行时间',end_time-start_time) 8 return gcf #返回嵌套函数的函数名 9 @timer 10 def foo(): #定义被装饰函数 11 time.sleep(1) 12 print('in foo') 13 foo() 14 #执行过程 15 #到达第二行,装饰器函数的定义,把装饰器函数整体加载到CPU 16 #到达第九行,语句的执行过程实际是foo=timer(foo),所以执行timer函数 17 #回到第三行,把嵌套函数gcf整体加载到CPU 18 #执行到第八行,返回一个嵌套函数名给装饰器函数timer,也即返回函数名给foo 19 #到达第十四行,执行返回的foo函数,又回到第三行,执行foo函数体 20 #到达第五行,执行func函数,转到第十行 21 #执行了func函数后,依次执行程序,直到结束程序
当被装饰函数中有参数时,参数传递过程遵循一定的规则。被装饰函数中有一个参数,使用以下方式。
import time def timer(func): #定义高阶函数,参数传递foo,装饰foo def gf(name): #定义嵌套函数,装饰foo start_time=time.time() func(name) #执行被装饰函数 end_time=time.time() print('程序运行时间',end_time-start_time) return gf #在高阶函数中返回嵌套函数 @timer def foo(name): #被装饰函数中有参数 time.sleep(1) print('in foo',name) foo('woniu')
被装饰函数有多个参数时,需要使用不定义参数传参
import time def timer(func): def gf(*args,**kwargs): start_time = time.time() func(*args,**kwargs) end_time = time.time() print('程序运行时间为',end_time-start_time) return gf @timer def foo(name,age): time.sleep(1) print('in foo',name,age) foo('woniu',24)
在装饰函数中传递参数,需要使用以下的规则
import time def timer(timer_type): #定义高阶函数作为装饰器,带有参数 def outter(func): #定义嵌套函数,参数为被装饰函数 def inner(*args,**kwargs): #定义嵌套函数,参数为被装饰函数的参数 start_time=time.time() func(*args,**kwargs) #调用被装饰函数 end_time=time.time() return inner #返回内层嵌套函数 return outter #返回外层嵌套函数 @timer(timer_type='min') def foo(name,args): #定义被装饰函数 time.sleep(1) print('in foo',name,age) foo('woniu',24)
被装饰函数有返回值,遵循如下规则
import timer def timer(timer_type): #定义高阶函数为装饰器函数,带有参数 def outter(func): #定义嵌套函数,参数为被装饰函数 def inner(*args,**kwargs) #定义嵌套函数,被装饰函数有参数 start_time = time.time() res = func(*args,**kwargs) end_time = time.time() print('程序运行时间为',end_time-start_time) return res #返回被装饰函数的返回值 return inner #返回内层嵌套函数 return outter #返回外层嵌套函数 @timer(timer_type='min') def foo(name,age): #定义被装饰函数,有返回值,有多个参数 time.sleep(1) print('in foo',name,age) return name print(foo('woniu',24)) #输出被装饰函数的返回值
- 迭代器
在Python的任意对象中,定义了返回一个迭代器的__iter__方法,或定义了支持下表索引的__getitem__方法,就称为可迭代对象。
#判断可迭代对象的两种方式 form collections import Iterable print(isinstance([],Iterable)) #使用isinstance方法判断 print(hasattr([],'__getitem__')) #使用是否具有方法__getitem__判断 class emp(): #定义对象 def __init__(self,employee): self.employee=employee def __getitem__(self,item): #定义方法,表示是一个可迭代对象 return self.employee[item] #返回一个类中的属性 emp=emp(['张三','李四','王五']) for i in emp: #emp对象增加了__getitem__对象后,变成了可迭代对象 print(i)
迭代器就是包括一个__iter__方法来返回迭代器本身,__next__方法返回迭代器的下一个值。
有了可迭代对象,为什么还需要迭代器?这是因为迭代器是一个工厂模式,是懒加载。预先不需要指定迭代器的大小,是根据需要动态的加载空间。所以也就没有长度属性。
from itertools import count from collections import iterator counter=count(start=10) #定义了一个迭代器对象 for i in range(10): #只需要指定循环次数,就可以随机生成迭代器 print(next(counter)) #每次循环都输出下一个迭代器值 print(isinstance(counter,iterator)) #判断是否迭代器 a=[1,2,3,4,5,6] #列表为可迭代对象 a_iter=iter(a) #列表强制转为迭代器 for item in a_iter: #对迭代器进行迭代 print(item) #迭代器对象进行迭代后,不能再次迭代。可迭代对象迭代后,依然可以迭代。
- 生成器
生成器是一个特殊的迭代器,不需要写__next__方法,__iter__方法,只需要在函数内部写一个yield关键字即可。
使用yield关键字,可以返回一个值。也可以保留函数的运行状态,等待下次函数的执行,函数下次执行是从yield语句后开始执行。
def demo(): #定义生成器 print('hello') yield 5 print('world') c=demo() #只是生成生成器对象,不运行 print(next(c)) #调用生成器,输出hello,由于yield返回5,再输出5 next(c) #在此输出world,程序从上次yield语句后开始执行
生成器的两种调用方法。next方法,send方法。
send方法也能够调用生成器,同时还会传递一个数据到生成器内部。
生成器的两种预激活机制。使用next方法,使用c.send(None)方法传递一个空值到生成器内部。
- 协程
协程是一种微线程,是一种用户级的轻量级线程。在同一个线程中,不同子程序可以中断转去执行其它程序,在执行结束后,又回来继续执行中断前的程序。这种任务调度的模式称为协程。协程拥有自己的上下文,寄存器和栈。
def consume(): #定义消费者 r='' while True: n=yield r #出现yield关键字,表示是一个生成器 print('[consumer] consuming %s' %n) r='200 OK' def produce(c): #定义生产者 c.send(None) #启动消费者 n=0 while n<5: n=n+1 print('[producer] produceing %s' %n) r=c.send(n) print('[producer] consumer return %s' %n)
c=consume()
produce(c)
执行过程
使用协程可以降低系统的开销,不想创建线程那样创建协程。也不必使用锁的机制来控制不同线程之间的运行。因为协程本来就是在一个线程之中运行。
import asyncio from collections.abc import Generator,Coroutine @asyncio.coroutine #使用装饰器来定义协程 def hello(): #定义测试函数 pass async def hello(): #使用async关键字来定义协程 pass h=hello() print(isinstance(h,Generator)) #测试是否生成器 print(isinstance(h,Coroutine)) #测试是否协程 #使用装饰器方法定义协程属于一个生成器, #使用原生协程定义方法定义协程就属于一个协程
使用asyncio框架来执行协程
import asyncio async def hello(name): #定义协程函数 print('hello',name) h=hello('woniu') #定义协程对象 loop=asyncio.get_event_loop() #定义事件循环对象容器 task=loop.create_task(h) #将协程对象转为task task=asyncio.ensure_future(h) #将协程对象转为task的另一种方法 loop.run_until_complete(task) #将task放到事件循环对象容器中运行
由于协程使用在异步I/O中,在协程中需要回调函数,来返回某个协程被中断后执行操作的结果。
import asyncio async def hello(x): #定义协程函数 await asyncio.sleep(x) #异步操作,休眠当前协程 return x #在协程休眠后,执行操作,返回操作的结果 h=hello(2) #定义协程对象 loop=asyncio.get_event_loop() #定义事件循环对象容器 task=asyncio.ensure_future(h) #将协程对象转为task loop.run_until_complete(task) #事件循环对象执行task print('返回结果:{}'.format(task.result())) #协程休眠后,执行的操作结果保存在task.result()方法中 #上述方法仅适用在返回操作结果。如果要对返回结果进行操作,再返回就需要使用函数 async def hello(x): #定义协程函数 await asyncio.sleep(x) #异步操作,休眠当前协程 return x #协程休眠结束,返回中断操作执行的结果 def callback(future): #定义回调函数 sum=10+future.result() #不经过任何操作的返回结果存放在future.result()方法中 print('返回结果:',sum) h=hello(2) loop=asyncio.get_event_loop() #创建事件循环对象容器 task=asyncio.ensure_future(h) #将协程对象转为task task.add_done_callback(callback) #将回调函数添加到task中 loop.run_until_complete(task) #事件循环对象容器中执行task
使用协程并发操作,使用更少的资源完成大的运行任务。
import asyncio import time def hello(x): #定义协程函数 print('等待:',x) await asyncio.sleep(x) #协程休眠 return '等待了{}'.format(x) if __name__=='__main__': start=time.time() h1=hello(1) #定义多个协程对象 h2=hello(2) h3=hello(3) tasks=[ #将协程对象转task放到列表中 asyncio.ensure_future(h1), asyncio.ensure_future(h2), asyncio.ensure_future(h3) ] loop=asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) #使用 asyncio.wait()方法运行多个task for task in tasks: print('任务返回结果:',task.result()) print('程序运行时间是',time.time()-start)
使用协程和多线程生成多数文件比较两者之间的性能
import asyncio import time async def write(path,x): #定义协程执行体,生成文件 with open(path,'w') as f: f.write('this is file %s' %x) if __name__=='__main__': start=time.time() #设置标记开始时间 loop=asyncio.get_event_loop() #创建事件循环对象容器 tasks=[] for i in range(10000): #创建一万个文件 tasks.append(write('/Users/tone/Desktop/h/'+str(i)+'.txt',i)) loop.run_until_complete(asyncio.wait(tasks)) #运行多个协程 print('程序的执行时间:',time.time()-start) #上述方法使用协程创建一万个文件 #以下方法使用多线程创建一万个文件 import threading import time def write(path,x): #定义线程函数 with open(path,'w') s f: f.write('this is fiile %s' %x) if __name__=='__main__': start=time.time() therads=[] for i in range(10000): #创建一万个文件 t=threading.Thread(target=write,args=('/Users/tone/Desktop/h/'+str(i)+'.txt'',i)) threads.append(t) t.start() [t.join() for t in threads] print('程序的执行时间:',time.time()-start)