PYTHON:Globals().Items()迭代尝试更改字典

2022-03-31 00:00:00 python python-import

问题描述

cso.data.__init__.py中,我正在尝试执行以下操作:

from  cso.data._features  import * # import sumbodule 

for k, v in globals().items():
    if isinstance(v, entity):# entity is some type
        print(k,v)

令我惊讶的是,我得到了:

Traceback (most recent call last):
  File "X:ProgrammingworkspaceEclipsePyCommonSencesrccsodata\__init__.py", line 20, in <module>
    from  cso.data._features  import *
  File "X:ProgrammingworkspaceEclipsePyCommonSencesrccsodata\__init__.py", line 49, in <module>
    for k, v in globals().items():
RuntimeError: dictionary changed size during iteration

出于某种原因,它试图以某种方式修改迭代的全局变量。怎么会这样呢? 有没有其他更好的方法来列出包中所有模块的name: value形式的所有变量?

列表理解等效项工作正常,但打印两次:

print([ (k, v) for k, v in globals().items() if isinstance(v, entity)])

这里发生了什么?


解决方案

当您在全局范围内运行代码时,分配给的名称也是全局名称。kv在开始迭代globals().items()之后首先被分配,这将在globals()词典中添加'k''v'的条目。

您可以通过在迭代前显式复制dict来避免这种情况,例如:

for k, v in globals().copy().items():

或在函数中执行工作(该函数将在局部作用域中存储迭代变量):

def print_global_entities():
    for k, v in globals().items():
        if isinstance(v, entity):# entity is some type
            print(k,v)

if __name__ == '__main__':
    print_global_entities()

这样做实际上会加快代码的引导速度;在函数外部,kvkv的每次存储和加载都涉及dict查找,而在函数内部,Python可以(CPython引用解释器确实如此)使用简单的C数组查找和编译时计算的索引。

第三种方法是欺骗方法:确保kv预先存在,这样globals()dict就不会添加或删除项。您只需添加:

k = v = None

就在for循环之前。

相关文章