我想做什么:
检查我在脚本中导入的不同模块(Python 2 或 3),并打印它们的名称。我目前使用的是 Python 2.7.12 和 3.6.4。
我从哪里开始:
该脚本只是导入模块,使用列表理解来查找其中的内容,然后打印列表:
#!/usr/bin/env python
import sys
import os
import types
module_list = [i.__name__ for i in globals().values()
if type(i) == types.ModuleType and i in sys.modules.values()]
print(module_list)
我最初是在 Python 3 中运行它,它运行得很好(对于 Python 2 也很好)。输出为:
['__builtin__', 'sys', 'os', 'types'] # Python 2.
['builtins', 'sys', 'os', 'types'] # Python 3.
此时,我决定扩展列表理解,因为我发现它是破译代码/逻辑流的良好实践。所以我将单个语句替换为:
module_list = []
for i in globals().values():
if type(i) == types.ModuleType and i in sys.modules.values():
module_list.append(i.__name__)
这就是事情变得棘手的地方。我收到一个 RuntimeError
,现在的输出是:
...
for i in globals().values():
RuntimeError: dictionary changed size during iteration
但是,它在 Python 2 中仍然有效。我现在比其他任何事情都更好奇,并尝试了一些事情。
我尝试过的:
将
globals().values()
转换为列表:for i in list(globals().values()): if type(i) == types.ModuleType and i in sys.modules.values(): module_list.append(i.__name__)
这在 Python 2 或 3 中按预期工作。
删除了
list()
并添加到正确的main
结构中:def main(): module_list = [] for i in globals().values(): if type(i) == type(sys) and i in sys.modules.values(): module_list.append(i.__name__) print(module_list) if __name__ == '__main__': main()
这在 Python 2 和 3 中按预期工作。
回顾一下:
- 列表理解适用于 Python 2 和 3。
for
循环仅适用于 Python 2。- 包装在
列表
中适用于Python 2和3。 - 正确的
main
结构适用于 Python 2 和 3。
问题:
Python 3 中的 for
循环破坏了什么?
最佳答案
for i in globals().values():
- 在获取 values
迭代器后,i
将添加到全局命名空间。如果您将 i = None
放在循环之前,或者执行 for i in list(globals().values()):
,它就会起作用。
在 python 2 中,values()
返回一个值列表,但在 python 3 中它是一个迭代器。该迭代器检测到更改并引发错误。
关于Python:检查导入模块时出现运行时错误的原因是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49563728/