avatar

刘刚刚的blog

采菊东篱下,悠然见南山🦥

  • 首页
  • 大模型应用
  • 常用软件/工具
  • Halo
  • 关于
Home python-迭代器、生成器、协程
文章

python-迭代器、生成器、协程

Posted 2022-12-25 Updated 2024-09- 27
By Administrator
14~18 min read

迭代器

Python中当容器对象提供了对迭代的支持时,可以通过container.__iter__()来返回一个迭代器对象。

迭代器需要支持以下两个方法,这两个方法共同构成了迭代器协议:

  1. iterator.__iter__()

    该方法返回迭代器本身,这个方法是配合for和in使用所必须的。

  2. iterator.__next__()

    该方法返回下一项,如果已没有可返回的内容则引发 StopIteration异常

生成器

当一个函数内存在yield关键字时,这个函数便成为一个生成器函数。

当一个生成器函数被调用时,变会返回一个名称为生成器的迭代器。

生成器支持以下方法:

  1. generator.__next__()

    有两个作用:

    (1)开始一个生成器函数的执行

    (2)从上次执行yield的地方恢复,如果为该用法,则上次的yield表达式的值,会被赋值为None.

    from icecream import  ic
    def echo(value=None):
        print("生成器开始执行")
        try:
            while True:
                try:
                    value = (yield value)
                except Exception as e:
                    value = e
        finally:
            print("关闭")
    
    
    generator = echo(1)
    ic(next(generator))
    ic(next(generator))
    
    #输出结果:
    >>>
    生成器开始执行
    ic| next(generator): 1
    ic| next(generator): None
    关闭
  2. generator.send()

    有两个作用:

    (1)开始一个生成器函数的执行,此时send的参数比如为None

    (2)从上次执行yield的地方恢复,如果为该用法,则上次的yield表达式的值,会被赋值为send的参数.

    from icecream import  ic
    def echo(value=None):
        print("生成器开始执行")
        try:
            while True:
                try:
                    value = (yield value)
                except Exception as e:
                    value = e
        finally:
            print("关闭")
    generator = echo(1)
    print("---")
    ic(generator.send(None))
    ic(generator.send(1))
    # 输出结果
    >>>
    ---
    生成器开始执行
    ic| generator.send(None): 1
    ic| generator.send(1): 1
    关闭
  3. generator.throw()

    在生成器暂停的位置引发一个异常,并返回该生成器函数产生的下一个值,如果没有下一个值,则会引发 StopIteration异常

    # 引发一个异常,有下一个值时的示例
    def echo(value=None):
        ic("生成器开始执行")
        try:
            while True:
                try:
                    value = (yield value)
                except Exception as e:
                    value = e
        finally:
            print("关闭")
    
    
    generator = echo(1)
    ic("---")
    ic(next(generator))
    ic(generator.throw(TypeError, "spam"))
    
    >>>
    ic| '---'
    ic| '生成器开始执行'
    ic| next(generator): 1
    ic| generator.throw(TypeError, "spam"): TypeError('spam')
    关闭
    # 引发一个异常,无下一个值时的示例
    def echo(value=None):
        ic("生成器开始执行")
        try:
            while True:
                try:
                    value = (yield value)
                except Exception as e:
                    break
        finally:
            print("关闭")
    
    
    generator = echo(1)
    ic("---")
    ic(next(generator))
    ic(generator.throw(TypeError, "spam"))
    
    >>>
    ic| '---'
    ic| '生成器开始执行'
    ic| next(generator): 1
    Traceback (most recent call last):
      File "E:\2022www\test_3.7\main.py", line 42, in <module>
        ic(generator.throw(TypeError, "spam"))
    StopIteration
    关闭
  4. generator.close()

    在生成器函数暂停的位置引发 GeneratorExit异常,如果此时生成器再产生一个值,则会引发RuntimeError,如果生成器已经由于异常或者正常退出,则不会引发异常.

    # 引发 `GeneratorExit`异常的示例
    def echo(value=None):
        ic("生成器开始执行")
        try:
            while True:
                try:
                    value = (yield value)
                except Exception as e:
                    break
        finally:
            traceback.print_exc()
            print("关闭")
    
    
    generator = echo(1)
    ic("---")
    ic(next(generator))
    ic(generator.close())
    
    >>>
    ic| '---'
    ic| '生成器开始执行'
    ic| next(generator): 1
    Traceback (most recent call last):
      File "E:\2022www\test_3.7\main.py", line 32, in echo
        value = (yield value)
    GeneratorExit
    ic| generator.close(): None
    关闭
    # 引发 `RuntimeError`异常的示例
    def echo(value=None):
        ic("生成器开始执行")
        try:
            while True:
                try:
                    value = (yield value)
                except Exception as e:
                    break
        finally:
            yield 1
            print("关闭")
    
    
    generator = echo(1)
    ic("---")
    ic(next(generator))
    ic(generator.close())
    
    >>>
    ic| '---'
    ic| '生成器开始执行'
    ic| next(generator): 1
    Traceback (most recent call last):
      File "E:\2022www\test_3.7\main.py", line 43, in <module>
        ic(generator.close())
    RuntimeError: generator ignored GeneratorExit

