Ich schreibe einen benutzerdefinierten Typ Foo
und ich möchte folgendes erreichen: wennKlassenname als idempotent Funktion typisieren
foo = Foo(bar)
dann schreiben, wenn bar
bereits eine Instanz von Foo
, dann Foo(foo)
zurückgibt, Objekt unmodifiziert, so beziehen sich foo
und bar
auf dasselbe Objekt. Andernfalls sollte ein neues Objekt vom Typ Foo
erstellt werden, unter Verwendung von Informationen aus bar
in welcher Weise auch immer Foo.__init__
als angemessen erachtet wird.
Wie kann ich das tun?
Ich würde annehmen, dass Foo.__new__
der Schlüssel dazu ist. Es sollte ziemlich einfach sein, Foo.__new__
das vorhandene Objekt zurückzugeben, wenn die instanceof
Überprüfung erfolgreich ist, und andernfalls super().__new__
aufrufen. Aber the documentation for __new__
schreibt dazu:
Wenn
__new__()
gibt eine Instanz von cls, dann wird die neue Instanz__init__()
Methode wie__init__(self[, ...])
aufgerufen werden, wo Selbst ist die neue Instanz und die übrigen Argumente sind die gleichen wie waren übergeben an__new__()
.
In diesem Fall würde ich eine Instanz der angeforderten Klasse zurückgeben, wenn auch keine neue. Kann ich den Anruf auf __init__
irgendwie verhindern? Oder muss ich innerhalb von __init__
eine Überprüfung hinzufügen, um festzustellen, ob es für eine neu erstellte Instanz oder für eine bereits vorhandene Instanz aufgerufen wird? Letzteres klingt nach Code-Duplikation, die vermeidbar sein sollte.
Ist es nicht erlaubt, Factory-Methoden zu verwenden, um dies zu erreichen? – Tagc
@Tagc: Ich bin irgendwie gewöhnt, Konstruktornamen für Umwandlungen zu verwenden.Zum Beispiel geben 'float (x)', 'str (x)' oder 'tuple (x)' das gleiche Objekt zurück, wenn es bereits vom richtigen Typ ist. Ich benutze diese Notation ziemlich oft, also möchte ich es auch für meine eigenen Typen, um konsistent zu sein. Es ist also eine Frage des Stils, denke ich. Funktionell würde eine Fabrikmethode natürlich genauso gut funktionieren. – MvG