Modify dict/set during iteration?

Dave Angel davea at ieee.org
Fri Oct 30 15:21:56 CET 2009


metal wrote:
> Steven D'Aprano wrote:
>   
>> On Thu, 29 Oct 2009 19:02:01 -0700, metal wrote:
>>     
>>> I used this quickndirty way, any good idea to solve this problem?
>>>       
>> It's not a problem that wants solving, it's a feature that wants paying
>> attention to.
>>
>> As a general rule, you shouldn't modify data structures while you're
>> iterating over them, unless the data structure is advertised as safe to
>> modify while being iterated over, or you can do so in a way that is
>> guaranteed to be safe. When it comes to dicts and sets, neither of those
>> conditions hold.
>>
>> Why do you want to do this? It seems like a lot of effort to avoid a
>> simple, straight-forward idiom:
>>
>> make a copy of the dict or set
>> iterate over the copy, making changes to the original
>>
>> What are you trying to accomplish by modifying objects while iterating
>> over them?
>>
>>
>>
>>     
>>> def miter(iterable):
>>>       
>> [...]
>>     
>>>         except RuntimeError, e:
>>>             # Not sure if there were any other RuntimeError
>>>             if 'changed size during iteration' in e.message:
>>>                 continue
>>>       
>> That is not safe. There's no guarantee that the error message won't
>> change, even between one minor version to another, or between one Python
>> implementation and another. If you insist on making such an unsafe test,
>> at the very least be as conservative in what you expect as possible:
>>
>> if 'changed' in e.message and 'size' in e.message:
>>
>> and hope that nobody runs your code with internationalised error messages.
>>
>> --
>> Steven
>>     
>
> Yes the idoim rulz. I confused my self.
>
> Maybe my real goal is the following:
>
> def miter(iterable):
> 	for x in tuple(iterable):
> 		if x in iterable:
> 			yield x
>
>
>   
That works, though I'd change the parameter name to something to 
indicate that it's a set or dictionary, not a general iterable.

As someone else pointed out, you can't use 'in' on a generator, for example.

Assuming a dict, what happens if a new item created in the dictionary, 
but reusing an old key?  It won't cause an exception, but you run the 
risk of either processing some data twice, or some not-at-all.  Whether 
that matters or not depends on your use-case.  Sometimes you need to 
copy the keys, and sometimes you need to copy the keys and their values.

DaveA




More information about the Python-list mailing list