我试图在python中围绕generator
和yield
。我知道具有yield的函数返回一个生成器对象。但是,如果我尝试将该生成器对象转换为列表,它会挂起我的机器。我试图找出原因。如果将生成器对象转换为列表,那么更优雅的方法是什么。
def fib():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
a = fib()
print(type(a))
b = fib()
print(type(b))
print(list(b))
输出
<class 'generator'>
<class 'generator'>
答案 0 :(得分:4)
问题是您的生成器没有结束条件(while True
而没有break
)
即使编写这样的生成器是有意义的(例如:产生Pi
的所有小数或我刚刚在代码中识别出的Fibonacci序列:)),当你将它转换为列表时,它永远循环(并且也吃掉所有的记忆)
BTW:list()
当然是将(有限:))生成器转换为list
对象的最佳方法。
答案 1 :(得分:3)
list()
无法转换无限序列。您需要为生成器添加上限:
def fib(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
print list(fib(10))
答案 2 :(得分:3)
由于您的生成器没有上限,因此询问它的列表就像要求列出Fibonacci序列的所有数字(如前所述,它是无限的,因此可能需要一些时间:))
所以,要么在你的fib()生成器中加入一个参数,如另一篇文章中所解释,或者使用类似的东西,例如10个下一个值:
b = fib()
[next(b) for _ in range(10)]
答案 3 :(得分:1)
问题在于您的生成器 - list(fib())
基本上遍历生成器的所有迭代并将它们放在列表中。由于您的生成器是无限循环,因此迭代永远不会停止。
答案 4 :(得分:1)
正如其他人所说,你的发电机将无限运行。如果您尝试将无限生成器转换为列表,它将运行内存。您获得输出的原因是因为您需要使用next()
(在Python 2中为.__next__
)来从生成器获取下一个元素。例如
>>> def gen():
for i in range(100):
yield i
>>> g = gen()
>>> next(g)
0
>>> next(g)
1
>>> next(g)
2
>>>
但是你似乎想要从你的生成器创建一个完整的迭代,在这种情况下你不能。 Python将耗尽内存。如果要将生成器转换为列表,则必须具有上限。
>>> def gen():
while True:
yield 0
>>> g = gen()
>>> list(g)
# it gets stuck forever