python 生成器

本文介绍了Python中的生成器,包括迭代协议、生成器的定义和使用,以及生成器推导式。生成器通过`yield`关键字实现迭代,不占用额外内存,适合处理大量数据。此外,还提到了`itertools`模块在生成器中的应用,以及生成器在生产者-消费者模型和管道中的作用。使用生成器能提高代码效率并节省内存。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

迭代协议

如下,调用__iter__()建立迭代器对象并调用__next__()方法迭代元素。

>>> x = [1,2,3]
>>> it = x.__iter__()
>>> it
<listiterator object at 0x590b0>
>>> it.__next__()
1
>>> it.__next__()
2
>>> it.__next__()
3
>>> it.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in ? StopIteration
>>>

常用的 for-loop 迭代使用了底层的迭代协议。

生成器

生成器是使用 yield 定义迭代的任意函数。

def countdown(n):
    # Added a print statement
    print('Counting down from', n)
    while n > 0:
        yield n
        n -= 1

调用生成器会建立一个生成器对象,并不会马上输出结果。

>>> x = countdown(10)
# There is NO PRINT STATEMENT
>>> x
# x is a generator object
<generator object at 0x58490>
>>>

生成器使用__next__() 迭代输出。

>>> x = countdown(10)
>>> x
<generator object at 0x58490>
>>> x.__next__()
Counting down from 10
10
>>>

yield产生一个值,但暂停函数执行,该函数恢复执行在下一次调用__next__()时。

生成器函数实现了与for语句在列表、元组、字典、文件等使用中,相同的低级迭代协议。

生成器推导式

列表推导式的生成器版本。

>>> a = [1,2,3,4]
>>> b = (2*x for x in a)
>>> b
<generator object at 0x58760>
>>> for i in b:
...   print(i, end=' ')
...
2 4 6 8
>>>

与列表推导式的区别:

  • 不构造列表。
  • 构建生成器对象,唯一的目的是迭代。
  • 不可重复使用。

不可重复使用的意思如下:

>>> nums = [1, 2, 3, 4, 5]
>>> squares = (x*x for x in nums)
>>> squares
<generator object <genexpr> at 0x109207e60>
>>> for n in squares:
...     print(n)
...
1
4
9
16
25

如果再尝试 for 循环遍历,将没有结果。

>>> for n in squares:
...     print(n)
...
>>>

语法结构,注意是括号。

(<expression> for i in s if <conditional>)

小型生成器的编写例子:

def filter_symbols(rows, names):
    for row in rows:
        if row['name'] in names:
            yield row

应使用如下方式编写:

rows = (row for row in rows if row['name'] in names)

生成器表达式的主要用途是对序列执行一些计算,但只使用一次结果。

使用生成器,代码运行得更快并且使用的内存更少。

使用生成器的好处:

  • 在迭代时,可以执行搜索,替换,修改等操作。
  • 处理管道可以应用于多种数据处理问题。
  • 仅在需要的时候 yield 值,可以对流数据进行操作,与列表推导式相比不需要构建列表,节省了内存。
  • 生成器代码可重复使用,并且迭代与使用迭代的功能被分开。

itertools 模块

itertools是一个库模块,具有旨在帮助迭代器/生成器的各种功能。

一些例子

itertools.chain(s1,s2)
itertools.count(n)
itertools.cycle(s)
itertools.dropwhile(predicate, s)
itertools.groupby(s)
itertools.ifilter(predicate, s)
itertools.imap(function, s1, ... sN)
itertools.repeat(s, n)
itertools.tee(s, ncopies)
itertools.izip(s1, ... , sN)

所有函数都以迭代方式处理数据。

更多内容查看生成器实用技巧

生产者和消费者模型

生成器与各种形式的生产者-消费者问题密切相关,类似 Unix 管道。

# Producer
def follow(f):
    ...
    while True:
        ...
        yield line        # Produces value in `line` below
        ...

# Consumer
for line in follow(f):    # Consumes value from `yield` above
    ...

yield 为消费者提供价值。

管道

生产者→加工→加工→消费者。

管道有一个初始数据生产者、一组中间处理阶段和一个最终消费者。

def producer():
    ...
    yield item          # yields the item that is received by the `processing`
    ...

def processing(s):
    for item in s:      # Comes from the `producer`
        ...
        yield newitem   # yields a new item
        ...

def consumer(s):
    for item in s:      # Comes from the `processing`
        ...
a = producer()
b = processing(a)
c = consumer(b)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Not_Today.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值