pop method question

Steven D'Aprano steve at REMOVE.THIS.cybersource.com.au
Sun Mar 4 01:02:40 CET 2007

On Sat, 03 Mar 2007 15:36:14 -0800, Paul Rubin wrote:

> James Stroud <jstroud at mbi.ucla.edu> writes:
>> for akey in dict1:
>>    if some_condition(akey):
>>      dict2[akey] = dict2.pop(akey)
>> Which necessitates a key is a little cleaner than your latter example.
> Yeah, I also think removing keys from a dict while iterating over it
> (like in Steven's examples) looks a bit dangerous dangerous.

It is dangerous. That's why I didn't do it.

I very carefully iterated over a list, not the dictionary, and in fact put
in a comment explicitly saying that you can't iterate over the dictionary:

for key in some_dict.keys(): 
    # can't iterate over the dictionary directly!

If you try to iterate over the dictionary directly, you get a RuntimeError
exception when the dictionary changes size. Unfortunately, the exception
isn't raised until AFTER the dictionary has changed size.

>>> D = {1:1, 2:2}
>>> for key in D:
...     D.pop(key)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
>>> D
{2: 2}

That's a gotcha to watch out for: the exception isn't raised until
the damage is done.

> Assuming you meant "dict1.pop" instead ot dict2.pop above, your
> example might be written
>     dict2 = dict((k, dict1.pop(k)) for k in dict1 if some_condition(k))
> avoiding some namespace pollution etc.

You get a RuntimeError exception when dict1 changes size.

You know, if I were easily offended, I'd be offended that you accused _me_
of writing dangerous code when my code both worked and worked safely,
while your code failed and did damage when it did so (dict1 irretrievably
loses an item).



More information about the Python-list mailing list