Python-迭代协议-__iter__ __next__ iter next yield

iter

  本质是for循环调用的实质,for循环通过调用这个函数返回可迭代对象生成器形式,开始迭代取值捕获StopIteration错误退出循环

  for循环首先找__iter__方法,然后再找 __getitem__方法,如果都没找到则报错,对象不是可迭代对象

 

__iter__

  如果是自定义类生成的对象则iter方法调用__iter__函数, 这个函数必须返回迭代器对象

 

next

  启动生成器。并获取生成器第一个值

 

__next__

  将对象变成生成器对象,也是 next方法调用对象中__next__方法

from random import randint


class BeiMenChuiXue:
    """自己实现的迭代器"""
    def __init__(self, iterable):
        self.iterable = iterable

    def __next__(self):
        for member in self.iterable:
            yield member


class DuGuJiuJiu:
    """可迭代对象"""
    def __init__(self, numbers):
        self.numbers = numbers

    def __iter__(self):
        # 通过全局函数 iter实现
        # return iter(self.numbers)

        # 交给自己实现的迭代器
        return next(BeiMenChuiXue(self.numbers))


if __name__ == '__main__':
    numbers = [randint(-10, 10) for _ in range(10)]
    print(numbers)
    du_gu_jiu_jiu = DuGuJiuJiu(numbers)
    for member in du_gu_jiu_jiu:
        print(member)

  

 北门吹雪: https://www.cnblogs.com/2bjiujiu/

 

yield

  yield可以跳出函数并传出一个值,也可以传递进去一个值被函数内部收到并接着执行函数,类似函数与函数之间形成通信并且可以暂停并启动函数的特性,是协程实现的最底层原理

def bei_men_chui_xue():
    hai = yield "我是 bei_men_chui_xue 函数"
    print(hai)


if __name__ == '__main__':
    bei = bei_men_chui_xue()
    message = bei.send(None)
    print(message)
    try:
        bei.send("我是 main 函数")
    except StopIteration as e:
        pass

  

经验:

  1. for循环迭代的本质还是生成器对象,然后捕获StopIteration自动退出循环

  2. 协程实现的底层原理是yield特性,既可以暂停函数并传出一个值也可以接收一个值重新启动函数的特性最具有Python语言风格

  3. 迭代结束会自动触发StopIteration,这个异常是结束信号,需要捕获这个异常

 

bei_men_chui_xue: https://www.cnblogs.com/2bjiujiu/

 

通过yield读取大文件思路:

  1. 打开文件获得句柄 open

  2. 通过read方法读取指定偏移量数据

  3. 定义一个读生成器,传递文件句柄和读取偏移量

  4. 定义一个buf,循环判断分隔符是否在buf中,取出分隔符前面的字符(通过切片),yield出去,更新buf分隔符后面的字符

  5. 如果没有找到分隔符,则read数据,判断是否读取完毕,读取完毕退出,有数据则拼接到buf中

def read_big_file(filename, read_size=20, sep='\n'):
    """读取大文件"""
    f = open(filename, 'r', encoding='utf-8')
    buf = ''
    sep_len = len(sep)
    while True:
        # 第一层取数据
        data = f.read(read_size)
        # 判断文件是否读完
        if data is None:
            raise StopIteration
        buf += data
        while True:
            # 第二层生成数据
            if sep in buf:
                index = buf.index(sep)
                yield buf[:index]
                buf = buf[index + sep_len:]
            else:
                break


if __name__ == '__main__':
    file_name = "python_this.txt"
    read_generator = read_big_file(filename=file_name)
    oneline = next(read_generator)
    twoline = next(read_generator)
    threeline = next(read_generator)
    print(oneline, end='')
    print(twoline, end='')
    print(threeline, end='')

  

 

posted @ 2018-06-06 10:20  梦_鱼  阅读(1095)  评论(0编辑  收藏  举报