For-Schleife: Objekt ändert sich in jeder Iteration

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
gerald123
User
Beiträge: 36
Registriert: Donnerstag 10. September 2015, 12:10

Hey, ich möchte über eine Liste iterieren, wobei sich die Länge der Liste am Ende jeder Iteration ändert -->

Code: Alles auswählen

people = ["A"]

for n in people:
    if len(people) == 3:
        print "OK", n
        break
    people.extend("A")
    
   
Würded ihr diese Methode so empfehlen, oder gibt es elegantere Wege?

Vielen Dank
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@gerald123: das Beispiel ist sinnfrei, denn das würde man ja mit:

Code: Alles auswählen

people = ["A", "A", "A"]

for n in people:
    pass
print "OK", n
oder gleich als

Code: Alles auswählen

print "OK", "A"
schreiben.
Kannst Du Dein wirkliches Problem schildern? So kann man keinen sinnvollen Rat geben.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Hey, ich möchte über eine Liste iterieren, wobei sich die Länge der Liste am Ende jeder Iteration ändert -->
Also das Beispiel macht aber was anders, nämlich eine Liste solange erweitern, bis sie drei Elemente hat. Und das geht auch anders / eleganter.

Was willst du denn wirklich vor.

Gruß, noisefloor
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@gerald123
Die elegantere Lösung ist, eine neue Liste zu erzeugen, in der die benötigten Elemente enthalten sind. Gleichzeitiges Iterieren und Verändern des Inhalts ist bei Container-Objekten fast nie eine gute Idee.
BlackJack

@gerald123: Der Beispielcode ist poblematisch wenn die die Liste bereits mehr als drei Elemente enthält. Dann hat man da nämlich eine Endlosschleife die irgendwann von einem `MemoryError` gestoppt wird, wenn die immer weiter wachsende Liste nicht mehr in den Speicher passt.

Hier mal zwei Varianten ohne über die Liste zu iterieren:

Code: Alles auswählen

In [1]: people = ['A']

In [2]: people.extend(['A'] * (3 - len(people)))

In [3]: people
Out[3]: ['A', 'A', 'A']

In [4]: from itertools import repeat

In [5]: people = ['A']

In [6]: people.extend(repeat('A', 3 - len(people)))

In [7]: people
Out[7]: ['A', 'A', 'A']
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

wenn es um die Länge geht, würde ich while mit kleiner 3 nehmen.
empty Sig
BlackJack

@harryberlin: Im gezeigten Beispiel gar kein ``while``. Wenn schon eine Schleife, dann eine ``for``-Schleife, denn es ist vor Eintritt in die Schleife ja bereits bekannt wie oft die durchlaufen werden wird.
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

soweit ich das sehe durchläuft die schleife einmal.
und dann wird die liste einmal erweitert.
und fertig.
für die 3 abfrage, sehe ich gar keine berechtigung.
deswegen war meine annahme, er will solang erweitern, bis sie eine Länge von 3 hat.
empty Sig
BlackJack

@harryberlin: Die Schleife wird 2× durchlaufen und durch die Bedingung mit den ``== 3`` abgebrochen. Ist halt gefährlich wenn die Liste schon mehr als drei Einträge enthält, weil man dann eine Endlosschleife mit einer endlos grösser werdenden Liste hat. Darum ging ich ja auch davon aus das 3 das Maximum sein sollte, und dann kann man meine bereits gezeigten Lösungen ohne explizite Schleifen verwenden oder eben eine ``for``-Schleife, denn man kann ja ausrechnen wie oft die durchlaufen werden muss.

Code: Alles auswählen

In [23]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:people = ["A"]
:
:for n in people:
:    if len(people) == 3:
:        print "OK", n
:        break
:    people.extend("A")
:<EOF>
OK A

In [24]: people
Out[24]: ['A', 'A', 'A']
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

da muss ich jetz blöd fragen, wieso durchläuft die schleife 2x, wenn people = ["A"] ist?
empty Sig
BlackJack

@harryberlin: Weil `people` nur im ersten Durchlauf (am Anfang) ``['A']`` ist. Im zweiten ist es ``['A', 'A']``. Insofern wird die Schleife 2½ mal durchlaufen, denn beim dritten mal wird am Anfang der Schleife wegen der ``== 3``-Bedingung die Schleife abgebrochen. Ich bin mir auch gar nicht sicher ob sich jede Python-Implementierung so verhalten muss, also ob das Verhalten des Iterators für Listen irgendwo festgelegt ist für den Fall das die Liste während der Iteration verändert wird.
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

hui, wieder was gelernt.
das war mir neu, dass die eingaben für die for schleife erneut geprüft werden.
deswegen hatte ich zuerst an while gedacht.
empty Sig
BlackJack

@harryberlin: Ich vermute Du hast da gerade eine falsche Vorstellung von der ``for``-Schleife, beziehungsweise ordnest dem Konstrukt selbst Code zu der nicht fest mit der Schleife verbunden ist. Die fragt das Objekt nach dem ``in``-Schlüsselwort nach einem Iterator und den dann wiederholt nach dem nächsten Element, solange bis der bei so einer Anfrage mit einer `StopIteration`-Ausnahme antwortet. Das ist die einzige Sache die von der ``for``-Schleife getestet wird. Was der Iterator macht hängt von dem Objekt ab das den auf Anfrage liefert. Also in diesem Fall was die Liste beziehungsweise der von ihr gelieferte Iterator macht:

Code: Alles auswählen

In [1]: people = ['A']

In [2]: it = iter(people)

In [3]: next(it)
Out[3]: 'A'

In [4]: people.append('B')

In [5]: next(it)
Out[5]: 'B'

In [6]: next(it)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-6-2cdb14c0d4d6> in <module>()
----> 1 next(it)

StopIteration:
Das bei ``next(it)`` nach dem `append()` nicht schon `StopIteration` ausgelöst wird, ist eine Entscheidung des Programmierers der den `list`-Datentyp implementiert hat. Der hätte sich auch anders entscheiden können. Das hat nichts mit dem Code der Implementierung für ``for``-Schleifen zu tun.
Antworten