Diese Frage dient nicht der Diskussion, ob das Singleton-Entwurfsmuster wünschenswert ist, ein Anti-Muster ist oder für irgendwelche Religionskriege, sondern um zu diskutieren, wie dieses Muster in Python am besten auf eine Weise implementiert werden kann, die am pythonischsten ist. In diesem Fall definiere ich "am pythonischsten" so, dass es dem "Prinzip des geringsten Erstaunens" folgt .
Ich habe mehrere Klassen, die zu Singletons werden würden (mein Anwendungsfall ist für einen Logger, aber das ist nicht wichtig). Ich möchte nicht mehrere Klassen mit zusätzlichem Kaugummi überladen, wenn ich einfach erben oder dekorieren kann.
Beste Methoden:
Methode 1: Ein Dekorateur
def singleton(class_):
instances = {}
def getinstance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return getinstance
@singleton
class MyClass(BaseClass):
pass
Vorteile
- Dekorateure sind auf eine Weise additiv, die oft intuitiver ist als Mehrfachvererbung.
Nachteile
- Während mit MyClass () erstellte Objekte echte Singleton-Objekte sind, ist MyClass selbst eine Funktion, keine Klasse, sodass Sie keine Klassenmethoden daraus aufrufen können. Auch für
m = MyClass(); n = MyClass(); o = type(n)();
dannm == n && m != o && n != o
Methode 2: Eine Basisklasse
class Singleton(object):
_instance = None
def __new__(class_, *args, **kwargs):
if not isinstance(class_._instance, class_):
class_._instance = object.__new__(class_, *args, **kwargs)
return class_._instance
class MyClass(Singleton, BaseClass):
pass
Vorteile
- Es ist eine wahre Klasse
Nachteile
- Mehrfachvererbung - eugh!
__new__
könnte während der Vererbung von einer zweiten Basisklasse überschrieben werden? Man muss mehr denken als nötig.
Methode 3: Eine Metaklasse
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
#Python2
class MyClass(BaseClass):
__metaclass__ = Singleton
#Python3
class MyClass(BaseClass, metaclass=Singleton):
pass
Vorteile
- Es ist eine wahre Klasse
- Deckt die Vererbung automatisch ab
- Verwendet
__metaclass__
für den richtigen Zweck (und machte mich darauf aufmerksam)
Nachteile
- Sind da irgendwelche?
Methode 4: Dekorateur, der eine gleichnamige Klasse zurückgibt
def singleton(class_):
class class_w(class_):
_instance = None
def __new__(class_, *args, **kwargs):
if class_w._instance is None:
class_w._instance = super(class_w,
class_).__new__(class_,
*args,
**kwargs)
class_w._instance._sealed = False
return class_w._instance
def __init__(self, *args, **kwargs):
if self._sealed:
return
super(class_w, self).__init__(*args, **kwargs)
self._sealed = True
class_w.__name__ = class_.__name__
return class_w
@singleton
class MyClass(BaseClass):
pass
Vorteile
- Es ist eine wahre Klasse
- Deckt die Vererbung automatisch ab
Nachteile
- Gibt es keinen Aufwand für das Erstellen jeder neuen Klasse? Hier erstellen wir zwei Klassen für jede Klasse, die wir zu einem Singleton machen möchten. Obwohl dies in meinem Fall in Ordnung ist, mache ich mir Sorgen, dass dies möglicherweise nicht skaliert. Natürlich wird diskutiert, ob es zu einfach sein sollte, dieses Muster zu skalieren ...
- Was ist der Sinn des
_sealed
Attributs super()
Gleichnamige Methoden können für Basisklassen nicht aufgerufen werden, da sie wiederkehren. Dies bedeutet, dass Sie__new__
eine Klasse, für die Sie einen Aufruf benötigen, nicht anpassen und nicht in Unterklassen unterteilen können__init__
.
Methode 5: ein Modul
eine Moduldatei singleton.py
Vorteile
- Einfach ist besser als komplex
Nachteile
foo.x
oder , wenn Sie darauf bestehen ,Foo.x
stattFoo().x
); Verwenden Sie Klassenattribute und statische / Klassenmethoden (Foo.x
).Antworten:
Verwenden Sie eine Metaklasse
Ich würde Methode 2 empfehlen , aber Sie sind besser dran, eine Metaklasse als eine Basisklasse zu verwenden. Hier ist eine Beispielimplementierung:
Oder in Python3
Wenn Sie
__init__
jedes Mal ausführen möchten, wenn die Klasse aufgerufen wird, fügen Sie hinzuzur
if
Aussage inSingleton.__call__
.Ein paar Worte zu Metaklassen. Eine Metaklasse ist die Klasse einer Klasse ; Das heißt, eine Klasse ist eine Instanz ihrer Metaklasse . Sie finden die Metaklasse eines Objekts in Python mit
type(obj)
. Normale Klassen neuen Stils sind vom Typtype
.Logger
im obigen Code wird vom Typ seinclass 'your_module.Singleton'
, genauso wie die (einzige) Instanz vonLogger
vom Typ sein wirdclass 'your_module.Logger'
. Wenn Sie Logger rufen mitLogger()
, fragt Python zuerst die Metaklasse vonLogger
,Singleton
, was zu tun ist, so dass beispielsweise die Schaffung vorbelegt werden. Dieser Vorgang ist der gleiche wie bei Python, bei dem eine Klasse gefragt wird, was zu tun ist, indem sie aufruft,__getattr__
wenn Sie dabei auf eines ihrer Attribute verweisenmyclass.attribute
.Eine Metaklasse entscheidet im Wesentlichen, was die Definition einer Klasse bedeutet und wie diese Definition implementiert wird. Siehe zum Beispiel http://code.activestate.com/recipes/498149/ , das im Wesentlichen C-Stile
struct
in Python mithilfe von Metaklassen neu erstellt. Der Thread Was sind einige (konkrete) Anwendungsfälle für Metaklassen? liefert auch einige Beispiele, sie scheinen im Allgemeinen mit deklarativer Programmierung in Zusammenhang zu stehen, insbesondere wie sie in ORMs verwendet werden.Wenn Sie in dieser Situation Ihre Methode 2 verwenden und eine Unterklasse eine
__new__
Methode definiert , wird diese bei jedem Aufruf ausgeführt,SubClassOfSingleton()
da sie für den Aufruf der Methode verantwortlich ist, die die gespeicherte Instanz zurückgibt. Bei einer Metaklasse wird sie nur einmal aufgerufen , wenn die einzige Instanz erstellt wird. Sie möchten anpassen, was es bedeutet, die Klasse aufzurufen , was durch ihren Typ bestimmt wird.Im Allgemeinen ist es sinnvoll , eine Metaklasse zum Implementieren eines Singletons zu verwenden. Ein Singleton ist etwas Besonderes, da er nur einmal erstellt wird. Mit einer Metaklasse können Sie die Erstellung einer Klasse anpassen . Durch die Verwendung einer Metaklasse erhalten Sie mehr Kontrolle, falls Sie die Definitionen der Singleton-Klassen auf andere Weise anpassen müssen.
Ihre Singletons benötigen keine Mehrfachvererbung (da die Metaklasse keine Basisklasse ist). Für Unterklassen der erstellten Klasse , die Mehrfachvererbung verwenden, müssen Sie jedoch sicherstellen, dass die Singleton-Klasse die erste / ganz links stehende Metaklasse mit einer neu definierten Metaklasse ist
__call__
Es ist sehr unwahrscheinlich, dass dies ein Problem darstellt. Das Instanz-Diktat befindet sich nicht im Namespace der Instanz, sodass es nicht versehentlich überschrieben wird.Sie werden auch hören, dass das Singleton-Muster gegen das "Prinzip der Einzelverantwortung" verstößt - jede Klasse sollte nur eines tun . Auf diese Weise müssen Sie sich nicht darum kümmern, eine Sache des Codes durcheinander zu bringen, wenn Sie eine andere ändern müssen, da sie getrennt und gekapselt sind. Die Metaklassenimplementierung besteht diesen Test . Die Metaklasse ist für die Durchsetzung des Musters verantwortlich , und die erstellten Klassen und Unterklassen müssen nicht wissen, dass es sich um Singletons handelt . Methode Nr. 1 besteht diesen Test nicht, wie Sie mit "MyClass selbst ist eine Funktion, keine Klasse, daher können Sie keine Klassenmethoden daraus aufrufen" festgestellt haben.
Python 2 und 3 kompatible Version
Um etwas zu schreiben, das sowohl in Python2 als auch in Python 3 funktioniert, muss ein etwas komplizierteres Schema verwendet werden. Da in der Regel metaclasses Subklassen von Typ sind
type
, dann ist es möglich , eine zu verwenden , um dynamisch eine Zwischenbasisklasse zur Laufzeit mit ihm als seine Metaklasse zu erstellen und verwenden Sie dann , dass als die Basisklasse der öffentlichenSingleton
Basisklasse. Es ist schwieriger zu erklären als zu tun, wie im Folgenden dargestellt:Ein ironischer Aspekt dieses Ansatzes ist, dass zur Implementierung einer Metaklasse Unterklassen verwendet werden. Ein möglicher Vorteil ist, dass im Gegensatz zu einer reinen Metaklasse
isinstance(inst, Singleton)
zurückkehren wirdTrue
.Korrekturen
Bei einem anderen Thema haben Sie dies wahrscheinlich bereits bemerkt, aber die Implementierung der Basisklasse in Ihrem ursprünglichen Beitrag ist falsch.
_instances
muss auf die Klasse verwiesen werden , muss verwendet werdensuper()
oder Sie rekursieren und__new__
ist eigentlich eine statische Methode, an die Sie die Klasse übergeben müssen , keine Klassenmethode, da die eigentliche Klasse noch nicht erstellt wurde, als sie erstellt wurde wird genannt. All diese Dinge gelten auch für eine Metaklassenimplementierung.Dekorateur, der eine Klasse zurückgibt
Ich habe ursprünglich einen Kommentar geschrieben, aber er war zu lang, deshalb füge ich ihn hier hinzu. Methode 4 ist besser als die andere Decorator-Version, aber es ist mehr Code als für einen Singleton erforderlich, und es ist nicht so klar, was es tut.
Die Hauptprobleme ergeben sich daraus, dass die Klasse eine eigene Basisklasse ist. Ist es nicht seltsam, wenn eine Klasse eine Unterklasse einer nahezu identischen Klasse mit demselben Namen ist, die nur in ihrem
__class__
Attribut existiert? Das bedeutet auch , dass Sie nicht definieren können alle Methoden, die die Methode mit dem gleichen Namen auf ihrer Basisklasse aufrufen mit ,super()
weil sie Rekursion wird. Dies bedeutet, dass Ihre Klasse nicht angepasst werden__new__
kann und nicht von Klassen abgeleitet werden kann, die sie aufrufen__init__
müssen.Wann wird das Singleton-Muster verwendet?
Ihr Anwendungsfall ist eines der besseren Beispiele für die Verwendung eines Singletons. Sie sagen in einem der Kommentare: "Für mich war das Protokollieren immer ein natürlicher Kandidat für Singletons." Du hast absolut recht .
Wenn Leute sagen, Singletons seien schlecht, ist der häufigste Grund, dass sie einen impliziten gemeinsamen Zustand haben . Während bei globalen Variablen und Modulimporten der obersten Ebene ein expliziter gemeinsamer Status vorliegt, werden andere Objekte, die weitergegeben werden, im Allgemeinen instanziiert. Dies ist mit zwei Ausnahmen ein guter Punkt .
Die erste und eine, die an verschiedenen Stellen erwähnt wird, ist, wenn die Singletons konstant sind . Die Verwendung globaler Konstanten, insbesondere von Aufzählungen, wird allgemein akzeptiert und als vernünftig angesehen, da keiner der Benutzer sie für einen anderen Benutzer durcheinander bringen kann . Dies gilt auch für einen konstanten Singleton.
Die zweite Ausnahme, die weniger erwähnt wird, ist das Gegenteil - wenn der Singleton nur eine Datensenke ist , keine Datenquelle (direkt oder indirekt). Aus diesem Grund fühlen sich Logger wie eine "natürliche" Verwendung für Singletons. Da die verschiedenen Benutzer die Logger nicht so ändern, wie es anderen Benutzern wichtig ist, gibt es keinen wirklich gemeinsam genutzten Status . Dies negiert das Hauptargument gegen das Singleton-Muster und macht sie aufgrund ihrer einfachen Verwendung für die Aufgabe zu einer vernünftigen Wahl .
Hier ist ein Zitat von http://googletesting.blogspot.com/2008/08/root-cause-of-singletons.html :
quelle
__new__
in einer Metaklasse ist, wenn die Klasse neu ist - wenn sie definiert ist, nicht wenn die Instanz neu wäre. Das Aufrufen der class (MyClass()
) ist die Operation, die Sie überschreiben möchten, nicht die Definition der Klasse. Wenn Sie wirklich verstehen möchten, wie Python funktioniert, können Sie am besten docs.python.org/reference/datamodel.html lesen (außer es weiterhin zu verwenden) . Eine gute Referenz für Metaklassen ist eli.thegreenplace.net/2011/08/14/python-metaclasses-by-example . Ein guter Artikel über Singletons ist die Serie aus dem Google-Blog, die ich in dieser Antwort verlinkt habe.Module werden nur einmal importiert, alles andere überdenkt. Verwenden Sie keine Singletons und versuchen Sie, keine Globals zu verwenden.
quelle
s = some_global_variable; str = pickle.dumps(s); s1 = pickle.loads(str); print s is s1; # False
is
Operator testet auf Zeigergleichheit . Ich wäre ziemlich überrascht - bis zu dem Punkt, dass ich es als Fehler bezeichne -, wenn ichpickle.loads
einen Verweis auf ein bereits vorhandenes Objekt anstelle eines Verweises auf ein neu erstelltes Objekt zurückgeben würde. Testen Sie daher, obs is s1
Sie nichts über die Eignung der Verwendung von Modulen als Singletons wissen.pickle.loads()
macht das schon, zB für Instanzen vonbool
undNoneType
.pickle.loads(pickle.dumps(False)) is False
ErträgeTrue
True
,False
undNone
, und hat nichts mit dem Code - behind zu tunpickle.loads
. Es ist auch sicher, nur für schreibgeschützte Objekte zu tun. Wenn Siepickle.loads
einen Verweis auf ein bereits vorhandenes modifizierbares Objekt wie ein Modul zurückgeben würden, wäre dies ein Fehler. (Und so stehe ich zu meiner Implikation, dass das Codebeispiel von dividbyzero nichts beweist.)Verwenden Sie ein Modul. Es wird nur einmal importiert. Definieren Sie einige globale Variablen darin - sie sind Singletons 'Attribute'. Fügen Sie einige Funktionen hinzu - die 'Methoden' des Singletons.
quelle
Sie brauchen wahrscheinlich nie einen Singleton in Python. Definieren Sie einfach alle Ihre Daten und Funktionen in einem Modul und Sie haben einen De-facto-Singleton.
Wenn Sie wirklich unbedingt eine Singleton-Klasse haben müssen, würde ich gehen mit:
Benutzen:
Dabei ist mysingleton.py Ihr Dateiname, in dem My_Singleton definiert ist. Dies funktioniert, da Python den Code nach dem ersten Import einer Datei nicht erneut ausführt.
quelle
Hier ist ein Einzeiler für Sie:
So verwenden Sie es:
Ihr Objekt wird eifrig instanziiert. Dies kann sein oder nicht, was Sie wollen.
quelle
type(wat)
oderwat.__class__
. Wenn Sie dies wirklich erreichen möchten, definieren Sie die Klasse besser und instanziieren Sie sie sofort, ohne sich mit dem Dekorateur herumschlagen zu müssen.wat2 = type(wat)()
, aber das ist Python, wir sind alle einverstanden mit Erwachsenen und all dem. Sie können nicht garantieren, dass es nur eine Instanz gibt, aber Sie können garantieren, dass Menschen, die eine zweite erstellen, hässlich aussehen und - wenn sie anständige, aufrechte Menschen sind - wie ein Warnzeichen für sie aussehen. Was vermisse ich?Check out Stapelüberlauf Frage Gibt es eine einfache, elegante Möglichkeit, Singletons in Python zu definieren? mit mehreren Lösungen.
Ich würde dringend empfehlen, Alex Martellis Vorträge über Designmuster in Python zu sehen: Teil 1 und Teil 2 . Insbesondere spricht er in Teil 1 über Singletons / Shared State Objects.
quelle
Hier ist meine eigene Implementierung von Singletons. Alles was Sie tun müssen, ist die Klasse zu dekorieren; Um den Singleton zu erhalten, müssen Sie dann die
Instance
Methode verwenden. Hier ist ein Beispiel:Und hier ist der Code:
quelle
SingletonList = Singleton(list).Instance(); print(SingletonList is type(SingletonList)())
sollteTrue
in echtem Singleton drucken ; mit Ihren Code drucktFalse
Methode 3 scheint sehr ordentlich zu sein, aber wenn Sie möchten, dass Ihr Programm sowohl in Python 2 als auch in Python 3 ausgeführt wird , funktioniert es nicht. Selbst der Schutz der einzelnen Varianten mit Tests für die Python-Version schlägt fehl, da die Python 3-Version in Python 2 einen Syntaxfehler verursacht.
Vielen Dank an Mike Watkins: http://mikewatkins.ca/2008/11/29/python-2-and-3-metaclasses/ . Wenn Sie möchten, dass das Programm sowohl in Python 2 als auch in Python 3 funktioniert, müssen Sie Folgendes tun:
Ich gehe davon aus, dass 'Objekt' in der Zuweisung durch die 'Basisklasse' ersetzt werden muss, aber ich habe das nicht versucht (ich habe Code wie abgebildet ausprobiert).
quelle
class MyClass(metaclass=Singleton)
Nun, abgesehen davon, dass Sie dem allgemeinen pythonischen Vorschlag zustimmen, eine globale Modulebene zu haben, wie wäre es damit:
Ausgabe ist:
quelle
_sealed
Attributs? Soweit ich sehe, macht das nichts? Etwas nervt mich daran, dass es nicht gut funktionieren sollte ... Ich werde später in dieser Woche einige Vergleichstests durchführen.__init__
, die bei jeder Initialisierung aufgerufen werden sollen. Nur ein einfaches 'In class.method initialisiert werden'.Wie wäre es damit:
Verwenden Sie es als Dekorateur für eine Klasse, die ein Singleton sein sollte. So was:
Dies ähnelt dem
singleton = lambda c: c()
Dekorateur in einer anderen Antwort. Wie die andere Lösung hat die einzige Instanz den Namen der Klasse (MySingleton
). Mit dieser Lösung können Sie jedoch weiterhin Instanzen aus der Klasse "erstellen" (tatsächlich die einzige Instanz erhalten), indem Sie dies tunMySingleton()
. Es verhindert auch, dass Sie zusätzliche Instanzen erstellen, indem Sie dies tuntype(MySingleton)()
( wodurch auch dieselbe Instanz zurückgegeben wird).quelle
type(MySingleton)()
, wenn Sie anrufen ,MySingleton.__init__()
wird es aufgerufen und das Objekt wird mehrmals initialisiert. Sie können es schriftlichcls.__init__ = lambda self: pass
in Ihrem behebensingleton
. Außerdemcls.__call__
scheint das Überschreiben sinnlos und sogar schädlich zu sein -__call__
in diesem Zusammenhang wird es verwendet, wenn Sie anrufenMySingleton(any, list, of, arguments)
, nicht wenn Sie anrufentype(MySingleton)(any, list, of, arguments)
.__init__()
Aufruf erneut aufgerufen wirdtype(MySingleton)()
. Die von Ihnen vorgeschlagene Lösung (Hinzufügencls.__init__ = lambda self: pass
) führt zu einem Syntaxfehler, da der letzte Teil des Lambda-Ausdrucks ein Ausdruck und keine Anweisung sein muss. Das Hinzufügencls.__init__ = lambda self: None
funktioniert jedoch, also habe ich das zu meiner Antwort hinzugefügt.__call__
. Meine Absicht war es, beides zu machentype(MySingleton)()
undMySingleton()
die Instanz zurückzugeben. Also macht es was ich wollte. Sie können sich MySingleton entweder als Typ des Singletons oder als Instanz des Singletons (oder als beides) vorstellen.Ich werfe meine in den Ring. Es ist ein einfacher Dekorateur.
Vorteile Ich denke, es hat gegenüber einigen anderen Lösungen:
YourClass
. Dies beinhaltet, dass Sie keine Metaklasse für Ihre Klasse verwenden müssen (beachten Sie, dass sich die oben genannte Metaklasse im Werk befindet und nicht die "echte" Klasse).YourClass
, es sieht aus wie eine Klasse (weil es so ist) und sie verwenden es normal. Anrufer müssen nicht an eine Werksfunktion angepasst werden.YourClass()
instanziiert, ist immer noch eine echte Instanz der vonYourClass
Ihnen implementierten, kein Proxy jeglicher Art, also keine Chance auf daraus resultierende Nebenwirkungen.isinstance(instance, YourClass)
und ähnliche Operationen funktionieren immer noch wie erwartet (obwohl dieses Bit abc erfordert, schließt Python <2.6 aus).Ein Nachteil fällt mir ein: Klassenmethoden und statische Methoden der realen Klasse können nicht transparent über die Factory-Klasse aufgerufen werden, die sie versteckt. Ich habe dies selten genug verwendet, damit ich nie auf dieses Bedürfnis gestoßen bin, aber es könnte leicht behoben werden, indem eine benutzerdefinierte Metaklasse in der Factory verwendet wird, die implementiert,
__getattr__()
um den Zugriff auf all-ish-Attribute an die reale Klasse zu delegieren.Ein verwandtes Muster, das ich tatsächlich als nützlicher empfunden habe (nicht, dass ich sage, dass solche Dinge überhaupt sehr oft erforderlich sind), ist ein "einzigartiges" Muster, bei dem das Instanziieren der Klasse mit denselben Argumenten dazu führt, dass dieselbe Instanz zurückgegeben wird. Dh ein "Singleton pro Argument". Das Obige passt sich diesem Brunnen an und wird noch prägnanter:
Trotzdem stimme ich dem allgemeinen Rat zu, dass Sie, wenn Sie glauben, eines dieser Dinge zu brauchen, wahrscheinlich einen Moment innehalten und sich fragen sollten, ob Sie es wirklich tun. 99% der Zeit, YAGNI.
quelle
serial
Kommunikation für die Klassenverarbeitung verfügen und eine Instanz erstellen möchten, die Sie als Argument an die serielle Schnittstelle senden möchten, funktioniert dies mit dem herkömmlichen Ansatz nichtquelle
Code basierend auf Tollis Antwort .
Erläuterung:
Erstellen Sie eine neue Klasse, die von einer bestimmten erbt
cls
(sie ändert sich nicht,
cls
falls jemand dies wünschtsingleton(list)
).Instanz erstellen. Vor dem Überschreiben ist
__new__
es so einfach.__new__
mit der vor kurzem definierten Methode überschrieben .Die Funktion wird
instance
nur zurückgegeben, wenn dies vom Aufrufer erwartet wird, andernfalls wird sie ausgelöstTypeError
.Die Bedingung ist nicht erfüllt, wenn jemand versucht, von einer dekorierten Klasse zu erben.
instance
ist bereits initialisiert, daher wird die Funktion durch die Funktion ersetzt__init__
, die nichts tut.Sehen Sie, wie es online funktioniert
quelle
Es ist der Antwort von fab etwas ähnlich, aber nicht genau das gleiche.
Der Singleton-Vertrag erfordert nicht, dass wir den Konstruktor mehrmals aufrufen können. Da ein Singleton nur einmal erstellt werden sollte, sollte er nicht nur einmal erstellt werden? Das "Spoofing" des Konstrukteurs beeinträchtigt wohl die Lesbarkeit.
Mein Vorschlag ist also genau das:
Dies schließt die Verwendung des Konstruktors oder des Feldes
instance
durch den Benutzercode nicht aus:... wenn Sie sicher wissen, dass
Elvis
das noch nicht erstellt wurde, und dasKing
hat.Aber es ermutigt Benutzer, die
the
Methode universell anzuwenden :Um dies zu vervollständigen, können Sie auch überschreiben
__delattr__()
, um eine Ausnahme auszulösen, wenn versucht wird, eine Ausnahme zu löscheninstance
, und überschreiben__del__()
, damit eine Ausnahme ausgelöst wird (es sei denn, wir wissen, dass das Programm endet ...).Weitere Verbesserungen
Mein Dank geht an diejenigen, die mit Kommentaren und Änderungen geholfen haben, von denen weitere willkommen sind. Während ich Jython verwende, sollte dies allgemeiner funktionieren und threadsicher sein.
Anmerkungen:
__new__
__new__
müssen Sie mit @classmethod dekorieren oder__new__
es handelt sich um eine ungebundene Instanzmethodethe
eine Eigenschaft auf Klassenebene erstellen und möglicherweise in umbenennen könneninstance
quelle
__new
__ anstelle von __ zu verwenden__init__
, da es nur auf Klassenattribute einwirkt und dies verhindert, dass es kurzzeitig eine zweite Instanz gibt. Der Unterschied zwischen dieser und Methode 2 besteht darin, ob der Versuch, mehr als einmal zu initialisieren, die einzelne Instanz zurückgibt oder eine Ausnahme auslöst. Ich denke, ich bin froh, dass entweder das Singleton-Muster erfüllt ist, eines einfacher zu verwenden ist, während das andere expliziter ist, dass es ein Singleton ist.__init__
Unterklassen, aber während dies die Dinge einfacher macht, ist es nicht erforderlich__init__
so modifiziert , dass es hoffentlich unterklassifizierbar sein sollte ...the
könnte wahrscheinlich aus ähnlichen Gründen von einer Klassenmethode profitierenEin Liner (ich bin nicht stolz, aber er macht den Job):
quelle
Wenn Sie keine verzögerte Initialisierung der Singleton-Instanz benötigen, sollte Folgendes einfach und threadsicher sein:
Auf diese Weise
A
wird ein Singleton beim Modulimport initialisiert.quelle
Vielleicht verstehe ich das Singleton-Muster falsch, aber meine Lösung ist einfach und pragmatisch (pythonisch?). Dieser Code erfüllt zwei Ziele
Foo
überall zugänglich (global).Foo
existieren.Dies ist der Code.
Ausgabe
quelle
Nachdem ich einige Zeit damit zu kämpfen hatte, kam ich schließlich auf Folgendes, so dass das Konfigurationsobjekt nur einmal geladen wurde, wenn es von separaten Modulen aufgerufen wurde. Mit der Metaklasse kann eine globale Klasseninstanz im eingebauten Diktat gespeichert werden. Dies scheint derzeit die beste Möglichkeit zu sein, ein ordnungsgemäßes globales Programm zu speichern.
quelle
Ich kann mich nicht erinnern, wo ich diese Lösung gefunden habe, aber ich finde sie aus Sicht von Nicht-Python-Experten am elegantesten:
Warum mag ich das? Keine Dekoratoren, keine Metaklassen, keine Mehrfachvererbung ... und wenn Sie entscheiden, dass es kein Singleton mehr sein soll, löschen Sie einfach die
__new__
Methode. Da ich neu in Python bin (und OOP im Allgemeinen), erwarte ich, dass mich jemand klar macht, warum dies ein schrecklicher Ansatz ist.quelle
__new__
. Wiederhole dich nicht .*args
und**kwargs
und macht dann nichts mit ihnen? Geben Sie sie aufdict.__new__
diese Weise weiter :dict.__new__(cls, *args, **kwargs)
.__init__
Methode jedes Mal auf, wenn die Klasse aufgerufen wird. Wenn Ihre__init__
Methode tatsächlich etwas getan hat, würden Sie das Problem bemerken. Wann immer Sie dies tunSomeSingleton()
, wird der Status Ihres Singletons durch die__init__
Methode zurückgesetzt.Dies ist meine bevorzugte Methode zur Implementierung von Singletons:
quelle
Diese Antwort ist wahrscheinlich nicht das, wonach Sie suchen. Ich wollte einen Singleton in dem Sinne, dass nur dieses Objekt zum Vergleich seine Identität hatte. In meinem Fall wurde es als Sentinel-Wert verwendet . Auf die die Antwort sehr einfach ist, machen Sie ein beliebiges Objekt
mything = object()
und nach Pythons Natur wird nur dieses Ding seine Identität haben.quelle
eval
oder zu tunimportlib.reload
.Diese Lösung verursacht eine gewisse Verschmutzung des Namespaces auf Modulebene (drei Definitionen statt nur einer), aber ich finde es einfach zu folgen.
Ich würde gerne so etwas schreiben können (verzögerte Initialisierung), aber leider sind Klassen im Körper ihrer eigenen Definitionen nicht verfügbar.
Da dies nicht möglich ist, können wir die Initialisierung und die statische Instanz in aufteilen
Eifrige Initialisierung:
Faule Initialisierung:
Eifrige Initialisierung:
quelle