Seite 1 von 1
Elemente löschen aus Objektliste
Verfasst: Donnerstag 8. Dezember 2022, 21:50
von Sven7913
Hallo allerseits,
ich habe folgendes Problem:
Ich habe eine Liste, welche mittels for-Schleife eine bestimmte Anzahl an Klassenobjekten beinhaltet:
Code: Alles auswählen
orcs = list()
for i in range(20):
orcs.append(orcObjects.orcInitiateAdult())
print(orcs[i])
Die Objekte der Klasse orcInitiateAdult beinhalten bestimmte Attribute. Nun möchte ich eine Abfrage einbauen, welche sämtliche Objekte aus der Liste löscht, welche in einem bestimmten Attribut einen bestimmten Wert haben.
Ich habe es mit dieser Funktion versucht:
Code: Alles auswählen
def removeOrc():
for num in orcs:
if num.hp == 0:
orcs.remove(num)
Leider ist das einzige was passiert, dass anscheinend willkürlich ein paar der Objekte in der Liste gelöscht werden, allerdings nicht die, die beim Attribut hp den Wert 0 haben.
Da die Elemente der Liste keinen Namen, sondern lediglich den Speicherplatz bei der automatischen Generierung der Liste erhalten haben (
Code: Alles auswählen
<orcObjects.orcInitiateAdult object at 0x000001467A4B8A60>
), wüsste ich nicht, wie ich sonst gezielt auf einzelne Objekte in der Liste zugreifen könnte. Oder ist es möglich, über eine Funktion herauszufinden, an welcher Stelle in der Liste das einzelne Objekt steht und so das Objekt gezielt aus der Liste zu löschen?
Re: Elemente löschen aus Objektliste
Verfasst: Donnerstag 8. Dezember 2022, 23:23
von __deets__
Das ist ein Standardproblem. Eine Collection zu modifizieren, während man sie traversiert, ist nicht möglich - zumindest mit den gegeben Implementierungen. Das robuster zu machen, würde zu viel kosten.
Aber es geht auch ohne. Der einfachste Weg: neue Liste nur mit den gewünschten Objekten erstellen, und die bleibt erhalten.
Dein Code suggeriert auch die Verwendung dung globaler Variablen, weil du in deiner Funktion Namen aus dem nichts holst. Gewöhn dir das erst gar nicht an. Übergib Parameter, und gib berechnete Werte per return zurück.
Re: Elemente löschen aus Objektliste
Verfasst: Donnerstag 8. Dezember 2022, 23:51
von grubenfox
__deets__ hat geschrieben: Donnerstag 8. Dezember 2022, 23:23
Das ist ein Standardproblem. Eine Collection zu modifizieren, während man sie traversiert, ist nicht möglich - zumindest mit den gegeben Implementierungen. Das robuster zu machen, würde zu viel kosten.
Da könnte man noch mal drüber sprechen...
... und hier drüber:
Code: Alles auswählen
def removeOrc():
for num in orcs[:]:
if num.hp == 0:
orcs.remove(num)
Der Unterschied ist das [:] bei der for-Schleife.
Re: Elemente löschen aus Objektliste
Verfasst: Donnerstag 8. Dezember 2022, 23:57
von __deets__
@grubenfox: soll das im Widerspruch zu meiner Aussage stehen? Du drückst dich eher kryptisch aus. Wenn ja: ist Quatsch. Denn [:] erzeugt nunmal eine Kopie. Also modifiziert man nicht die Collection, über die man iteriert.
Und als Bonus hast du jetzt die Laufzeit gegenüber meinem Ansatz von O(n) auf O(n**2) erhöht, denn auf Listen ist remove seinerseits O(n).
Re: Elemente löschen aus Objektliste
Verfasst: Freitag 9. Dezember 2022, 00:26
von grubenfox
@__deets__: kein Widerspruch, nur als Ergänzung. Ohne Kopie geht es nicht... und [:] ist eine 'billige' [wenig Codeänderungen] Möglichkeit zu einer Kopie einer Liste zu kommen. Mit Nachteilen.
An die Laufzeit hatte ich jetzt noch nicht gedacht, da hatte ich erst mal nur den Speicherverbrauch für die komplette (flache) Kopie der Liste im Hinterkopf. Da hat man bei deinem Ansatz nur Kopien der Objekte die man auch wirklich behalten möchte. Darum auch die Bitte um ein Gespräch.
Re: Elemente löschen aus Objektliste
Verfasst: Freitag 9. Dezember 2022, 00:38
von __deets__
Der Unterschied zu meinem Ansatz: der erstellt eine Kopie mit mit den gewünschten Elementen. In einem Rutsch.
Du erstellst eine Kopie, iterierst über die, und entfernst jedes Element mit einer linearen Suche. Dadurch in der Summe quadratisch, und das ist leider wirklich schlecht. Der „Wert“, dass es nur drei Zeichen mehr sind, verblasst dagegen.
Re: Elemente löschen aus Objektliste
Verfasst: Freitag 9. Dezember 2022, 06:48
von Sirius3
@grubenfox: weder der Speicherbedarf, noch die Laufzeit noch die minimale Änderung sind hier entscheiden.
Die entscheidende Frage ist, wie verständlich ist der Code: im einen Fall wird eine Liste mit den gewünschten Objekten erzeugt, im anderen Fall wird eine Kopie erzeugt, um in der ursprünglichen Liste die nicht gewünschten Objekte herauszulöschen. Um das zu verstehen muss man zweimal um die Ecke denken.
Re: Elemente löschen aus Objektliste
Verfasst: Freitag 9. Dezember 2022, 09:35
von Sirius3
@Sven7913: Die Namensgebung ist für das Verständnis eines Programmcodes sehr wichtig. Irreführende Namen sind noch schlimmer als einfach nur kryptische Namen.
Es gibt in Python eine Namenskonvention, dass Module, Variablennamen und Funktionen komplett_klein geschrieben werden, und Klassen MitGroßenAnfangsbuchstaben.
In Python ist alles ein Objekt, ein Modul orcObjekts zu nennen, wäre ja nur dann sinnvoll, wenn es tatsächlich Dinge enthalten würde, die ausschließlich Orcs benutzen, eine Orc-Axt, ein Orc-Ohrring etc. Da scheint aber ein erwachsener Orc in dem Modul definiert zu werden.
Klassen werden nach Dingen benannt, orcInitiateAdult ist aber eine Tätigkeit. Der passende Name wäre als AdultOrc.
In removeOrc benutzt Du `num` um einen Orc zu bezeichnen. Das ist irreführend, denn mit num würde man eine Zahl assoziieren.
Man benutzt keine kryptischen Abkürzungen. hp -> health_points.
Re: Elemente löschen aus Objektliste
Verfasst: Freitag 9. Dezember 2022, 11:04
von __blackjack__
@Sven7913: Um das mit den Abkürzungen noch mal zu unterstreichen: `hp` steht natürlich für `hit_points` und hier werden nicht die toten Orcs ausgefiltert, sondern die, die einfach zu erschöpft sind, um noch mal zuzuschlagen.
Was immer es ist, es wäre auch gut wenn man das im Funktionsnamen erkennen könnte. Also `remove_dead_orcs()` oder `remove_exhausted_orcs()` zum Beispiel. Oder `remove_orcs_without_homepages()`.
Der Namenszusatz `object` oder `objects` mach übrigens nur Sinn falls der ausserhalb der Programmiersprache, also in der Problemdomäne, eine Bedeutung hat. innerhalb von Python ist der sinnfrei. Den könnte man an alles anhängen, denn alles was man an einen Namen binden kann ist in Python ein Objekt. Das im Namen zu erwähnen, bringt dem Leser keinen Mehrwert.
Den Indexzugriff in die Liste würde ich persönlich nicht machen. Man braucht Indexzugriffe in Listen relativ selten. Wenn dann würde ich hier auch nicht `i` benutzen, sondern -1, denn das drückt besser aus, dass man das letzte Element meint, und es funktioniert auch falls man in dem Code nicht mit einer leeren Liste startet. Aber wie gesagt, eigentlich würde ich das ohne Index machen:
Code: Alles auswählen
orcs = []
for _ in range(20):
orc = AdultOrc()
print(orc)
orcs.append(orc)
Mir scheint das aber unnötig umständlich geschrieben zu sein, nur um da ein `print()` für Debuggingzwecke rein zu basteln. Denn eigentlich wäre das erstellen von 20 Orcs eine einfache „list comprehension“:
Da könnte man am Ende die ganze Liste per `print()` ausgeben, oder mit `pprint()` aus dem `pprint()`-Modul in der Standardbibliothek, oder mit `pprint()` oder `cpprint()` aus dem externen `prettyprinter`-Modul.
Oder, falls man wirklich die einzelnen erzeugten Werten zu dem Zeitpunkt sehen will, würde sich so etwas wie das externe `icecream`-Modul anbieten. Mit dessen `ic`-Funktion wird das Objekt nicht nur ausgegeben, sondern auch der Ausdruck der dazu geführt hat, und die Funktion gibt ihr Argument als Ergebnis zurück, so dass man das auch einfach mitten in anderen Ausdrücken, wie beispielsweise der „list comprehension“, anwenden kann.
Code: Alles auswählen
from icecream import ic
...
orcs = [ic(AdultOrc()) for _ in range(20)]