Warum wird __init __ () immer nach __new __ () aufgerufen?

568

Ich versuche nur, eine meiner Klassen zu optimieren, und habe einige Funktionen im gleichen Stil wie das Flyweight-Designmuster eingeführt .

Ich bin jedoch etwas verwirrt darüber, warum __init__immer danach gerufen wird __new__. Ich habe das nicht erwartet. Kann mir jemand sagen, warum dies geschieht und wie ich diese Funktionalität ansonsten implementieren kann? (Abgesehen davon, dass die Implementierung in die integriert wird, __new__die sich ziemlich hackig anfühlt.)

Hier ist ein Beispiel:

class A(object):
    _dict = dict()

    def __new__(cls):
        if 'key' in A._dict:
            print "EXISTS"
            return A._dict['key']
        else:
            print "NEW"
            return super(A, cls).__new__(cls)

    def __init__(self):
        print "INIT"
        A._dict['key'] = self
        print ""

a1 = A()
a2 = A()
a3 = A()

Ausgänge:

NEW
INIT

EXISTS
INIT

EXISTS
INIT

Warum?

Dan
quelle
Ich habe versucht, auch das Designmuster zu verstehen, und zum ersten Mal davon gehört: Flyweight Design Pattern .. und ein sehr guter Link mit Beispiel in fast allen gängigen Sprachen.
EmmaYang

Antworten:

598

Verwenden __new__Sie diese Option, wenn Sie die Erstellung einer neuen Instanz steuern müssen.

Verwenden __init__Sie diese Option, wenn Sie die Initialisierung einer neuen Instanz steuern müssen.

__new__ist der erste Schritt der Instanzerstellung. Es wird zuerst aufgerufen und ist für die Rückgabe einer neuen Instanz Ihrer Klasse verantwortlich.

Im Gegensatz dazu __init__gibt nichts zurück; Es ist nur für die Initialisierung der Instanz verantwortlich, nachdem sie erstellt wurde.

Im Allgemeinen sollten Sie nicht überschreiben müssen, es __new__sei denn, Sie unterteilen einen unveränderlichen Typ wie str, int, unicode oder tuple.

Ab April 2008 Beitrag: Wann verwendet __new__vs. __init__? auf mail.python.org.

Sie sollten bedenken, dass das, was Sie versuchen, normalerweise mit einer Fabrik gemacht wird, und das ist der beste Weg, dies zu tun. Die Verwendung __new__ist keine gute saubere Lösung. Bitte berücksichtigen Sie die Verwendung einer Fabrik. Hier haben Sie ein gutes Fabrikbeispiel .

mpeterson
quelle
1
Endete __new__in einer Factory-Klasse, die ziemlich sauber geworden ist. Vielen Dank für Ihre Eingabe.
Dan
11
Entschuldigung, ich bin nicht der Meinung, dass die Verwendung von __new__streng auf die angegebenen Fälle beschränkt sein sollte. Ich fand es sehr nützlich für die Implementierung erweiterbarer generischer Klassenfabriken - siehe meine Antwort auf die Frage Unsachgemäße Verwendung __new__zum Generieren von Klassen in Python? für ein Beispiel dafür.
Martineau
170

__new__ist eine statische Klassenmethode, während __init__es sich um eine Instanzmethode handelt. __new__muss zuerst die Instanz erstellen, __init__kann sie also initialisieren. Beachten Sie, dass __init__nimmt selfals Parameter. Bis Sie eine Instanz erstellen, gibt es keine self.

Nun, ich verstehe, dass Sie versuchen, ein Singleton-Muster in Python zu implementieren . Dafür gibt es einige Möglichkeiten.

Auch, wie von Python 2.6, können Sie Klasse verwenden Dekorateure .

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
  ...
