我有以下示例代码:
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
将用于我的脚本中的后续逻辑。 最佳答案
它在python2.x中工作的原因是kwargs.items()
创建了一个列表-您可以将其视为字典的键/值对的快照。由于它是快照,因此您可以更改字典而无需修改要遍历的快照,一切正常。
在python3.x中,kwargs.items()
创建一个对字典的键-值对的 View 。由于它是 View ,因此您无法再更改 View 而又不能更改字典。这就是为什么您在python3.x中收到错误的原因
适用于python2.x和python3.x的一种解决方案是始终使用内置的list
创建快照:
for k, value in list(kwargs.items()):
...
或者,通过复制字典来创建快照:
for k, value in kwargs.copy().items():
...
这会起作用。在我在交互式解释器中所做的非常科学的尝试中,第一个版本比python2.x上的第二个版本快很多。还要注意,在python2.x上,这整个过程的效率会稍有降低,因为您将创建某些东西的附加副本(
list
或dict
,具体取决于您引用的版本)。根据您的其他代码,这似乎不是一个太多的问题。如果是这样,则可以使用诸如 six
之类的兼容性:for k, value in list(six.iteritems(kwargs)):
...