python迭代器和生成器的区别解析

Written by

in

文章目录
  • 目录
    • 1.迭代器
      • 1.1 可迭代对象
      • 1.2 迭代器
      • 1.3 可迭代对象和迭代器的区别
    • 2.生成器
      • 2.1 概念
      • 2.2 yield from

            可迭代对象指的是 实现了__iter__方法的对象,可以被for循环遍历的容器,比如一个列表,自定义的链表等。使用 iter() 方法获取它的迭代对象(可以理解为链表的指针)

            迭代器是指实现了 __iter__ 和 __next__方法对象,__iter__返回它本身,确保每个单独的节点都是可以被迭代的,满足链表可以从第n个元素开始访问的需求;__next__返回它的下一个节点,如果已经遍历完毕则抛出StopIteration异常。

    # 实现了__iter__方法,是一个可迭代对象,可以理解为是一个整的链表,但此时还不能单独访问其中的元素
    class Node:
        def __init__(self, data):
            self.data = data
            self.next: Node | None = None
        def __iter__(self):
            return NodeIter(self)
    #是迭代器对象,可以理解为指向链表首元素的指针,通过这个指针遍历所有的链表元素
    class NodeIter:
        def __init__(self, node: Node = None):
            self.current = node
        def __iter__(self):
            return self
        def __next__(self):
            if self.current is None:
                raise StopIteration
            else:
                node = self.current
                self.current = self.current.next
                return node #返回当前节点的值

    • 协议不同:可迭代对象只需实现 __iter__(),迭代器需要实现 __iter__() 和 __next__()
    • 状态:迭代器有内部状态(当前位置),可迭代对象通常没有
    • 重用性:可迭代对象可多次遍历(每次获取新迭代器),迭代器遍历一次后耗尽
    • 包含关系:所有迭代器都是可迭代对象,但并非所有可迭代对象都是迭代器

    依旧以链表举例,整个链表是一个可迭代对象,遍历这个对象的时候实际上是通过一个指向链表首元素的指针不断地移动到下一个元素来完成的,这个指针就可以理解为迭代器。

            生成器是一种特殊的迭代器,它通过 yield 关键字动态的返回值,而非一次性返回所有值,适合用来读取大文件或产生无限序列。生成器内部自动实现了 __iter__和__next__.

    当一个函数内部使用了yield关键字时,那么它就是一个生成器函数,此时函数的返回值不再是return后的返回值,而是类似于函数的对象 :

    <generator object fibonacci at 0x0000026E4B6D20A0>

    以一个生成n个斐波那契的生成器举例:

    def fibonacci(limit):
        """生成斐波那契数列"""
        a, b = 0, 1
        count = 0
        while count < limit:
            yield a
            a, b = b, a + b
            count += 1

    当执行下面的代码时:

    fibo = fibonacci(10)
    print(fibo) #输出:<generator object fibonacci at 0x0000026E4B6D20A0>
    print(next(fibo)) #输出0
    print(next(fibo)) #输出1
    print(next(fibo)) #输出1
    print(next(fibo)) #输出2

    fibo是一个生成器对象,这个对象可以生成10个斐波那契数,但不是同时生成在内存中,而是一个next()取回一个值,这个特性被称作 "惰性加载" 。执行第一个next()时,返回第一个yield后的值并且暂停函数的执行,等到第二次执行next()时从第一个field后开始继续执行,也就是说,当我在第一个 yield下面抛出异常,函数执行一次 next()并不会报错,因为抛出异常语句并没有执行,第二次执行next()才会报错,比如下面的代码:

    def generator1():
        print('第一个yield之前的语句块')
        yield 1
        print('第一个yield之后的语句块')
        print(1 / 0)
        print('第二个yield之前的语句块')
        yield 2
        print('第二个yield之后的语句块')
    ge = generator1() #产生了一个生成器对象
    print(next(ge))  # 只执行 print(1 / 0) 之前的代码函数就被中断了,所有不会报错
    print(next(ge))  # 回到第一个yield之后的代码继续执行,执行到print(1 / 0)语句,报错

    如果生成器函数中有return语句,return语句依旧有结束函数运行的作用,return之后的语句不可达,但仍然遵循上面的中断原则,并且return后的值是抛出 StopIteration异常的提示信息:

            当我们的生成器的数据是从一个列表中取得并且每次返回一个元素时应该怎么写?

    def generator():
        user_list = ["zhang","li","wang","qian"]
        for username in user_list:
            yield username
    ge = generator()
    for i in ge:
        print(i)

    yield from就是简化上面的流程,提升生成器的效率,以上代码可以用下面的代码替代:

    def generator():
        user_list = ["zhang","li","wang","qian"]
        yield from user_list
    ge = generator()
    for i in ge:
        print(i)

    到此这篇关于python迭代器和生成器的区别解析的文章就介绍到这了,更多相关python迭代器和生成器内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

    您可能感兴趣的文章:

    • Python迭代器和生成器之迭代器协议详解
    • Python 迭代器和生成器概念及场景分析
    • Python中迭代器与生成器的使用详解
    • Python迭代器与生成器及作用示例详解
    • Python迭代器、生成器、协程使用方式
    • 快速进修Python指南之迭代器Iterator与生成器
    • Python中的迭代器和生成器详解
    • python中的生成器、迭代器、装饰器详解
    • python列表生成器常用迭代器示例详解
    • Python中迭代器与生成器的用法

    站内搜索