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 Singleton
Metaklasse , 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!