vartec
quelle
8
@ Tyler Long, ich verstehe nicht ganz, wie das "@singleton" funktioniert? Weil der Dekorateur eine Funktion zurückgibt, MyClass jedoch eine Klasse ist.
Alcott
11
Warum das Wörterbuch? Da cls immer gleich sind und Sie beispielsweise für jeden Singleton ein neues Wörterbuch erhalten, erstellen Sie ein Wörterbuch mit nur einem Element.
Winston Ewert
7
@Alcott: Keine Meinung erforderlich - die Dokumente stimmen mit Ihnen überein.
Ethan Furman
2
@ Alcott. Ja, der Dekorateur gibt eine Funktion zurück. aber sowohl die Klasse als auch die Funktion sind aufrufbar. Ich denke, Instanzen = {} sollten eine globale Variable sein.
Tyler Long
4
@ TylerLong Alcott hat einen guten Punkt. Dies führt dazu, dass der Name MyClassan eine Funktion gebunden wird, die Instanzen der ursprünglichen Klasse zurückgibt. Aber es gibt jetzt überhaupt keine Möglichkeit, auf die ursprüngliche Klasse zu verweisen, und MyClasseine Funktion zu unterbrechen isinstance/ zu issubclassprüfen, direkt auf Klassenattribute / -methoden zuzugreifen MyClass.something, die Klasse in superAufrufen zu benennen usw. usw. Ob dies ein Problem ist oder nicht, hängt von der ab Klasse, auf die Sie es anwenden (und den Rest des Programms).
Ben
148

In den meisten bekannten OO-Sprachen weist ein Ausdruck wie SomeClass(arg1, arg2)eine neue Instanz zu, initialisiert die Attribute der Instanz und gibt sie dann zurück.

In den meisten bekannten OO-Sprachen kann der Teil "Attribute der Instanz initialisieren" für jede Klasse angepasst werden, indem ein Konstruktor definiert wird. Dies ist im Grunde nur ein Codeblock, der auf der neuen Instanz ausgeführt wird (unter Verwendung der Argumente, die für den Konstruktorausdruck bereitgestellt werden ), um die gewünschten Anfangsbedingungen festzulegen. In Python entspricht dies der __init__Methode der Klasse .

Pythons __new__ist nicht mehr und nicht weniger als eine ähnliche Anpassung pro Klasse des Teils "Neue Instanz zuweisen". Auf diese Weise können Sie natürlich ungewöhnliche Dinge tun, z. B. eine vorhandene Instanz zurückgeben, anstatt eine neue zuzuweisen. In Python sollten wir uns diesen Teil also nicht unbedingt als notwendige Zuordnung vorstellen. Alles, was wir brauchen, ist, dass wir __new__irgendwo eine geeignete Instanz finden.

Aber es ist immer noch nur die Hälfte des Jobs, und das Python-System kann nicht wissen, dass Sie manchmal die andere Hälfte des Jobs ( __init__) danach ausführen möchten und manchmal nicht. Wenn Sie dieses Verhalten wollen, müssen Sie dies explizit sagen.

Oft können Sie eine Umgestaltung vornehmen, die Sie nur benötigen __new__oder nicht benötigen __new__oder die __init__sich bei einem bereits initialisierten Objekt anders verhält. Wenn Sie dies jedoch wirklich möchten, können Sie mit Python "den Job" neu definieren, sodass SomeClass(arg1, arg2)nicht unbedingt ein Aufruf __new__gefolgt von " aufrufen " erforderlich ist __init__. Dazu müssen Sie eine Metaklasse erstellen und deren __call__Methode definieren .

Eine Metaklasse ist nur die Klasse einer Klasse. Die __call__Methode einer Klasse steuert, was passiert, wenn Sie Instanzen der Klasse aufrufen. So ein Metaklasse " __call__Methode steuert , was passiert , wenn Sie eine Klasse nennen; Das heißt, Sie können den Mechanismus zur Instanzerstellung von Anfang bis Ende neu definieren . Auf dieser Ebene können Sie einen völlig nicht standardmäßigen Instanzerstellungsprozess wie das Singleton-Muster am elegantesten implementieren. In der Tat, mit weniger als 10 Zeilen Code können Sie implementieren SingletonMetaklasse , dass dann auch Sie nicht mit zu futz benötigen __new__ überhaupt , und drehen kann jede sonst normale Klasse in ein Singleton durch einfaches Hinzufügen __metaclass__ = Singleton!

class Singleton(type):
    def __init__(self, *args, **kwargs):
        super(Singleton, self).__init__(*args, **kwargs)
        self.__instance = None
    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            self.__instance = super(Singleton, self).__call__(*args, **kwargs)
        return self.__instance

Dies ist jedoch wahrscheinlich eine tiefere Magie, als dies für diese Situation wirklich gerechtfertigt ist!

Ben
quelle
25

So zitieren Sie die Dokumentation :

