Python: globals().items() 迭代尝试改变字典
Python: globals().items() iterations try to change a dict
在 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)])
这里发生了什么?
因为 for 循环语句创建了一个新变量,在您的特定情况下:
for k, v in globals().items():
...
您已经在全局命名空间中创建了 k
和 v
,字面意思是 dict
另一方面,列表推导式创建了自己的局部函数作用域。只要做:
for k, v in globals().copy().items():
...
如果您不想复制,则执行:
k,v = None, None
for k,v in globals().items():
...
或者更好的是,将所有这些都包装在一个函数中,这样您就不会不小心触及全局命名空间
当您 运行 在全局范围内编写代码时,您分配的名称也是全局的。 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
查找,而在函数内部,Python 可以(并且 CPython 参考解释器确实)使用简单的 C 数组查找和在编译时计算的索引。
第三种方法是作弊方法:确保k
和v
预先存在,所以globals()
dict
不会添加或删除项目。您只需要添加:
k = v = None
就在 for
循环之前。
在 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)])
这里发生了什么?
因为 for 循环语句创建了一个新变量,在您的特定情况下:
for k, v in globals().items():
...
您已经在全局命名空间中创建了 k
和 v
,字面意思是 dict
另一方面,列表推导式创建了自己的局部函数作用域。只要做:
for k, v in globals().copy().items():
...
如果您不想复制,则执行:
k,v = None, None
for k,v in globals().items():
...
或者更好的是,将所有这些都包装在一个函数中,这样您就不会不小心触及全局命名空间
当您 运行 在全局范围内编写代码时,您分配的名称也是全局的。 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
查找,而在函数内部,Python 可以(并且 CPython 参考解释器确实)使用简单的 C 数组查找和在编译时计算的索引。
第三种方法是作弊方法:确保k
和v
预先存在,所以globals()
dict
不会添加或删除项目。您只需要添加:
k = v = None
就在 for
循环之前。