mur*_*d99 61
yield
当你有一个函数返回一个序列而你想迭代该序列时,最好使用它,但你不需要一次在内存中包含每个值.
例如,我有一个python脚本解析大量的CSV文件,我想返回每一行在另一个函数中处理.我不想一次将兆字节的数据存储在内存中,所以我yield
在python数据结构中的每一行.因此从文件中获取行的功能可能如下所示:
def get_lines(files):
for f in files:
for line in f:
#preprocess line
yield line
Run Code Online (Sandbox Code Playgroud)
然后,我可以使用与列表相同的语法来访问此函数的输出:
for line in get_lines(files):
#process line
Run Code Online (Sandbox Code Playgroud)
但是我节省了大量的内存使用量.
waf*_*dox 15
简单地说,yield
给你一个发电机.您可以在通常return
在函数中使用的地方使用它.作为一个真正做作的例子,从提示中切割和粘贴......
>>> def get_odd_numbers(i):
... return range(1, i, 2)
...
>>> def yield_odd_numbers(i):
... for x in range(1, i, 2):
... yield x
...
>>> foo = get_odd_numbers(10)
>>> bar = yield_odd_numbers(10)
>>> foo
[1, 3, 5, 7, 9]
>>> bar
<generator object yield_odd_numbers at 0x1029c6f50>
>>> bar.next()
1
>>> bar.next()
3
>>> bar.next()
5
Run Code Online (Sandbox Code Playgroud)
如您所见,在第一种情况下,foo
将整个列表一次保存在内存中.对于包含5个元素的列表来说,这不是什么大问题,但是如果你想要一个500万的列表怎么办?这不仅是一个巨大的内存消耗者,而且在调用函数时也需要花费大量时间来构建.在第二种情况下,bar
只给你一个发电机.生成器是可迭代的 - 这意味着您可以在for循环等中使用它,但每个值只能被访问一次.所有值也不会同时存储在内存中; 生成器对象"记住"上次调用它时循环的位置 - 这样,如果你使用一个可迭代(比方说)计数到500亿,你就不必数到500亿全部立即存储500亿个数字.同样,这是一个非常人为的例子,itertools
如果你真的想要数到500亿,你可能会使用它.:)
这是生成器最简单的用例.正如你所说,它可以用来编写有效的排列,yield
用于通过调用堆栈向上推送而不是使用某种堆栈变量.生成器也可以用于专门的树遍历,以及其他各种方式.
进一步阅读:
另一个用途是在网络客户端中。在生成器函数中使用“yield”可以通过多个套接字进行循环,而不需要线程的复杂性。
例如,我有一个硬件测试客户端,需要将图像的 R、G、B 平面发送到固件。需要同步发送的数据:红、绿、蓝、红、绿、蓝。我没有生成三个线程,而是有一个从文件读取并对缓冲区进行编码的生成器。每个缓冲区都是一个“yield buf”。文件结束,函数返回,迭代结束。
我的客户端代码循环访问三个生成器函数,获取缓冲区直到迭代结束。
归档时间: |
|
查看次数: |
23957 次 |
最近记录: |