Typische Implementierungen erstellen eine neue Instanz der Klasse, indem sie die __new __ () -Methode der Superklasse mit "super (currentclass, cls) .__ new __ (cls [, ...])" mit entsprechenden Argumenten aufrufen und die neu erstellte Instanz nach Bedarf ändern bevor Sie es zurückgeben.

...

Wenn __new __ () keine Instanz von cls zurückgibt, wird die __init __ () -Methode der neuen Instanz nicht aufgerufen.

__new __ () soll hauptsächlich Unterklassen unveränderlicher Typen (wie int, str oder tuple) ermöglichen, die Instanzerstellung anzupassen.

tgray
quelle
18
If __new__() does not return an instance of cls, then the new instance's __init__() method will not be invoked.Das ist ein wichtiger Punkt. Wenn Sie eine andere Instanz zurückgeben, wird das Original __init__niemals aufgerufen.
Jeffrey Jose
@tgray Mir ist klar, dass Ihre Antwort aus den Dokumenten stammt, aber ich bin gespannt, ob Sie einen Anwendungsfall kennen, bei dem eine Instanz von cls nicht zurückgegeben wird. Es scheint, als __new__würde die Methode einen Fehler auslösen, wenn das zurückgegebene Objekt von auf seine Klasse überprüft wird, anstatt zuzulassen, dass die fehlgeschlagene Prüfung stillschweigend übergeben wird, da ich nicht verstehe, warum Sie jemals etwas anderes als ein Objekt der Klasse zurückgeben möchten .
einschläfernd312
@ soporific312 Ich habe keine Anwendungsfälle gesehen. In dieser Antwort werden einige der Gründe für das Design erörtert, obwohl sie auch keinen Code gesehen haben, der diese "Funktion" nutzt.
tgray
12

Mir ist klar, dass diese Frage ziemlich alt ist, aber ich hatte ein ähnliches Problem. Folgendes hat getan, was ich wollte:

class Agent(object):
    _agents = dict()

    def __new__(cls, *p):
        number = p[0]
        if not number in cls._agents:
            cls._agents[number] = object.__new__(cls)
        return cls._agents[number]

    def __init__(self, number):
        self.number = number

    def __eq__(self, rhs):
        return self.number == rhs.number

Agent("a") is Agent("a") == True

Ich habe diese Seite als Ressource verwendet: http://infohost.nmt.edu/tcc/help/pubs/python/web/new-new-method.html

Alexey
quelle
7
Hinweis: __new__ gibt immer ein geeignetes Objekt zurück, daher wird __init__ immer aufgerufen - auch wenn die Instanz bereits vorhanden ist.
Oddthinking
10

Ich denke, die einfache Antwort auf diese Frage lautet: Wenn __new__ein Wert zurückgegeben wird, der vom Typ der Klasse ist, wird die __init__Funktion ausgeführt, andernfalls nicht. In diesem Fall gibt Ihr Code A._dict('key')die gleiche Klasse zurück wie cls, __init__wird also ausgeführt.

PMN
quelle
10

Wenn eine __new__Instanz derselben Klasse zurückgegeben wird, __init__wird sie anschließend für das zurückgegebene Objekt ausgeführt. Dh Sie können NICHT verwenden __new__, um zu verhindern, __init__dass ausgeführt wird. Selbst wenn Sie ein zuvor erstelltes Objekt von zurückgeben __new__, wird es immer wieder doppelt (dreifach usw.) initialisiert __init__.

Hier ist der generische Ansatz für das Singleton-Muster, der die obige vartec-Antwort erweitert und behebt:

def SingletonClass(cls):
    class Single(cls):
        __doc__ = cls.__doc__
        _initialized = False
        _instance = None

        def __new__(cls, *args, **kwargs):
            if not cls._instance:
                cls._instance = super(Single, cls).__new__(cls, *args, **kwargs)
            return cls._instance

        def __init__(self, *args, **kwargs):
            if self._initialized:
                return
            super(Single, self).__init__(*args, **kwargs)
            self.__class__._initialized = True  # Its crucial to set this variable on the class!
    return Single

Die ganze Geschichte ist hier .

Ein anderer Ansatz, der tatsächlich beinhaltet, __new__ist die Verwendung von Klassenmethoden:

class Singleton(object):
    __initialized = False

    def __new__(cls, *args, **kwargs):
        if not cls.__initialized:
            cls.__init__(*args, **kwargs)
            cls.__initialized = True
        return cls


