迭代器与生成器

一、迭代器 Iterator

 
1、可迭代对象:str、list、tuple、set、dict、文件句柄,range
                        __iter__() 这个方法导致了数据类型的可迭代
检测一个对象是否可迭代:
from collections import Iterable
print(isinstance('aaa',Iterable))
print(isinstance(123,Iterable))
输出 True  False

2、可迭代协议:只要包含了__iter__()方法的数据类型就是可迭代的

                        这是数据类型和python解释器定下来的协议
dir(对象),可以查看此类型的对象所有的方法
print(dir((1,3))
输出:列表
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']
 

 

3、迭代器 iterator
  就是实现了能从其中一个一个的取出值来
  迭代器 不关心值的索引状态  (所以for循环才能循环字典,集合等)
        for循环,在遍历之前,先调用对象的__iter__方法,将其转换成1个迭代器,然后用迭代器协议去实现循环访问
lst_iterator = [1,2,3].__iter__()       #lst_iterator 就是一个迭代器(通过可迭代对象,用__iter__()方法,获得)
print(lst_iterator)
输出
<list_iterator object at 0x00000203948C8710>  

    #天生就是迭代器的:比如文件句柄

    #后天生成迭代器的:比如 可迭代对象.__iter__() 
 
 
列表的迭代器跟 列表比起来,有哪些新的方法:
print(set(dir(lst_iterator))-set(dir([1,2,3])))
输出:
{'__next__',                       #一个一个取值
 '__length_hint__',                #获取迭代器中元素的长度
 '__setstate__'}                     #根据索引值指定从哪里开始迭代
 
4、迭代器协议:
迭代器中拥有__next__ 和 __iter__ 方法
 
检测是否是迭代器:
from collections import Iterator
lst_iterator = [1,2,3].__iter__()  
print(isinstance(lst_iterator,Iterator))
print(isinstance([1,2,3],Iterator))
输出True  False

在python中,学过的所有可以被for循环的 基本数据类型 都是可迭代的,而不是迭代器

文件句柄是 迭代器
range是可迭代对象,但不是迭代器,包含__iter__,没有__next__
for 可以是一个可迭代对象,也可以是一个迭代器
 
迭代器和可迭代对象之间的关系:
    #迭代器包含可迭代对象,
    #迭代器 = 可迭代对象.__iter__()
 
5、迭代器存在的本质是什么:
    #1、能够对python中的基本数据类型进行统一的遍历,不需要关心每一个值分别是什么
    #2、可以节省内存    ——惰性运算
  
用__next__实现一个for循环
lst_iterator = [1,2,3].__iter__()
while True:
    try:
        print(lst_iterator.__next__())
    except StopIteration:                  ##接收到异常错误,就怎么怎么样
        break
输出:1  2  3

二、生成器 Generator

 
1、生成器
    是自己写出来的,就是迭代器
        # 生成器函数
              yield / yield from
              yield语句,一次返回一个结果,在每个结果中间,挂起函数状态,以便下次从它离开的地方继续执行。
def generator_func():          ###生成器函数
    print(123)
    yield 'aaa'
    print(465)
    yield 'bbb'
g = generator_func()          ###生成一个迭代器g
print(g)       输出:<generator object generator_func at 0x00000226D0EC0EB8>
print(g.__next__())          输出:123 aaa
print(g.__next__())          输出:456 bbb

#带yield关键字的函数,就是生成器函数

#生成器函数,在调用的时候,只返回一个生成器,不执行生成器函数中的内容
 
2、从生成器中取值:
    #1、__next__  有几个yield 就可以取几次
    #2、for  循环取值,正常取  for i in g:
    #3、其他数据类型强制转换, list (g)  返回1个列表,里面包含生成器的所有内容
            #注意:调用生成器函数时,要先获取生成器,再进行next取值
                        生成器中的内容,只能取一个,且按顺序取值,没有回头路,取完为止
 
3、举例
def generator_func():
    yield 123
    yield 456

def get_clothing():
    for cloth in range(1,500):
        yield "第%s件衣服" % cloth
g = get_clothing()
for i in range(50):              #一下取出50件衣服(通过设定执行多少次yield来进行)
    print(g.__next__())         
for i in g:                          #取出前多少件衣服 (通过判断yield出来的值,来判断是否继续进行)
    print(i)
    if i =="第100件衣服":
        break

def func1()
    for i in [1,2,3,]:
        yield i
    for j in 'ABC':
        yield j
 
def func2()
    yield from [1,2,3]       ##只有python3里有 yield from
    yield from 'ABC'

4、对文件输入的监控

import time
def  tail():
    with open('tmp') as f:
        f.seek(0,2)                 #光标移动到最后
        while True:
            line = f.readline()
            if not line:
                time.sleep(0.5)
                continue
            yield line
g = tail()
for i in g:
    print(i,end="")

5、生成器预激装饰器

def func(func):
    def inner(*args,**kwargs):
        g = func(*args,**kwargs)
        g.__next___()
        return g
    return inner

 

posted @ 2017-09-04 19:27  唐宋元明卿  阅读(102)  评论(0编辑  收藏  举报