我有以下示例代码:
k_list = ['test', 'test1', 'test3']
def test(*args, **kwargs):
for k, value in kwargs.items():
if k in k_list:
print("Popping k = ", k)
kwargs.pop(k, None)
print("Remaining KWARGS:", kwargs.items())
test(test='test', test1='test1', test2='test2', test3='test3')
在 Python 2.7.13 中,这完全符合我的预期,并且在 kwargs
中仍然有一个项目:
('Popping k = ', 'test')
('Popping k = ', 'test1')
('Popping k = ', 'test3')
('Remaining KWARGS:', [('test2', 'test2')])
然而,在 Python 3.6.1 中,这失败了:
Popping k = test
Traceback (most recent call last):
File "test1.py", line 11, in <module>
test(test='test', test1='test1', test2='test2', test3='test3')
File "test1.py", line 5, in test
for k, value in kwargs.items():
RuntimeError: dictionary changed size during iteration
我需要调整什么以保持 Python 2 兼容性但在 Python 3.6 中正常工作?剩余的 kwargs
将用于我脚本中的后续逻辑。
原文由 PyNoob 发布,翻译遵循 CC BY-SA 4.0 许可协议
它在 python2.x 中工作的原因是因为
kwargs.items()
创建了一个列表——您可以将其视为字典键值对的快照。由于它是一个快照,您可以在不修改您正在迭代的快照的情况下更改字典,一切正常。在 python3.x 中,
kwargs.items()
创建字典键值对的 _视图_。由于它是一个视图,因此您不能在不更改视图的情况下更改字典。这就是你在 python3.x 中出错的原因一种适用于 python2.x 和 python3.x 的解决方案是始终使用
list
内置创建快照:或者,也可以通过复制字典来创建快照:
这会起作用。在我用我的交互式解释器做的一个非常不科学的实验中,第一个版本比 python2.x 上的第二个版本快很多。另请注意,这整个事情在 python2.x 上会稍微低效,因为您将创建一些东西的附加副本(
list
或dict
取决于您引用的版本) .根据您的其他代码,这看起来并不是什么大问题。如果是,您可以使用类似six
的兼容性: