Seite 1 von 1

phänomen bei interration?

Verfasst: Sonntag 17. April 2011, 00:02
von mrshoul
Hi,
nach vielen eignen Versuchen, Nachschlagen in verschiedenen Büchern und Suchanfragen im Forum, wage ich es doch hier eine Frage zu stellen.

Code: Alles auswählen

>>> a = [i for i in range(10)]
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> for i in a:
	if i < 2:
		a.remove(i)

		
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9]
# Wiso wird nur die Zahl 0 und nicht auch die Zahl 1 entfernt?
# Nochmal mit del:
>>> a = [i for i in range(10)]
>>> for i in a:
	if i < 2:
		del a[i]

		
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> # Gleiches Ergebnis
>>> # Prüfung:
>>> a[0]
1
>>> a[0]<2
True
Könnte mir das bitte jemand erklären?

Grüße,

mrshoul

Re: phänomen bei interration?

Verfasst: Sonntag 17. April 2011, 00:26
von Leonidas
Tipp: Nicht die Liste modifizieren über die man iteriert.

Code: Alles auswählen

a = [element for element in a if element >= 2]

Re: phänomen bei interration?

Verfasst: Sonntag 17. April 2011, 00:35
von mrshoul
Danke Leonidas!

Re: phänomen bei interration?

Verfasst: Sonntag 17. April 2011, 09:43
von snafu
Gibt es für dieses Verhalten eigentlich eine definierte Erklärung? Ansonsten wäre es ja vielleicht nicht schlecht, wenn Python das Modifizieren während des Iterierens gänzlich verbieten würde, damit es nicht zu bösen Überraschungen kommt.

Re: phänomen bei interration?

Verfasst: Sonntag 17. April 2011, 10:20
von EyDu
Wie möchtest du eine Modifizierung verhindern? Wenn man direkt über eine Liste iteriert ist das kein Problem, aber sobald man über Indizes geht, kann natürlich alles mögliche passieren und sogar sinnvoll sein.

Re: phänomen bei interration?

Verfasst: Sonntag 17. April 2011, 10:56
von BlackJack
@snafu: Was meinst Du mit "definierter Erklärung"? Der Iterator den ``for`` anfordert ist ja unabhängig, dass heisst der bekommt nichts davon mit wenn die Liste verändert wird. Der zählt bei jedem Aufruf von `__next__()` einfach stur den Index hoch über den er auf die Elemente zugreift. Wenn man die Positionen der Elemente zwischen solchen Aufrufen ändert, bekommt der Iterator davon nichts mit.

Wenn Du das verhindern möchtest, müsstest Du so etwas wie einen "Veränderungszähler" auf Listen einführen, der bei jeder verändernden Listenoperation hochgezählt wird und bei jedem Iteratorzugriff mit dem Stand verglichen wird, als der Iterator erstellt wurde. Falls unterschiedlich müsste der Iterator eine Ausnahme auslösen das man da etwas böses getan hat. Aber da fangen die Probleme ja schon an -- soll das wirklich bei *jedem* verändern der Liste passieren? Auch wenn man Elementen neu zuweist? Oder wenn man Elemente entfernt über die noch nicht iteriert wurde? Das würde das ganze Iterator-Protokoll komplexer machen. Ausserdem wäre es eine nicht rückwärts kompatible Änderung.

IMHO ist das jetzige Verhalten eine gute Mischung aus KISS-Prinzip und dem Vertrauen auf den Programmierer, dass er weiss was er da tut.

Re: phänomen bei interration?

Verfasst: Sonntag 17. April 2011, 11:19
von snafu
Ich wollte eigentlich nicht sagen, dass es verändert werden soll. Mein Fokus lag auf der Frage nach der Implementierung.

Verstehe ich den Ablauf so richtig:

(1) Zähler auf Index 0. Erstes Element der Liste auf Index 0.
(2) Element auf Index 0 wird gelöscht. Zweites Element rutscht daher von Index 1 auf Index 0.
(3) Zähler springt auf Index 1, wo aber nun das verschobene Element vom ursprünglichen Index 2 sitzt.
(4) Verschobenes Element vom ursprünglichen Index 1 wurde übersprungen und bleibt daher in der Liste erhalten.

EDIT: Ach, ich bin doof. Sehe jetzt erst, dass ja der Index genutzt wird. Dann ist das ja klar. Ich hätte gestern vielleicht weniger Erdbeer-Bowle trinken sollen. :mrgreen: