Python 字典在迭代过程中更改了大小-代码在Py2而不是Py3中工作
我有以下示例代码:Python 字典在迭代过程中更改了大小-代码在Py2而不是Py3中工作,python,python-2.7,python-3.x,dictionary,Python,Python 2.7,Python 3.x,Dictionary,我有以下示例代码: 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())
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')
在Python2.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
Popping k=测试
回溯(最近一次呼叫最后一次):
文件“test1.py”,第11行,在
测试(test='test',test1='test1',test2='test2',test3='test3')
文件“test1.py”,第5行,在测试中
对于k,以kwargs.items()表示的值:
RuntimeError:字典在迭代期间更改了大小
我需要调整什么来保持Python 2的兼容性,但在Python 3.6中可以正常工作?剩余的
kwargs
将用于我脚本中的后续逻辑。在Python 3中,dict.items
已更改为视图,在此之前它返回了一个副本。要再次使用副本并获取交叉兼容代码,您可以更改此行:
for k, value in kwargs.items():
为此:
for k, value in list(kwargs.items()):
它在python2.x中工作的原因是
kwargs.items()
创建了一个列表——您可以将其视为字典键值对的快照。因为它是一个快照,所以您可以更改字典,而无需修改正在迭代的快照,并且一切正常
在python3.x中,kwargs.items()
在字典的键值对中创建一个视图。由于它是一个视图,因此在不更改视图的情况下无法再更改字典。这就是为什么在python3.x中会出现错误
在python2.x和python3.x上都适用的一种解决方案是始终使用列表创建快照
内置:
for k, value in list(kwargs.items()):
...
或者,通过复制dict创建快照:
for k, value in kwargs.copy().items():
...
这会奏效的。我在交互式解释器中做了一个非常不科学的实验,第一个版本比python2.x上的第二个版本快很多。还要注意的是,在python2.x上,这整件事情的效率会有点低,因为您将创建某个内容的附加副本(根据您引用的版本,可以是列表
或dict
)。根据您的其他代码,这看起来不太重要。如果是,您可以使用以下内容来实现兼容性:
for k, value in list(six.iteritems(kwargs)):
...
我不会使用循环,而是设置:
# Your setup
kwargs = dict(test='test', test1='test1', test2='test2', test3='test3')
k_list = ['test', 'test1', 'test3']
# How to extract unwanted keys:
common_keys = set(kwargs) & set(k_list)
kwargs = { k: kwargs[k] for k in kwargs if k not in common_keys }
在最后一行中,我没有使用
kwargs.items()
或.iteritems()
,因此该示例在这两个版本中都运行良好。但是如果你只针对Python 3,你可能想在产品中使用<代码>。不是要覆盖您的编辑。@ChristianDean,所以有问题。谢谢你修改我的语法!