in-place-Veränderung eines Objektes

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
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

Ich möchte ein Objekt "in place" verändern, aber wie man leicht sehen kann, ist die Vorgehensweise in folgendem Beispiel falsch:

Code: Alles auswählen

class IList(list):
   def transform(self):
      #self.sort()  #wie gewuenscht, aber *nicht immer vorhanden*
      self = sorted(self)  #veraendert self nicht wirklich
      print("intern:",self)  #gibt gewuenschtes Ergebnis aus

Code: Alles auswählen

ll = IList([4,2,5,3])
print(ll)
ll.transform()
print(ll)  #gibt weiterhin [4,2,5,3] aus
Nicht immer soll ein Objekt bloß geordnet werden, und bei längeren Abänderungen ist es in der Regel unvermeidlich, das gewünschte Ergebnis irgendwo zwischenzuspeichern. Das soll der Anwender aber nicht merken: das Objekt, dem die Methode angehört, soll automatisch abgeändert werden.

Wie macht man das? Oder macht man das nie?
Zuletzt geändert von Goswin am Donnerstag 15. Dezember 2011, 15:11, insgesamt 2-mal geändert.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Goswin hat geschrieben:

Code: Alles auswählen

      self = sorted(self)  #veraendert self nicht wirklich
Dann mach mal Folgendes:

Code: Alles auswählen

        self[:] = sorted(self)
deets

Warum nicht "self.sort", die Methode, die Listen in-place sortiert?
Rekrul
User
Beiträge: 78
Registriert: Dienstag 7. Dezember 2010, 16:23

@Goswin

Code: Alles auswählen

self[:] = sorted(self)
... ist keine in-place Sortierung. So wird dem Programmierer lediglich 'xy = xy.transform()' erspart. Um richtig 'in-place' zu sortieren musst du schon self.sort verwenden. Sollte sort nicht immer vorhanden sein, dann musst du wohl selbst 'in-place' sortieren.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Rekrul hat geschrieben:@Goswin

Code: Alles auswählen

self[:] = sorted(self)
... ist keine in-place Sortierung.
Wobei vom TE wohl eher der Erhalt der Objektidentität gemeint war und weniger das tatsächliche interne Vorgehen. Von daher bietet es sich durchaus an, den *Inhalt*, nicht aber das Objekt an sich zu erneuern. Wozu das gut ist bzw warum nicht einfach grundsätzlich von `list` geerbt wird, ist natürlich eine andere Frage...
deets

@snafu

Es wird ja von list geerbt.

Wobei ich erst jetzt den "nicht immer vorhanden" Kommentar sehe - und nicht verstehe...
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

deets hat geschrieben:Wobei ich erst jetzt den "nicht immer vorhanden" Kommentar sehe - und nicht verstehe...
Tja, es ist schon mal schwer, den Lesern eine Frage umfassend und gleichzeitig einfach zu gestalten.

Es geht mir nicht ums Ordnen einer Liste, es geht mir um eines meiner komplizierteren Objekte, dass ich abändern will. Meine Methode dafür ist viel zu lang als dass ihr sie wirklich lesen wollt, und 99% davon ist für die Fragestellung völlig irrelevant. In dieser Methode erstelle ich ein neues Objekt, das den Platz des ursprünglichen Objektes einnehmen soll. Dem Anwender will ich nur die Syntax

Code: Alles auswählen

objekt = objekt.transformiert()
ersparen, was ich mit einem einfachen "return" in der Methode leicht erreichen könnte. Er soll aber

Code: Alles auswählen

objekt.transformiere()
schreiben dürfen, um anstelle des Bezeichners "objekt" auch komplizierte Ausdrücke nur einmal schreiben zu müssen.
deets

@Goswin

Siehste, mit ein bisschen Muehe und ohne verwirrendes Beiwerk versteht man die Frage auch.

Und die Antwort ist ganz einfach: nein, es gibt keine Magie, durch die man ein neues Objekt erzeugen, und alle Referenzen auf ein anderes Objekt dadurch ersetzen kann.

Ob das aber ueberhaupt eine relevante Frage ist, wage ich mal zu bezweifeln. Denn du kannst deine transform-Funktion ja schreiben, wie's dir beliebt - und einfach jedweden internen Zustand aendern, ganz nach gusto.

Viel wichtiger ist die Frage, ob die API die du deinen Benutzern da anbietest sinnvoll ist. Das Beispiel von list.sort und die spaetere Einfuehrung von sorted zeigen, dass es eigentlich oft besser ist, eine nicht-modifizierende API anzubieten, die ein neues Objekt erstellt. Dann ist es dem Nutzer ueberlassen, womit er arbeiten will. Das laesst sich natuerlich nicht 100%ig verallgemeinern, sonst waere Python ja streng funktional.

Aber ich finde es meistens deutlich besser, explizit zu entscheiden, wann ich ein veraendertes Objekt nur temporaer brauche, oder es eine bestehende Referenz ersetzen soll.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Goswin:
Du kannst Dir mit einer Wrapperklasse behelfen, die das Zielobjekt als Attribut mitschleift. Ein 'transform()' erstellt Dein neues Zielobjekt nach Deinem Gusto im Wrapperobjekt und bindet es an das Attribut. Wichtige Attribute des Zielobjektes kannst Du auf das Wrapperobjekt ummappen.

Allerdings ist das ein bisschen smelly, prinzipiell schliesse mich deets Ausführungen an.
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

@deets: Ich glaube, du hast recht, wenn es nur um die Syntax geht. Ich könnte ja immer

Code: Alles auswählen

system = alg.def[2:,var.ind].tudas(par=str(3)).syst
system = system.abwandle()
mit anscheinend derselben Auswirkung schreiben.

Wenn ich ein wirklich großes Objekt habe (und das wird so sein), dann darf das aber auch in der Methode nicht kopiert werden. Vielleicht sollte ich eine Funktion schreiben, etwa

Code: Alles auswählen

abwandle(system)
anstelle von einer Methode

Code: Alles auswählen

system.abwandle()
Oder, wie <jerch> gerade vorschlägt, eine Wrapperklasse (diese Technik muss ich noch lernen).
deets

@Goswin

Der Vorteil einer extra Funktion vs. einer Methode will mir nicht einleuchten - im Gegenteil. Da musst du dann in externem Code Wissen ueber dein Objekt haben, oder aber du delegierst doch nur wieder. Und der Import wird auch nicht besser.

Wichtig ist eben, dass ding.abwandle() nix zurueckgibt - so wie list.sort das auch nicht tut. Denn nur dann kommt man nicht in die Gefahr zu glauben, da waere eine Kopie erstellt worden.

Aber wenn ich mal fragen darf: was ist denn 'richtig gross'?
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

deets hat geschrieben:Aber wenn ich mal fragen darf: was ist denn 'richtig gross'?
@deets: Ja, du darfst fragen.

Ich suche (unter anderem) die Smith-Normalform ganzzahliger Matrizen mit bis zu 30'000'000_Zeilen und 100'000_Spalten, das wären also 3'000'000'000'000 Einträge (die allermeisten davon freilich_0). Ob das wohl groß genug ist :wink: ? Ich benutze numpy.

Ich erwarte nun nicht, derart große Matrizen wirklich zu meistern, aber das Grundanliegen ist: je größer desto besser. Ich benutze Python zwar nur für einen Prototypen, aber auch der sollte nicht langsamer sein als unbedingt nötig...

Vielen Dank für dein Interesse!
Antworten