Ist sicher (dokumentiertes Verhalten?), Um die Domäne eines Iterators in der Ausführung zu löschen

StackOverflow https://stackoverflow.com/questions/2965351

Frage

Ich wollte wissen, ob sicher ist (dokumentiertes Verhalten?), Um den Domänenraum eines Iterators in der Ausführung in Python zu löschen.

Betrachten Sie den 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" ist das, was ich "den Domänenraum eines Iterators" nenne (wenn es ein geeigneteres Wort/Phrase gibt, weiß Lemme).

Was ich tue, ist, Werte daraus zu löschen, während der Iterator 'DX' es durchläuft.

Hier ist, was ich vom Code erwarte:

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 )

.. und hier ist was ich bekomme:

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

Wie Sie sehen können - was ich erwarte, ist das, was ich bekomme - die widerspricht dem Verhalten, das ich in einem solchen Szenario von anderen Sprachen hatte.

Daher - ich wollte Sie fragen, ob es eine Regel wie "Der Iterator wird ungültig, wenn Sie seinen Raum während der Iteration mutieren" in Python?

Ist es sicher (dokumentiertes Verhalten?) In Python, solche Dinge zu tun?

War es hilfreich?

Lösung

Aus Das Python -Tutorial:

Es ist nicht sicher, die in der Schleife iterierte Sequenz zu modifizieren (dies kann nur für veränderliche Sequenztypen wie Listen geschehen). Wenn Sie die Liste, über die Sie iteriert werden, ändern müssen (z. B. um ausgewählte Elemente zu duplizieren), müssen Sie eine Kopie iterieren. Die Scheibennotation macht dies besonders bequem:

>>> 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']

Andere Tipps

Im Allgemeinen nein, es ist nicht sicher und Sie können unvorhersehbares Verhalten erhalten. Iteratoren müssen sich unter diesen Umständen nicht auf bestimmte Weise verhalten.

Was in Ihrem Beispiel passiert, ist

# 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]

Was meinst du mit sicher? Ihr Code erhoben keine Fehler, aber er ist natürlich eine ausgeprägte Möglichkeit. Bedenken Sie Folgendes:

>>> 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

Es ist nicht klar, warum Sie dies tun möchten, aber es gibt keine zusätzlichen Regeln für Iteratoren. Sie handeln genau wie jeder andere Typ.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top