Python:检查导入的模块时,此RuntimeError的来源是什么?

时间:2018-03-29 19:31:38

标签: python python-3.x python-2.7

我想做什么:

检查我在脚本中导入的不同模块(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。
  • 包装list适用于Python 2和3。
  • 适当的main结构适用于Python 2和3。

问题:

Python 3中for循环破坏了什么呢?

1 个答案:

答案 0 :(得分:1)

获得for i in globals().values():迭代器后,

i - values被添加到全局命名空间。如果您在循环之前放置i = None,或执行for i in list(globals().values()):,则可以正常工作。

在python 2中,values()返回一个值列表,但在python 3中它是一个迭代器。迭代器检测到更改并引发错误。