class MyClass(Singleton):
    @classmethod
    def __init__(cls, x, y):
        print "init is here"

    @classmethod
    def do(cls):
        print "doing stuff"

Bitte beachten Sie, dass Sie bei diesem Ansatz ALLE Ihre Methoden dekorieren müssen @classmethod, da Sie niemals eine echte Instanz von verwenden werden MyClass.

Zaar Hai
quelle
6

Verweis auf dieses Dokument :

Bei der Unterklasse von unveränderlichen integrierten Typen wie Zahlen und Zeichenfolgen und gelegentlich in anderen Situationen ist die neue statische Methode hilfreich. new ist der erste Schritt in der Instanzkonstruktion, der vor init aufgerufen wird .

Die neue Methode wird mit der Klasse als erstem Argument aufgerufen. Es ist dafür verantwortlich, eine neue Instanz dieser Klasse zurückzugeben.

Vergleichen Sie dies mit init : init wird mit einer Instanz als erstem Argument aufgerufen und gibt nichts zurück. Es liegt in der Verantwortung, die Instanz zu initialisieren.

Es gibt Situationen, in denen eine neue Instanz erstellt wird, ohne init aufzurufen (z. B. wenn die Instanz aus einem Pickle geladen wird). Es gibt keine Möglichkeit, eine neue Instanz zu erstellen, ohne new aufzurufen (obwohl Sie in einigen Fällen davonkommen können, die new einer Basisklasse aufzurufen ).

In Bezug auf das, was Sie erreichen möchten, finden Sie in derselben Dokumentation auch Informationen zum Singleton-Muster

class Singleton(object):
        def __new__(cls, *args, **kwds):
            it = cls.__dict__.get("__it__")
            if it is not None:
                return it
            cls.__it__ = it = object.__new__(cls)
            it.init(*args, **kwds)
            return it
        def init(self, *args, **kwds):
            pass

Sie können diese Implementierung auch aus PEP 318 mit einem Dekorator verwenden

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
...
kiriloff
quelle
1
Eine bastardisierte Form von initfrom zu nennen, __new__klingt wirklich hackig. Dafür sind Metaklassen da.
Verrückter Physiker
6
class M(type):
    _dict = {}

    def __call__(cls, key):
        if key in cls._dict:
            print 'EXISTS'
            return cls._dict[key]
        else:
            print 'NEW'
            instance = super(M, cls).__call__(key)
            cls._dict[key] = instance
            return instance

class A(object):
    __metaclass__ = M

    def __init__(self, key):
        print 'INIT'
        self.key = key
        print

a1 = A('aaa')
a2 = A('bbb')
a3 = A('aaa')

Ausgänge:

NEW
INIT

NEW
INIT

EXISTS

NB Als Nebeneffekt M._dictEigenschaft wird automatisch zugänglich Aals A._dictso kümmern sie nicht zufällig zu überschreiben.

Antony Hatchkins
quelle
Ihnen fehlt eine festgelegte __init__Methode cls._dict = {}. Sie möchten wahrscheinlich nicht, dass ein Wörterbuch von allen Klassen dieses Metatyps gemeinsam genutzt wird (aber +1 für die Idee).
Mad Physicist
5

__new__ sollte eine neue, leere Instanz einer Klasse zurückgeben. __init__ wird dann aufgerufen, um diese Instanz zu initialisieren. Sie rufen __init__ im "NEUEN" Fall von __new__ nicht an, also wird es für Sie aufgerufen. Der aufrufende Code verfolgt __new__nicht, ob __init__ für eine bestimmte Instanz aufgerufen wurde oder nicht, und sollte es auch nicht, da Sie hier etwas sehr Ungewöhnliches tun.

Sie können dem Objekt in der Funktion __init__ ein Attribut hinzufügen, um anzuzeigen, dass es initialisiert wurde. Überprüfen Sie als erstes in __init__, ob dieses Attribut vorhanden ist, und fahren Sie nicht fort, wenn dies der Fall war.

Andrew Wilkinson
quelle
5

Bei einer Aktualisierung der Antwort von @AntonyHatchkins möchten Sie wahrscheinlich ein separates Instanzwörterbuch für jede Klasse des Metatyps. Dies bedeutet, dass Sie eine __init__Methode in der Metaklasse haben sollten, um Ihr Klassenobjekt mit diesem Wörterbuch zu initialisieren, anstatt es für alle Klassen global zu machen.

