在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
之后,首先分配v
和globals().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()
这样做实际上使您的代码可以更快地启动。在函数外部,每个
k
和v
的存储以及从dict
和k
的加载都涉及一个v
查找,而在函数内部,Python可以(并且CPython参考解释器可以)使用具有计算出的索引的简单C数组查找在编译时。第三种方法是作弊方法:确保预先存在
globals()
和dict
,所以for
不会添加或删除项目。您所需要做的就是添加:k = v = None
在循环之前。
关于python - Python:globals()。items()迭代尝试更改字典,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57532675/