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,所以有问题。谢谢你修改我的语法!