Safe (documented behavior?) To remove iterator domain at runtime

I wanted to know if it is safe (documented behavior?) To remove the iterator domain space when executed in Python.

Consider the code:

import os import sys sampleSpace = [ x*x for x in range( 7 ) ] print sampleSpace for dx in sampleSpace: print str( dx ) if dx == 1: del sampleSpace[ 1 ] del sampleSpace[ 3 ] elif dx == 25: del sampleSpace[ -1 ] print sampleSpace 

'sampleSpace' is what I call the "iterator domain space" (if there is a more suitable word / phrase, I know the lemma).

What I am doing is removing the values ​​from it while the "dx" iterator is working through it.

Here is what I expect from the code:

 Iteration versus element being pointed to (*): 0: [*0, 1, 4, 9, 16, 25, 36] 1: [0, *1, 4, 9, 16, 25, 36] ( delete 2nd and 5th element after this iteration ) 2: [0, 4, *9, 25, 36] 3: [0, 4, 9, *25, 36] ( delete -1th element after this iteration ) 4: [0, 4, 9, 25*] ( as the iterator points to nothing/end of list, the loop terminates ) 

.. and here is what I get:

 [0, 1, 4, 9, 16, 25, 36] 0 1 9 25 [0, 4, 9, 25] 

As you can see, what I expect is what I get, which contradicts the behavior that I had with other languages ​​in this scenario.

Therefore - I wanted to ask you if there is any rule like “iterator becomes invalid if you mutate its space during iteration” in Python?

How safe (documented behavior?) In Python to do such things?

+4
source share
3 answers

From the Python tutorial :

An incorrect sequence change is repeated in a loop (this can only happen for mutable sequence types such as lists). If you need to change the list that you are repeating (for example, to duplicate selected items), you must iterate over the copy. The slice designation makes this particularly convenient:

 >>> for x in a[:]: # make a slice copy of the entire list ... if len(x) > 6: a.insert(0, x) ... >>> a ['defenestrate', 'cat', 'window', 'defenestrate'] 
+6
source

Generally speaking, no, it is unsafe, and you can get unpredictable behavior. Iterators are not required to behave in a certain way under these conditions.

What happens in your example:

 # list is [0, 1, 4, 9, 16, 25, 36] if dx == 1: # we're at index 1 when this is true del sampleSpace[ 1 ] # we've removed the item at index 1, and the iterator will move to the next valid position - still index 1, but in a mutated list. We got lucky in this case # the list now contains [0, 4, 9, 16, 25, 36] del sampleSpace[ 3 ] # we remove the item at index 3 which is (now) value 16 # the list now contains [0, 4, 9, 25, 36] elif dx == 25: del sampleSpace[ -1 ] # we remove the final item, list now looks like # the list now contains [0, 4, 9, 25] 
+1
source

What do you mean by security? There are no errors in your code, but this is of course a great feature, think about it:

 >>> a = range(3) >>> for i in a: del a Traceback (most recent call last): File "<pyshell#13>", line 2, in <module> del a NameError: name 'a' is not defined >>> a [0, 1, 2] >>> for i in a: del a[i+1] Traceback (most recent call last): File "<pyshell#27>", line 2, in <module> del a[i+1] IndexError: list assignment index out of range 

It is not clear why you want to do this, but there are no additional rules that apply to iterators. They act just like any other type.

0
source

Source: https://habr.com/ru/post/1311724/


All Articles