pop method question

Steven D'Aprano steve at REMOVE.THIS.cybersource.com.au
Sat Mar 3 19:02:40 EST 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!
    do_something_with(some_dict.pop(key))


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)
...
1
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).

*wink*



-- 
Steven.




More information about the Python-list mailing list