19

I have a deque in Python that I'm iterating over. Sometimes the deque changes while I'm interating which produces a RuntimeError: deque mutated during iteration.

If this were a Python list instead of a deque, I would just iterate over a copy of the list (via a slice like my_list[:], but since slice operations can't be used on deques, I wonder what the most pythonic way of handling this is?

My solution is to import the copy module and then iterate over a copy, like for item in copy(my_deque): which is fine, but since I searched high and low for this topic I figured I'd post here to ask?

Dana the Sane
  • 14,762
  • 8
  • 58
  • 80
Brian Madden
  • 951
  • 1
  • 8
  • 21
  • 7
    Why are you altering the `deque` while iterating it? Can you show some code? – thefourtheye May 07 '15 at 16:50
  • What do you expect to happen to the iteration you're in the middle of with respect to whatever modifications are being made to the deque? – martineau May 07 '15 at 17:23
  • As to why I'm altering it, this deque is a queue that's used to hold a stack of active modes in a pinball machine software app, and while the modes are being serviced it's possible for other modes to start and get added to the deque. I'm fine with not calling anything that came in during the iteration, or to call anything that was removed during the iteration. Really I want to iterate over the deque as it was when the iteration started, hence the copy. – Brian Madden May 07 '15 at 17:32
  • Is temporary preventing the alteration an option? Then you could use a threading.Lock object. – Harald Thomson Apr 15 '19 at 06:44

2 Answers2

20

You can "freeze" it by creating a list. There's no necessity to copy it to a new deque. A list is certainly good enough, since you only need it for iterating.

for elem in list(my_deque):
    ...

list(x) creates a list from any iterable x, including deque, and in most cases is the most pythonic way to do so.


Bare in mind this solution is only valid if the deque is being modified in the same thread (i.e. inside the loop). Else, be aware that list(my_deque) is not atomic, and is also iterating over the deque. This means that if another thread alters the deque while it runs, you end up with the same error. If you're in a multithreaded environment, use a lock.

shx2
  • 61,779
  • 13
  • 130
  • 153
0

While you can create a list out of the deque, for elem in list(deque), this is not always optimum if it is a frequently used function: there's a performance cost to it esp. if there is a large number of elements in the deque and you're constantly changing it to an array structure.

A possible alternative without needing to create a list is to use a while loop with some boolean var to control the conditions. This provides for a time complexity of O(1).

lionbigcat
  • 803
  • 6
  • 13
  • 2
    A `while` loop is good for destructive iteration while adding elements, but it's not going to be much help for the questioner's use case. – user2357112 Sep 15 '18 at 05:34