Python 在 print() 之后跳过 for 循环
Posted
技术标签:
【中文标题】Python 在 print() 之后跳过 for 循环【英文标题】:Python skipping for-loop after print() 【发布时间】:2016-02-26 09:59:04 【问题描述】:我正在调试编写代码的部分,所以我使用大量对print
的调用来检查我的变量的值。我遇到了一种情况,当打印一个变量时,Python 会跳过一个 for
循环。
import numpy as np
import itertools as itr
(...)
class myclass():
def a_function_inside_a_class():
print('-------------')
current_size = self.get_current_size()
current_size[dimension] += 1
new_layer = [range(i) for i in current_size]
new_layer[dimension] = [current_size[dimension]]
print(new_layer)
new_layer = itr.product(*new_layer)
print(list(new_layer)) # THIS LINE CAUSES PROBLEMS
for c in new_layer:
print('for')
print(list(c))
(...)
a_function_that_causes_some_error(c)
我创建一个列表,然后使用itertools
创建此列表的组合,然后对其进行迭代。
如果我像上面那样调用a_function_inside_a_class()
,我没有打印出for
。没有错误发生。解释器没有进入循环。
(...)
-------------
[[2], range(0, 1), range(0, 1)]
[(2, 0, 0)]
-------------
[range(0, 1), [2], range(0, 1)]
[(0, 2, 0)]
(...)
但如果我注释掉#print(list(new_layer))
,则执行for循环,我得到一个由其他函数a_function_that_causes_some_error(c)
引起的错误。
-------------
[[2], range(0, 1), range(0, 1)]
for
[2, 0, 0]
Traceback (most recent call last):
(...)
list(new_layer)
不会改变new_layer
对象本身,只会创建一个列表并将其传递给print()
函数,是吗?
【问题讨论】:
为什么函数体内有self
,但函数的参数列表中没有?
只需在第一次调用之后的行中添加另一个print(list(new_layer))
,您就会明白它为什么会失败。
print
不是问题,list()
是。 itertools.product()
是一个生成器,当您在其上使用 list()
时,您已经耗尽了迭代器。改为在列表中添加for
。
@cdarke - 你把它宠坏了!我想在不泄露的情况下暗示这个事实。但你完全正确! :-)
@MSeifert:我在写文档时正在检查我的评论,所以我错过了你的评论。很抱歉破坏了你的乐趣!
【参考方案1】:
问题是itertools.product
返回了一个生成器。
当您调用 print(list(new_layer))
时,您正在从生成器构造一个列表,但不要在任何地方保存对该列表的引用。
生成器本身在将其转换为列表后将耗尽,因为list(some_generator)
在该生成器上调用__next__
(或next
,取决于Python 版本)直到它引发StopIteration
。
>>> from itertools import product
>>> new_layer = product([1,2,3], [4,5,6])
>>> new_layer
<itertools.product object at 0x7f46e90349b0>
>>> print(list(new_layer))
[(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]
>>> print(list(new_layer))
[]
如你所见,构造列表一次后,生成器为空。
你可以通过使用来修复你的程序
new_layer = list(itr.product(*new_layer))
print(new_layer)
因为现在您将获得对从生成器创建的列表的引用。
【讨论】:
您的建议有效,但它与在他的情况下使用itertools
完全矛盾,因为您将结果保存在应该只保留生成器的地方。这里的教训应该是:不要在循环之前调试循环变量,在循环中调试/显示它们
@MSeifert 是的,据我了解 OP,他正在使用打印调用进行调试。我建议在程序经过正确测试之前使用我的修复程序。然后,在删除打印语句后,不再需要将生成器转换为列表,如果您按原样使用生成器,程序将更加节省内存。以上是关于Python 在 print() 之后跳过 for 循环的主要内容,如果未能解决你的问题,请参考以下文章
python 学习笔记(循环,print的几种写法,操作符)