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:\Programming\workspaceEclipse\PyCommonSence\src\cso\data\__init__.py", line 20, in <module>
    from  cso.data._features  import *
  File "X:\Programming\workspaceEclipse\PyCommonSence\src\cso\data\__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)])


这是怎么回事

最佳答案

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

您可以通过在迭代之前显式复制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()


这样做实际上使您的代码可以更快地启动。在函数外部,每个kv的存储以及从dictk的加载都涉及一个v查找,而在函数内部,Python可以(并且CPython参考解释器可以)使用具有计算出的索引的简单C数组查找在编译时。

第三种方法是作弊方法:确保预先存在globals()dict,所以for 不会添加或删除项目。您所需要做的就是添加:

k = v = None


在循环之前。

关于python - Python:globals()。items()迭代尝试更改字典,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57532675/

10-12 14:28
查看更多