python装饰器,迭代器,生成器

  • 什么是装饰器?

装饰器是装饰其它函数,为其它函数增加特定功能。在原来的函数上,增加一些限制或制约的条件,称为装饰器。

使用装饰器不会修改原函数的源码,也不会修改原函数的调用方式。

装饰器的基础知识有,函数也是变量,高阶函数,嵌套函数。

函数名和变量名一样只是一个变量的标识符,指向函数定义的内存地址。在函数定义中取调用其它函数时,不会立即调用调用该函数。

高阶函数的两个要求为,在函数形参中可以传递函数,函数的返回值包含函数名。

 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)
原文地址:https://www.cnblogs.com/feng1014/p/12635121.html