class MetaQuasiSingleton(type):
    def __init__(cls, name, bases, attibutes):
        cls._dict = {}

    def __call__(cls, key):
        if key in cls._dict:
            print('EXISTS')
            instance = cls._dict[key]
        else:
            print('NEW')
            instance = super().__call__(key)
            cls._dict[key] = instance
        return instance

class A(metaclass=MetaQuasiSingleton):
    def __init__(self, key):
        print 'INIT'
        self.key = key
        print()

Ich habe den ursprünglichen Code mit einer __init__Methode aktualisiert und die Syntax in die Python 3-Notation geändert (Aufruf ohne superArgumente und Metaklasse in den Klassenargumenten anstelle eines Attributs).

In jedem Fall ist der wichtige Punkt hier, dass Ihr Klasseninitialisierer ( __call__Methode) entweder nicht ausgeführt wird __new__oder __init__wenn der Schlüssel gefunden wird. Dies ist viel sauberer als die Verwendung __new__, bei der Sie das Objekt markieren müssen, wenn Sie den Standardschritt überspringen möchten __init__.

Verrückter Physiker
quelle
4

Etwas tiefer in das hinein graben!

Der Typ einer generischen Klasse in CPython ist typeund ihre Basisklasse ist Object(es sei denn, Sie definieren explizit eine andere Basisklasse wie eine Metaklasse). Die Reihenfolge der Anrufe auf niedriger Ebene finden Sie hier . Die erste aufgerufene Methode ist die, type_calldie dann tp_newund dann aufruft tp_init.

Der interessante Teil hier ist, dass tp_newdie Objectneue Methode 's (Basisklasse) aufgerufen wird, die object_newa tp_alloc( PyType_GenericAlloc) ausführt, die den Speicher für das Objekt zuweist :)

Zu diesem Zeitpunkt wird das Objekt im Speicher erstellt und die __init__Methode aufgerufen. Wenn __init__es nicht in deiner Klasse implementiert ist, wird das object_initaufgerufen und es macht nichts :)

Dann wird type_callnur das Objekt zurückgegeben, das an Ihre Variable gebunden ist.

xpapazaf
quelle
4

Man sollte es __init__als einfachen Konstruktor in traditionellen OO-Sprachen betrachten. Wenn Sie beispielsweise mit Java oder C ++ vertraut sind, wird dem Konstruktor implizit ein Zeiger auf seine eigene Instanz übergeben. Im Fall von Java ist es die thisVariable. Wenn man den für Java generierten Bytecode untersuchen würde, würde man zwei Aufrufe bemerken. Der erste Aufruf bezieht sich auf eine "neue" Methode, und der nächste Aufruf bezieht sich auf die init-Methode (dies ist der tatsächliche Aufruf des benutzerdefinierten Konstruktors). Dieser zweistufige Prozess ermöglicht die Erstellung der tatsächlichen Instanz, bevor die Konstruktormethode der Klasse aufgerufen wird, die nur eine andere Methode dieser Instanz ist.

Im Fall von Python gibt __new__es jetzt eine zusätzliche Funktion, auf die der Benutzer zugreifen kann. Java bietet diese Flexibilität aufgrund seiner Typisierung nicht. Wenn eine Sprache diese Funktion bereitstellt, kann der Implementierer von __new__in dieser Methode viele Dinge tun, bevor er die Instanz zurückgibt, einschließlich der Erstellung einer völlig neuen Instanz eines nicht verwandten Objekts in einigen Fällen. Und dieser Ansatz eignet sich auch besonders für unveränderliche Typen im Fall von Python.

grdvnl
quelle
4

Ich bin jedoch etwas verwirrt darüber, warum __init__immer danach gerufen wird __new__.

Ich denke, die C ++ - Analogie wäre hier nützlich:

  1. __new__ordnet einfach Speicher für das Objekt zu. Die Instanzvariablen eines Objekts benötigen Speicher, um es zu halten, und dies __new__würde der Schritt tun.

  2. __init__ Initialisieren Sie die internen Variablen des Objekts auf bestimmte Werte (kann Standard sein).

HAltos
quelle
2

Das __init__wird danach aufgerufen, __new__sodass Ihr hinzugefügter Code weiterhin aufgerufen wird, wenn Sie ihn in einer Unterklasse überschreiben.

