问题描述
我有以下示例代码:
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
中仍然有一个项目:
In Python 2.7.13 this prints exactly what I expect and still has an item left in the kwargs
:
('Popping k = ', 'test')
('Popping k = ', 'test1')
('Popping k = ', 'test3')
('Remaining KWARGS:', [('test2', 'test2')])
但是,在Python 3.6.1中,此操作失败:
In Python 3.6.1, however, this fails:
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
将用于我的脚本中的后续逻辑.
What do I need to adjust to maintain the Python 2 compatibility but work correctly in Python 3.6? The remaining kwargs
will be used for later logic in my script.
推荐答案
它在python2.x中工作的原因是kwargs.items()
创建了一个列表-您可以将其视为字典键值的快照对.由于它是快照,因此您可以更改字典而无需修改要遍历的快照,一切正常.
The reason that it works in python2.x is because kwargs.items()
creates a list -- You can think of it as a snapshot of the dictionary's key-value pairs. Since it is a snapshot, you can change the dictionary without modifying the snapshot that you're iterating over and everything is OK.
在python3.x中,kwargs.items()
在字典的键/值对中创建一个 view .由于它是视图,因此您不能再更改视图而不更改视图.这就是为什么您在python3.x中得到错误的原因
In python3.x, kwargs.items()
creates a view into the dictionary's key-value pairs. Since it is a view, you can no longer change the dictionary without also changing the view. This is why you get an error in python3.x
同时适用于python2.x和python3.x的一种解决方案是始终使用内置的list
创建快照:
One resolution which will work on both python2.x and python3.x is to always create a snapshot using the list
builtin:
for k, value in list(kwargs.items()):
...
或者,通过复制字典来创建快照:
Or, alternatively, create a snapshot by copying the dict:
for k, value in kwargs.copy().items():
...
这将起作用.在我在交互式解释器中所做的非常科学的尝试中,第一个版本比python2.x上的第二个版本快很多.还要注意,在python2.x上,这整个过程的效率会稍有降低,因为您将创建某些内容的附加副本(list
或dict
,具体取决于您引用的版本).根据您的其他代码,这似乎不是一个太多的问题.如果是这样,可以使用类似 six
之类的兼容性:
This will work. In a very unscientific experiement that I did in my interactive interpreter, the first version is a fair amount faster than the second on python2.x. Also note that this whole thing will be slightly inefficient on python2.x because you'll be creating an addition copy of something (either a list
or dict
depending on which version you reference). Based on your other code, that doesn't look like too much of a concern. If it is, you can use something like six
for compatibility:
for k, value in list(six.iteritems(kwargs)):
...
这篇关于字典在迭代过程中更改了大小-代码在Py2中有效,而在Py3中无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!