__new__ vs. __init__

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
cofi
Moderator
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Freitag 6. Mai 2011, 17:58

proofy hat geschrieben:Und habe jetzt wohl dadurch einen weiteren Sinn für __new__ gefunden.
Wenn man sicher gehen will, dass ein Attribut wirklich existieren soll, sollte man es wohl in der __new__ erzeugen und
Erm. Und warum sollte es deiner Meinung der Initialisierung in `__init__` ueberlegen sein?
BlackJack

Freitag 6. Mai 2011, 18:51

@proofy: Ich schliesse mich der Frage von cofi an.

Ausserhalb vom Ableiten von "immutable" Typen und Metaprogrammierung fällt mir nur noch das Singleton-Entwurfsmuster als Anwendung ein. Von Metaklassen lasse ich in der Regel die Finger, weil man IMHO mit solcher "Magie" vorsichtig und sparsam umgehen sollte. Von nicht veränderbaren Typen leite ich anscheinend nicht ab, und Singletons setze ich um in dem ich einfach von solchen Klassen nur ein Exemplar erstelle und gut ist. Ich glaube ich habe noch nie in "normalem" Quelltext eine `__new__()`-Methode implementiert. Wenn Du das gewohnheitsmässig machst, oder demnächst machen willst, ist das IMHO ziemlich ungewöhnlich. Denn auch in anderer Leute Quelltext habe ich bisher nur sehr vereinzelt `__new__()`-Methoden gesehen.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Freitag 6. Mai 2011, 19:10

Ich habe __new__ bisher auch nur einmal benutzt http://www.python-forum.de/viewtopic.php?f=1&t=26077, da ich es dort quasi als Klassen-Fabrik nutze, was man sich auch anders hätte lösen können.

Ansonsten schließe ich mich den Vorednern auch an, da ist nichts *überlegenes* an "__new__". Es hat schlicht einen anderen Aufgabenbereich.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
proofy
User
Beiträge: 32
Registriert: Montag 21. März 2011, 12:47

Montag 9. Mai 2011, 12:00

Klassenfabrik ist z.B. eine gute Gelegenheit. Ich meine ja nicht, dass man es dauernd machen soll.
Bei mir war es z.B. aus json direkt ein Objekt aus einer übergebenen Klasse zu erzeugen.
Auch mit der Kommunikation mit "Fremdsystemen" wie .net scheint es sinnvoll zu sein, weil dort die "Fabriken" gerne __new__ aufrufen als __init__ .
lunar

Montag 9. Mai 2011, 12:05

Für solche Zwecke würde ich eher Klassenmethoden einsetzen, e.g. "Foo.from_json(json)". Explizit, weniger magisch und daher meines Erachtens besser lesbar und leichter verständlich.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 9. Mai 2011, 15:22

proofy hat geschrieben:Klassenfabrik ist z.B. eine gute Gelegenheit.
Da finde ich es oftmals sinnvoller eine Funktion eine Klasse zurückgeben zu lassen, statt Metaprogramming zu machen.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
proofy
User
Beiträge: 32
Registriert: Montag 21. März 2011, 12:47

Dienstag 10. Mai 2011, 16:37

Also irgendwie driftet es doch jetzt in eine Art Glaubenskrieg ab oder ich verstehe es mal wieder nicht?

__new__ ist doch __init__ so überlegen wie Äpfel Birnen, also gar nicht und 2 völlig verschiedene Dinge.
__new__ ist doch eine Klassenmethode oder?
Mein Beispiel würde ohne __new__ nicht funktionieren.

Muss in __init__ auf jeden Fall immer alles initialisiert werden?
Wenn nicht, finde ich ein __new__ recht einfach und überhaupt nicht magisch (im Gegensatz zu lamda ;)
So wird ein __repr__ immer funktionieren.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Dienstag 10. Mai 2011, 16:48

Nochmal, du erstellst da ein neues Klassenobjekt/typ von dem du dann instanzierst. Das ist dann nicht mehr die Klasse die du angelegt hast, sondern eine Kopie davon und das jedesmal. Also in meinen Augen ist das was völlig anderes.
Python Dokumentation hat geschrieben:Class Types
Class types, or “new-style classes,” are callable. These objects normally act as factories for new instances of themselves, but variations are possible for class types that override __new__(). The arguments of the call are passed to __new__() and, in the typical case, to __init__() to initialize the new instance.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

Dienstag 10. Mai 2011, 17:34

@proofy: Das mit dem "überlegen sein" kommt von Deiner Behauptung `__new__()` würde irgendwie mehr garantieren bezüglich der Existenz von Attributen. Wobei ich nicht verstehe was Du damit meinst? In der `__init__()` kann man ein Objekt auch nur halb initialisieren wenn man lustig ist. Das geht mit `__new__()` aber genau so.

`__new__` ist per se nicht "magisch" aber es wird (nur) für Magie benötigt. Und wenn man keine Magie damit implementiert, kann man auch `__init__()` verwenden. Dann ist `__new__()` einfach nur das falsche, da unnötig komplexere, Werkzeug.

