>>> 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
如您所见,在第一种情况下,foo一次将整个列表保存在内存中。5个元素的列表没什么大不了的,但是如果你想要一个500万的列表呢?这不仅是一个巨大的内存消耗器,它也花费了大量的时间来构建时,该函数被调用。在第二种情况下,bar只是给你一个生成器。生成器是一个iterable——这意味着您可以在for循环等中使用它,但每个值只能访问一次。所有的值也不会同时存储在内存中;生成器对象“记住”上次调用它时它在循环中的位置--这样,如果使用iterable to(比方说)count to 500亿,就不必一次全部计数到500亿,并存储500亿个数以进行计数。再说一次,这是一个非常做作的例子,如果你真的想数到500亿,你可能会使用itertools。:)
另一个用途是在网络客户机中。在生成器函数中使用'yield'循环遍历多个套接字,而不需要复杂的线程。
例如,我有一个硬件测试客户机,需要将映像的R、G、B平面发送到固件。需要同步发送的数据:红、绿、蓝、红、绿、蓝。我没有生成三个线程,而是有一个从文件读取的生成器,对缓冲区进行编码。每个缓冲区都是“屈服缓冲区”。文件结束,函数返回,迭代结束。
我的客户机代码在三个生成器函数之间循环,在迭代结束之前获取缓冲区。
当您有一个返回序列的函数,并且您希望在该序列上迭代时,最好使用
yield
,但您不需要同时在内存中拥有每个值。例如,我有一个python脚本,它解析一个CSV文件的大列表,我希望返回要在另一个函数中处理的每一行。我不想一次将兆字节的数据存储在内存中,所以我在python数据结构中的每一行
yield
。因此,从文件中获取行的函数可能类似于:然后,我可以使用与with list相同的语法来访问此函数的输出:
但是我节省了很多内存。
简单地说,
yield
给你一个生成器。在通常在函数中使用return
的地方使用它。作为一个真正做作的例子从一个提示剪贴。。。如您所见,在第一种情况下,
foo
一次将整个列表保存在内存中。5个元素的列表没什么大不了的,但是如果你想要一个500万的列表呢?这不仅是一个巨大的内存消耗器,它也花费了大量的时间来构建时,该函数被调用。在第二种情况下,bar
只是给你一个生成器。生成器是一个iterable——这意味着您可以在for循环等中使用它,但每个值只能访问一次。所有的值也不会同时存储在内存中;生成器对象“记住”上次调用它时它在循环中的位置--这样,如果使用iterable to(比方说)count to 500亿,就不必一次全部计数到500亿,并存储500亿个数以进行计数。再说一次,这是一个非常做作的例子,如果你真的想数到500亿,你可能会使用itertools
。:)这是生成器最简单的用例。正如您所说的,它可以用来编写有效的置换,使用
yield
通过调用堆栈向上推,而不是使用某种堆栈变量。生成器还可以用于专门的树遍历和所有其他事情。进一步阅读:
相关问题 更多 >
编程相关推荐