PyN*_*oob 3 python dictionary python-2.7 python-3.x
我有以下示例代码:
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')
Run Code Online (Sandbox Code Playgroud)
在Python 2.7.13中,这完全可以打印出我所期望的内容,并且仍然在kwargs:
('Popping k = ', 'test')
('Popping k = ', 'test1')
('Popping k = ', 'test3')
('Remaining KWARGS:', [('test2', 'test2')])
Run Code Online (Sandbox Code Playgroud)
但是,在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
Run Code Online (Sandbox Code Playgroud)
为了保持Python 2的兼容性但要在Python 3.6中正常工作,我需要进行哪些调整?其余的kwargs将用于我的脚本中的后续逻辑。
在 Python 3 中,dict.items被更改为view,之前它返回一个副本。要再次使用副本并获取交叉兼容代码,您可以更改以下行:
for k, value in kwargs.items():
Run Code Online (Sandbox Code Playgroud)
对此:
for k, value in list(kwargs.items()):
Run Code Online (Sandbox Code Playgroud)
它在python2.x中工作的原因是kwargs.items()创建了一个列表-您可以将其视为字典的键/值对的快照。由于它是快照,因此您可以在不修改要迭代的快照的情况下更改字典,一切正常。
在python3.x中,kwargs.items()创建对字典的键/值对的视图。由于它是视图,因此您无法再更改视图而又不能更改字典。这就是为什么您在python3.x中收到错误的原因
适用于python2.x和python3.x的一种解决方案是始终使用list内置函数创建快照:
for k, value in list(kwargs.items()):
...
Run Code Online (Sandbox Code Playgroud)
或者,通过复制字典来创建快照:
for k, value in kwargs.copy().items():
...
Run Code Online (Sandbox Code Playgroud)
这将起作用。在我在交互式解释器中所做的非常不科学的实验中,第一个版本比python2.x上的第二个版本快很多。还要注意,在python2.x上,这整个过程的效率会稍有降低,因为您将创建某些事物的附加副本(a list或dict取决于您引用的版本)。根据您的其他代码,这似乎不是一个太多的问题。如果是这样,则可以使用类似six的兼容性:
for k, value in list(six.iteritems(kwargs)):
...
Run Code Online (Sandbox Code Playgroud)