生成器与迭代器的联系与区别

  1. 概念的区别

    生成器是使用了yield关键字的函数

    迭代器是实现了迭代器协议的对象

  2. 用途

    迭代器是访问容器的一种方式

    生成器是一种生成元素的方法,但生成器也实现了迭代器协议

  3. 两者的关联

    生成器也是一种迭代器

def echo(value=None):
    ic("生成器开始执行")
    yield 1


ec = echo(1)
from collections.abc import Iterator, Generator
#
print(type(ec))
print(ec.__class__.mro())
print(isinstance(ec, Iterator))
print(isinstance(ec, Generator))
>>>
<class 'generator'>
[<class 'generator'>, <class 'object'>]
True
True
[<class 'collections.abc.Iterator'>, <class 'collections.abc.Iterable'>, <class 'object'>]
[<class 'collections.abc.Generator'>, <class 'collections.abc.Iterator'>, <class 'collections.abc.Iterable'>, <class 'object'>]

tip:

此处的通过python的类的mro与abc中的mro不同,尚未找到原因,猜测可能是因为cpython的原因.

列表生成式与生成器推导式

列表生成式直接生成的就是列表

生成器推导式为生成器

a = [i for i in range(10)] # 列表生成式
b = (i for i in range(10)) # 生成器推导式
ic(a,type(a))
ic(b,type(b))
>>> 
ic| a: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], type(a): <class 'list'>
ic| b: <generator object <genexpr> at 0x035F7CF0>
    type(b): <class 'generator'>

可迭代对象与迭代器的关系

可迭代对象实现了__iter__()方法,可以将可迭代对象转为迭代器.

yield与协程

yield在生成器中实现了保存程序运行状态时上下文的功能,其作用与协程一样.

但是其并无法在遇到io时自动切换

python
License:  CC BY 4.0
Share

Further Reading

Apr 21, 2025

Typing

类型注释让python 有了更好的编辑器提示功能。 基础使用 对函数参数和返回值,进行类型注释 def surface_area_of_cube(edge_length: float) -> str:    return f"The surface area of the cube is {6 *

Feb 25, 2025

python多进程多线程下的计数及日志打印

注意点: 需要保证在多进程内的进程锁是同一个 需要保证在单进程中的多线程内线程锁是同一个 # logger.py import multiprocessing import threading ​ ​ class Logger_test:    def __init__(self, process

Dec 25, 2022

python-迭代器、生成器、协程

迭代器 Python中当容器对象提供了对迭代的支持时,可以通过container.__iter__()来返回一个迭代器对象。 迭代器需要支持以下两个方法,这两个方法共同构成了迭代器协议: iterator.__iter__() 该方法返回迭代器本身,这个方法是配合for和in使用所必须的。 iter

OLDER

HeadFirst 设计模式--外观模式(Facade Pattern)

NEWER

vmware硬盘占用过大的处理

Recently Updated

  • 文本切分-语义分割(Semantic Chunking)
  • dify 并发配置优化
  • Typing
  • 大模型返回中json_schema与json_mode的区别
  • Async

Trending Tags

Halo 运维 postgresql 设计模式 linux就该这么学 nas rag odoo python 文本切分

Contents

©2025 刘刚刚的blog. Some rights reserved.

Using the Halo theme Chirpy