Welches Beispiel meinst Du denn jetzt was ohne `__new__()` nicht ginge?
proofy
User
Beiträge: 32
Registriert: Montag 21. März 2011, 12:47

Donnerstag 26. Mai 2011, 14:06

Natürlich kann man auch alles in der __init__() machen, umgekehrt kenne ich bisher keinen Grund immer auf __new__() zu verzichten.

Das Beispiel kam aus einem Beitrag von mir vorher.

Properties lesen, die nicht gesetzt wurden. Man könnte hier auch die Abfrage in __init__ besser gestalten, damit ein default-Wert gesetzt wird.
proofy hat geschrieben:

Code: Alles auswählen

class Project(object):

    def __init__(self, inName = "", inProjectNumber=0):
        if inName:
            self.__name = str(inName)
        if inProjectNumber:
            self.__projectNumber = inProjectNumber

    def __new__(cls, *args, **kwds):
        instance = super(Project, cls).__new__(cls)
        instance.__name = None
        instance.__projectNumber = -1
        return instance


    def __repr__(self):
        return "Project: \n{\n Name: %s\n ProjectNumber: %d\n }" % (str(self.Name), self.ProjectNumber)


    @property
    def Name(self):
        return self.__name

    @property
    def ProjectNumber(self):
        return self.__projectNumber

Zuletzt geändert von proofy am Freitag 27. Mai 2011, 09:38, insgesamt 1-mal geändert.
lunar

Donnerstag 26. Mai 2011, 14:13

@proofy: "__new__()" ist semantisch einfach die falsche Methode. Sie implementiert die Erzeugung eines Exemplars aus der Klasse, das Setzen von Attributen auf diesem Exemplar ist aber Teil der Initialisierung des Exemplars, gehört also in "__init__()".
Benutzeravatar
snafu
User
Beiträge: 5534
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Donnerstag 26. Mai 2011, 17:45

@proofy: Das, was du da machst, ist extrem unüblich. Klar, funktioniert es auf diese Weise und letztlich kann dir ja niemand vorschreiben, wie du deine Programme schreibst. Ich bin mir aber ziemlich sicher, dass du kaum Projekte finden wirst, die so vorgehen wie du. Wenn ich so etwas in Code sehen würde, fände ich es eher abschreckend. Auf jeden Fall ist es ein Stolperstein für den Leser. Ich sehe auch nicht, welchen Vorteil dies gegenüber dem üblichen Weg mittels `__init__()` haben soll.
shcol (Repo | Doc | PyPi)
proofy
User
Beiträge: 32
Registriert: Montag 21. März 2011, 12:47

Freitag 27. Mai 2011, 09:35

@lunar Gehören die Attribute beim Erzeugen eines Objektes nicht dazu?
Und wenn ja, welchen Wert sollen diese dann besitzen? Sinnvoll wäre z.B. None . Immerhin würde dann aber das Attribut existieren.
Initialisiert wird es dann mit __init__ . Finde ich eine Runde Sache. Den Schritt mehr finde ich schon ganz nützlich, muss ich aber auch nicht immer machen. Wenn ich z.B. zum Zeitpunkt der Initialisierung alle Attribute kenne und auch einen Initialwert passend dazu, mache ich natürlich auch nur ein __init__, also so zu 95% ;)
BlackJack

Freitag 27. Mai 2011, 09:55

@proofy: Nein die Attribute gehören zur Erzeugung des Objekts nicht dazu. Das wird in der `__init__()` gemacht. Warum die Attribute unbedingt vor der `__init__()` existieren sollten, ist mir ehrlich gesagt nicht ganz klar. Was genau bringt das, ausser dass Du mehr schreiben musst, und jeder der schon etwas länger Python programmiert, sich fragt warum das so umständlich gemacht wird!? `__new__()` ist dazu da um schon bei der Erzeugung des Objekts eingreifen zu können, was bei der `__init__()` nicht geht. Wenn man das in `__new__()` aber gar nicht nutzt, sollte man `__new__()` nicht implementieren. Attribute in `__new__()` an `None` zu binden um sie gleich danach in der `__init__()` an einen anderen Wert zu binden, finde ich eher eckig als rund. Irgendwie sinnfrei.
proofy
User
Beiträge: 32
Registriert: Montag 21. März 2011, 12:47

Freitag 27. Mai 2011, 10:03

Bin ja der gleichen Meinung, aber gut zu wissen, dass man es könnte.
Überladen von Methoden funktioniert ja nicht bei Python. Vielleicht ist das so eine Art "Hilfskrücke".
Mit __new__() ohne Übergabeparameter zum Erzeugen des Objektes und Standardwerten in den Attributen und mit __init(json)__ das Objekt erzeugen und gleich Werte zuweisen. Mal so ein Vorschlag :roll: und ja, es stimmt, es ist Javastyle ;)
Sind Schlangen eigentlich Kaffeetrinker?
Antworten