Loop mit __new__

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

Montag 16. Februar 2009, 11:22

Folgender Code ist falsch (erzeugt unendliche Rekursion), aber warum bloss?

Code: Alles auswählen

class Klob(object):
  def __new__(cls,folge=None):
    if folge==None: return Klob(folge=31415926535)
    else: return Klob(folge=folge)
  def __init__(self,folge): self.folge=folge
Zuletzt geändert von Goswin am Montag 16. Februar 2009, 12:04, insgesamt 2-mal geändert.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Montag 16. Februar 2009, 11:37

Weil ein `Foo()` immer __new__ aufruft und du in __new__ wiederum __new__ aufrufst.

Warum eigentlich nicht so?

Code: Alles auswählen

class Klob(object):
    def __init__(self,folge=31415926535): self.folge=folge
Und lass mal das Fett-Schreiben und brüllen, das ist unhöflich.
Benutzeravatar
Goswin
User
Beiträge: 361
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen

Montag 16. Februar 2009, 12:01

Ok, vielen Dank!

Ich greife mal zurück auf meine altbewährte factory-Funktion, die lässt sich offenbar nicht so ohne weiteres durch __new__ ersetzen.
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Montag 16. Februar 2009, 12:06

Moin,

kommt ganz drauf an. Aber Factory-Funktionen sind wohl meistens besser. In __new__ ein nicht offensichtliches Verhalten reinzuprogrammieren kann für Verwirrung sorgen. Und es besteht ja die Chance, dass du die Klasse nochmal wo anders benutzen willst - ohne das spezielle Verhalten. Dann hast du erstmal Pech und musst Code ändern ;-).

Gruß,
Manuel
Benutzeravatar
Goswin
User
Beiträge: 361
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen

Montag 16. Februar 2009, 12:33

Hier ist mir noch ein Trick eingefallen:

Code: Alles auswählen

class Klob(object):
  def __init__(self,folge):
    assert not folge==None
    self.folge=folge
  def __repr__(self): return "Klob("+str(self.folge)+")"
  #viele_weitere_wichtige_Methoden


_Klob=Klob
class Klob(_Klob):
  #verfuegt ueber saemtliche Methoden vom alten Klob
  def __new__(cls,folge=None):
    if folge==None: return _Klob(folge=31415926535)
    else: return _Klob(folge=folge)
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Montag 16. Februar 2009, 12:54

Ich verstehe nicht was du mit diesem Konstrukt erreichen willst.
Also mich würde zum Beispiel schonmal irritieren
das ich von der neuen Klasse "Klob" keine Instanz bekomme sondern immer
nur von der alten Klasse. Wo ist der Vorteil?
Benutzeravatar
Goswin
User
Beiträge: 361
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen

Montag 16. Februar 2009, 13:28

Zap hat geschrieben:Wo ist der Vorteil?
Ganz meine Frage. Ich habe bisher keine Ahnung, wofür die Methode __new__ gut sein soll, und suche nach Anwendungsbeispielen, die alle verkrampft ausfallen. Aber wie wir schon von Perl wissen: "There-is-more-than-one-way-to-do-it" :D. Schade, dass die Methode __init__ kein "return" oder "self=..." annimmt; das wird wohl eine Altlast von Python sein.
Benutzeravatar
snafu
User
Beiträge: 5521
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Montag 16. Februar 2009, 13:42

Ich glaube du denkst einfach nur zu kompliziert. Wenn ein Standard-Wert für "folge" verwendet werden soll (d.h. dieser Wert gilt auch dann, wenn bei der Initialisierung nichts für "folge" angegeben wird), dann macht man das üblicherweise so:

Code: Alles auswählen

class Klob(object):
    def __init__(self, folge=31415926535):
        self.folge = folge
EDIT: Oh, wurde schon gesagt.
shcol (Repo | Doc | PyPi)
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 16. Februar 2009, 13:49

