__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.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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 (former) Modvoice
proofy
User
Beiträge: 32
Registriert: Montag 21. März 2011, 12:47

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

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

@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

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

@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: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@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.
proofy
User
Beiträge: 32
Registriert: Montag 21. März 2011, 12:47

@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

@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

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?
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@proofy: Was soll dein Konstrukt denn jetzt bitte mit dem Überladen von Methoden zu tun haben bzw inwiefern wird da etwas ausgeglichen, was einem wegen diesem nicht in Python vorhandenen Feature fehlen würde? Wenn ich "überladen" will, dann nutze ich Defaultwerte für Schlüsselwortargumente und/oder Typprüfungen innerhalb der Methode. Oder meintest du, dass du irgendwie `__new__()` nutzen willst, um `__init__()` zu überladen (was ich ziemlich wirsch fände)? Ich sehe halt nicht den Zusammenhang zwischen dem Thema dieses Threads und der von dir geäußerten Idee, diese Art von "Workaround" haben zu wollen.
BlackJack

@proofy: Hilfskrücke für was denn bitte? Wenn Du alternative ”Konstruktoren” willst, dafür gibt es Klassenmethoden. Deinen Vorschlag verstehe ich nicht? Wozu braucht man da eine `__new__()`-Methode? Die `__init__()` die anscheinend mit JSON-Daten gefüttert werden soll, wird ja nach der `__new__()` mit *deren* Argumenten auch noch einmal aufgerufen. Man würde da also nur das JSON-Argument sinnlos durch eine `__new__()`-Methode schleifen, die man überhaupt nicht benötigt. Das kann man auch alles in der `__init__()` machen.

Falls Du so etwas hier meintest:

Code: Alles auswählen

class Point(object):
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    @classmethod
    def from_dict(cls, dictionary):
        return cls(dictionary['x'], dictionary['y'])
Da braucht man kein `__new__()`.
proofy
User
Beiträge: 32
Registriert: Montag 21. März 2011, 12:47

Es kommt aus der C# und Java Welt, wo in Factories Objekte z.B. aus JSON erzeugt werden. Diese werden zunächst ohne Übergabe zum Konstruktor erzeugt und dann über Properties mit "aufgefüllt" . In meinem Fall habe ich mit IronPython gearbeitet und versucht eine JSON Objekt Fabrik aus .Net unter im Silverlight-Container zu verwenden. Da wusste ich noch nichts über __new__() und diese Fabriken aus einer anderen (Programmier)welt verwenden __new__() . Und hier im Forum konnte man mir Antworten geben, um das zu verstehen. Vielen Dank noch mal. :)
Antworten