Wenn Sie versuchen, eine Klasse zu unterordnen, die bereits eine hat __new__, kann jemand, der sich dessen nicht bewusst ist , __init__den Anruf zunächst anpassen und an die Unterklasse weiterleiten __init__. Diese Konvention des Aufrufs __init__nach __new__hilft , dass die Arbeit wie erwartet.

Das muss __init__noch alle Parameter berücksichtigen, die die Oberklasse __new__benötigt, aber wenn dies nicht getan wird, wird normalerweise ein klarer Laufzeitfehler erzeugt. Und das __new__sollte wahrscheinlich explizit *argsund '** kw' zulassen , um klar zu machen, dass die Erweiterung in Ordnung ist.

Aufgrund des Verhaltens, das auf dem Originalplakat beschrieben wurde, ist es im Allgemeinen eine schlechte Form, beide __new__und __init__dieselbe Klasse auf derselben Vererbungsstufe zu haben.

Jay Obermark
quelle
1

Ich bin jedoch etwas verwirrt darüber, warum __init__immer danach gerufen wird __new__.

Kein anderer Grund als der, dass es einfach so gemacht wird. __new__hat nicht die Verantwortung, die Klasse zu initialisieren, eine andere Methode ( __call__möglicherweise - ich weiß es nicht genau).

Ich habe das nicht erwartet. Kann mir jemand sagen, warum dies geschieht und wie ich diese Funktionalität ansonsten implementiere? (Abgesehen davon, dass die Implementierung in die integriert wird, __new__die sich ziemlich hackig anfühlt).

Sie hätten __init__nichts tun können, wenn es bereits initialisiert worden wäre, oder Sie könnten eine neue Metaklasse mit einer neuen schreiben __call__, die nur __init__neue Instanzen aufruft und ansonsten nur zurückgibt __new__(...).

Devin Jeanpierre
quelle
1

Der einfache Grund ist, dass das neue zum Erstellen einer Instanz verwendet wird, während init zum Initialisieren der Instanz verwendet wird. Vor der Initialisierung sollte zuerst die Instanz erstellt werden. Deshalb sollte new vor init aufgerufen werden .

ZQ Hu
quelle
1

Jetzt habe ich das gleiche Problem und aus bestimmten Gründen habe ich beschlossen, Dekorateure, Fabriken und Metaklassen zu meiden. Ich habe es so gemacht:

Hauptdatei

def _alt(func):
    import functools
    @functools.wraps(func)
    def init(self, *p, **k):
        if hasattr(self, "parent_initialized"):
            return
        else:
            self.parent_initialized = True
            func(self, *p, **k)

    return init


class Parent:
    # Empty dictionary, shouldn't ever be filled with anything else
    parent_cache = {}

    def __new__(cls, n, *args, **kwargs):

        # Checks if object with this ID (n) has been created
        if n in cls.parent_cache:

            # It was, return it
            return cls.parent_cache[n]

        else:

            # Check if it was modified by this function
            if not hasattr(cls, "parent_modified"):
                # Add the attribute
                cls.parent_modified = True
                cls.parent_cache = {}

                # Apply it
                cls.__init__ = _alt(cls.__init__)

            # Get the instance
            obj = super().__new__(cls)

            # Push it to cache
            cls.parent_cache[n] = obj

            # Return it
            return obj

Beispielklassen

class A(Parent):

    def __init__(self, n):
        print("A.__init__", n)


class B(Parent):

    def __init__(self, n):
        print("B.__init__", n)

In Benutzung

>>> A(1)
A.__init__ 1  # First A(1) initialized 
<__main__.A object at 0x000001A73A4A2E48>
>>> A(1)      # Returned previous A(1)
<__main__.A object at 0x000001A73A4A2E48>
>>> A(2)
A.__init__ 2  # First A(2) initialized
<__main__.A object at 0x000001A7395D9C88>
>>> B(2)
B.__init__ 2  # B class doesn't collide with A, thanks to separate cache
<__main__.B object at 0x000001A73951B080>
  • Achtung: Sie sollten nicht initialize Eltern, es wird mit anderen Klassen kollidieren - es sei denn , Sie separate Cache in jedem der Kinder definiert, das nicht das, was wir wollen.
  • Warnung: Es scheint eine Klasse mit Eltern zu sein, da sich Großeltern seltsam verhalten. [Nicht überprüft]

Probieren Sie es online aus!

Rotklee
quelle