python - Dictionary changed size during iteration - Code works in Py2 Not in Py3 -
i have following sample code:
k_list = ['test', 'test1', 'test3'] def test(*args, **kwargs): 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')
in python 2.7.13 prints expect , still has item left in kwargs
:
('popping k = ', 'test') ('popping k = ', 'test1') ('popping k = ', 'test3') ('remaining kwargs:', [('test2', 'test2')])
in python 3.6.1, however, 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 k, value in kwargs.items(): runtimeerror: dictionary changed size during iteration
what need adjust maintain python 2 compatibility work correctly in python 3.6? remaining kwargs
used later logic in script.
the reason works in python2.x because kwargs.items()
creates list -- can think of snapshot of dictionary's key-value pairs. since snapshot, can change dictionary without modifying snapshot you're iterating on , ok.
in python3.x, kwargs.items()
creates view dictionary's key-value pairs. since view, can no longer change dictionary without changing view. why error in python3.x
one resolution work on both python2.x , python3.x create snapshot using list
builtin:
for k, value in list(kwargs.items()): ...
or, alternatively, create snapshot copying dict:
for k, value in kwargs.copy().items(): ...
this work. in unscientific experiement did in interactive interpreter, first version fair amount faster second on python2.x. note whole thing inefficient on python2.x because you'll creating addition copy of (either list
or dict
depending on version reference). based on other code, doesn't of concern. if is, can use six
compatibility:
for k, value in list(six.iteritems(kwargs)): ...
wiki
Comments
Post a Comment