Goswin hat geschrieben:Ich habe bisher keine Ahnung, wofür die Methode __new__ gut sein soll
Wenn du das Verhalten der Klasse grundlegend ändern willst oder gar etwas anderes Zurückgeben willst oder generell seltsame Sachen.

Und ja, es ist einfach meist nicht nötig, so einfach ist das.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Montag 16. Februar 2009, 13:55

Unter "seltsame Sache" könnte man als Beispiel das Singleton-Pattern anführen. Innerhalb von __new__ sorgst du dafür, dass immer dieselbe Instanz zurückgegeben wird. Aber da es eine "seltsame Sache" ist, sollte man sowas nicht tun ;-).
lunar

Montag 16. Februar 2009, 14:08

Wtforms nutzt beispielsweise __new__, um die Klassen für Felder zu implementieren. Ein Blick in dessen Quellcode mag zur Aufklärung über mögliche Einsatzzwecke von __new__() dienen.
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Montag 16. Februar 2009, 14:16

Ich habe lediglich gelesen das es Sinn machen würde um eigenschaften von
Immutable Objects für eigene Zwecke anzupassen.
Mir kommt dabei sowas in den Sinn.

Code: Alles auswählen

In [17]: class Int16(int):
   ....:     def __new__(cls, val):
   ....:         return int.__new__(cls, val, 16)
   ....:
   ....:     def __str__(self):
   ....:         return "%X" % self
   ....:
   ....:

In [18]: Int16("10")
Out[18]: 16

In [19]: print Int16("10")
10
Ob man sowas braucht oder nicht steht auf einem anderen Blatt ;)
Benutzeravatar
Goswin
User
Beiträge: 361
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen

Montag 16. Februar 2009, 15:41

snafu hat geschrieben:Ich glaube du denkst einfach nur zu kompliziert.
Vielleicht vereinfache ich meine Beispiele zuviel.
Ich habe komplizierte Objekte, die von verschiedenen Parametern abhängen. Einer dieser Parameter heißt speicherdatei. Bei speicherdatei==None soll das Objekt neu erzeugt werden, was zeitraubend ist. Bei speicherdate<>None wird es mit Hilfe des Pickle-Moduls schnell wiederhergestellt. Um das zu realisieren, benutze ich derzeit eine Fabrikfunktion.

(Meine ursprüngliche Frage wurde von audax bereits geklärt, wir wären somit hier beim Smalltalk :D )
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Dienstag 17. Februar 2009, 00:25

Goswin hat geschrieben:Folgender Code ist falsch (erzeugt unendliche Rekursion), aber warum bloss?
Wie schon erwähnt wegen dem rekursiven Aufruf.

Versuchs mal so:

Code: Alles auswählen

class Klob(object):
  def __new__(cls,folge=None):
    if folge==None: return object.__new__(cls, folge=31415926535)
    else: return object.__new__(cls, folge=folge)
  def __init__(self,folge): self.folge=folge
Für deinen Anwendungsfall ist __new__ schon das richtige Mittel.
Benutzeravatar
Goswin
User
Beiträge: 361
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen

Dienstag 17. Februar 2009, 15:56

@Darii:
Es funktioniert NICHT, wenigstens nicht so, wie es sollte. Beobachte einmal, dass man deine Definition von __new__ gänzlich fortlassen kann, ohne dass sich etwas ändert; alle Argumente von "object.__new__" außer dem ersten werden verworfen.

Aber hier habe ich *schwitz* einen weiteren Vorschlag:

Code: Alles auswählen

class Klob(object):
  def __new__(cls,folge=31415926535):
    self = object.__new__(cls)
    #
    #Instanzierung hier, abhaengig vom Wert von folge
    self.rep = "Klob("+str(folge)+")"
    #alle Anweisungen vom ursprünglichen def __init__(self)
    #
    return self

klob = Klob(folge=123);   print klob.rep
klob = Klob();   print klob.rep
Ein mögliches "def __init__(self,folge=None): pass" darf nur dann fortgelassen werden, wenn man __new__ mit einem EINZIGEN Argument aufruft (ansonsten meldet das Programm einen Fehler).
Antworten