Es scheint viele Definitionsmöglichkeiten zu geben Singles in Python. Gibt es eine übereinstimmende Meinung zu Stack Overflow?
Gibt es eine einfache, elegante Möglichkeit, Singletons zu definieren? [duplicate]
Jamie
Staale
Ich sehe nicht wirklich die Notwendigkeit, da ein Modul mit Funktionen (und keine Klasse) gut als Singleton dienen würde. Alle seine Variablen wären an das Modul gebunden, das ohnehin nicht wiederholt instanziiert werden könnte.
Wenn Sie eine Klasse verwenden möchten, gibt es in Python keine Möglichkeit, private Klassen oder private Konstruktoren zu erstellen, sodass Sie sich nicht vor mehreren Instanziierungen schützen können, außer nur durch Konventionen bei der Verwendung Ihrer API. Ich würde immer noch Methoden in ein Modul einfügen und das Modul als Singleton betrachten.
-
Könnte der Konstruktor nicht einfach prüfen, ob bereits eine Instanz erstellt wurde, und eine Ausnahme auslösen, wenn dies der Fall ist?
– Casebash
16. Mai 2010 um 7:56 Uhr
-
Dies ist in Ordnung, solange Sie die Vererbung nicht als Teil Ihres Entwurfs verwenden müssen. In diesem Fall sind die meisten der folgenden Antworten besser geeignet
– Jim Jeffries
6. Juni 2011 um 8:23 Uhr
-
Es ist kaputt, wenn Sie einen zyklischen Import haben
– sterbend
25. September 2012 um 10:49 Uhr
-
Was werde ich tun, wenn ich möchte, dass dieses Modul vererbbar ist?
– Yossi
26. November 2012 um 9:09 Uhr
-
Das ist meiner Meinung nach falsch. Ein Ärgernis bei Schnittstellen auf Modulebene ist die Verwaltung der Importe. Zum Beispiel Python
logging
ist eine Schnittstelle auf Modulebene. Um sicherzustellen, dass Sie danach vollständig aufräumenlogging
du musst anrufenlogging.shutdown()
. Dies bedeutet, dass Sie importieren müssenlogging
in das aufrufende Modulshutdown
. Wenn es sich um ein Singleton-Muster handelt, ist es möglich, shutdown für die Instanz in jedem Modul aufzurufen, an das es übergeben wird.– Matt
25. Februar 2016 um 6:49 Uhr
Paul Manta
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 verwenden Instance
Methode. Hier ist ein Beispiel:
@Singleton
class Foo:
def __init__(self):
print 'Foo created'
f = Foo() # Error, this isn't how you get the instance of a singleton
f = Foo.instance() # Good. Being explicit is in line with the Python Zen
g = Foo.instance() # Returns already created instance
print f is g # True
Und hier ist der Code:
class Singleton:
"""
A non-thread-safe helper class to ease implementing singletons.
This should be used as a decorator -- not a metaclass -- to the
class that should be a singleton.
The decorated class can define one `__init__` function that
takes only the `self` argument. Also, the decorated class cannot be
inherited from. Other than that, there are no restrictions that apply
to the decorated class.
To get the singleton instance, use the `instance` method. Trying
to use `__call__` will result in a `TypeError` being raised.
"""
def __init__(self, decorated):
self._decorated = decorated
def instance(self):
"""
Returns the singleton instance. Upon its first call, it creates a
new instance of the decorated class and calls its `__init__` method.
On all subsequent calls, the already created instance is returned.
"""
try:
return self._instance
except AttributeError:
self._instance = self._decorated()
return self._instance
def __call__(self):
raise TypeError('Singletons must be accessed through `instance()`.')
def __instancecheck__(self, inst):
return isinstance(inst, self._decorated)
-
Da Python im Lieferumfang enthalten ist, sollte dies Teil von a sein
desing_pattern
Standardbibliothek, danke– schneidig
31. August 2014 um 0:23 Uhr
-
@akhan Ich habe mich entschieden, Konstruktoren absichtlich nicht mit Argumenten zu unterstützen, da die Argumente nur beim ersten Mal verwendet und alle anderen Male ignoriert werden. Dadurch kann es sehr schwierig werden, Ihrem Code zu folgen, da Sie möglicherweise an verschiedenen Stellen unterschiedliche Argumente verwenden, aber möglicherweise nicht wissen, welcher dieser Aufrufe derjenige ist, der das Singleton tatsächlich initialisiert.
– Paul Manta
28. April 2017 um 7:53 Uhr
-
@akhan Wenn Sie Ihren Singleton wirklich mit Argumenten initialisieren möchten, sollten Sie einen separaten haben
initialize()
Methode, die beliebige Argumente und Würfe annehmen kann, wenn sie mehr als einmal aufgerufen wird.– Paul Manta
28. April 2017 um 7:54 Uhr
-
Das ist ein wirklich schlecht Singleton-Implementierung. Erstens ist es kein richtiger Dekorateur, weil es nicht verwendet wird
functools.wraps
oderfunctools.update_wrapper
. Zweitens muss die Instanz per Anruf abgerufen werdenFoo.Instance()
ist schrecklich unpythonisch und es gibt genau 0 Gründe, warum es nicht so implementiert werden konnteFoo()
stattdessen. Drittens führt das Ersetzen der Klasse auf diese Weise zu unerwarteten Ergebnissen wietype(Foo.instance()) is Foo
->False
– Aran-Fey
28. Mai 2018 um 12:59 Uhr
-
@Aran-Fey scheint, als würde diese Lösung Ihre Blase wirklich zum Platzen bringen, lol. Ich glaube nicht, dass Paul Manta jemals gesagt hat, dass dies die beste Lösung weltweit ist. Er versuchte nur, die Frage des ursprünglichen Autors zu beantworten. Ich denke, es ist eine großartige Lösung für ein “Mangel davon” in Python.
– JokerMartini
5. Juli 2019 um 15:17 Uhr
jojo
Sie können die überschreiben __new__
Methode so:
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(
cls, *args, **kwargs)
return cls._instance
if __name__ == '__main__':
s1 = Singleton()
s2 = Singleton()
if (id(s1) == id(s2)):
print "Same"
else:
print "Different"
-
WARNUNG: Wenn __new__() eine Instanz von cls zurückgibt, wird die Methode __init__() der neuen Instanz wie __init__(self[, …]), wobei self die neue Instanz ist und die verbleibenden Argumente die gleichen sind, die an __new__() übergeben wurden. Wenn eine Unterklasse von Singleton __init__() implementiert, wird sie mehrmals mit demselben Selbst aufgerufen. Ich landete stattdessen mit einer Fabrik.
– alsuren
8. September 2011 um 12:48 Uhr
-
Dies wäre besser, wenn Sie hier eine Metaklasse als Antwort verwenden: stackoverflow.com/a/33201/804147
– unterlaufen
23. Januar 2012 um 15:24 Uhr
-
Dies gibt die folgende Warnung aus –
singleton.py:9: DeprecationWarning: object.__new__() takes no parameters
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
– Siddhant
2. Januar 2013 um 16:17 Uhr
-
@Siddhant: Schlimmer noch, in Python 3 wird diese Warnung zu einem Fehler. Sehen bugs.python.org/issue1683368 und blog.jaraco.com/2014/05/… für mehr Details.
– Jason R. Coombs
14. Juni 2014 um 16:36 Uhr
-
Ein weiteres Problem besteht darin, diese Implementierung in Unterklassen umzuwandeln. Unterklassen enthalten einen Verweis auf die Oberklasse in
_instance
, wenn es zuvor instanziiert wurde (aber nicht umgekehrt). Um das zu beheben, können Sie ersetzenif not cls._instance
mitif type(cls._instance) != cls
(was funktioniert, weilNone
ist nichtSingleton
undSingleton
ist nichtSubSingleton(Singleton)
).– rel
15. Juni um 10:39 Uhr
Peter Hofmann
Ein etwas anderer Ansatz zur Implementierung des Singletons in Python ist der Borg-Muster von Alex Martelli (Google-Mitarbeiter und Python-Genie).
class Borg:
__shared_state = {}
def __init__(self):
self.__dict__ = self.__shared_state
Anstatt also alle Instanzen dazu zu zwingen, dieselbe Identität zu haben, teilen sie sich den Status.
Zugespitzt
Der Modulansatz funktioniert gut. Wenn ich unbedingt ein Singleton brauche, bevorzuge ich den Metaclass-Ansatz.
class Singleton(type):
def __init__(cls, name, bases, dict):
super(Singleton, cls).__init__(name, bases, dict)
cls.instance = None
def __call__(cls,*args,**kw):
if cls.instance is None:
cls.instance = super(Singleton, cls).__call__(*args, **kw)
return cls.instance
class MyClass(object):
__metaclass__ = Singleton
-
Dieses Muster verstößt gegen das „Single Responsibility Principle“ (c2.com/cgi/wiki?SingleResponsibilityPrinciple). Siehe Punkt (2) in blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx.
– Haridsv
20. Mai 2010 um 19:21 Uhr
-
@haridsv Ich stimme nicht zu. Die Tatsache, dass die Klasse ein Singleton ist ist in der Metaklassenimplementierung abstrahiert — die Klasse selbst weiß oder kümmert sich nicht darum, dass sie ein Singleton ist, da sie nicht für die Durchsetzung dieser Anforderung zuständig ist, die Metaklasse ist es. Die folgende Methode ist jedoch eindeutig ein Verstoß, wie Sie bemerken. Die Methode der Basisklasse liegt irgendwo dazwischen.
– agf
23. Juli 2011 um 4:38 Uhr
-
@dare2be: Könnte das von Ihnen erwähnte Kopierproblem nicht einfach dadurch behoben werden, dass die Metaklasse auch a hinzufügt
__deepcopy__()
Methode zur erstellten Klasse?– Martinau
3. Dezember 2012 um 18:18 Uhr
-
@martineau: Das ist
type.__init__
es überschreibt, nichtMyClass.__init__
– Erich
3. Februar 2014 um 0:00 Uhr
-
Ein anderer Stackoverflow-Kommentar erwähnte, dass Sie diesen Fehler durch Überschreiben beheben können new__() “` Klasse SingletonMeta(Typ): def _new__(cls, name, bases, dict): dict[‘_deepcopy‘] = Diktat[‘copy‘] = lambda self, *args: self return super(SingletonMeta, cls).__new__(cls, name, bases, dict) “` – stackoverflow.com/a/9887928/748503
– James McGuigan
24. November 2017 um 18:38 Uhr
Peter Mortensen
Sehen Sie sich diese Implementierung an PEP318Implementierung des Singleton-Musters mit einem Dekorateur:
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass:
...
-
Dieses Muster verstößt gegen das „Single Responsibility Principle“ (c2.com/cgi/wiki?SingleResponsibilityPrinciple). Siehe Punkt (2) in blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx.
– Haridsv
20. Mai 2010 um 19:21 Uhr
-
@haridsv Ich stimme nicht zu. Die Tatsache, dass die Klasse ein Singleton ist ist in der Metaklassenimplementierung abstrahiert — die Klasse selbst weiß oder kümmert sich nicht darum, dass sie ein Singleton ist, da sie nicht für die Durchsetzung dieser Anforderung zuständig ist, die Metaklasse ist es. Die folgende Methode ist jedoch eindeutig ein Verstoß, wie Sie bemerken. Die Methode der Basisklasse liegt irgendwo dazwischen.
– agf
23. Juli 2011 um 4:38 Uhr
-
@dare2be: Könnte das von Ihnen erwähnte Kopierproblem nicht einfach dadurch behoben werden, dass die Metaklasse auch a hinzufügt
__deepcopy__()
Methode zur erstellten Klasse?– Martinau
3. Dezember 2012 um 18:18 Uhr
-
@martineau: Das ist
type.__init__
es überschreibt, nichtMyClass.__init__
– Erich
3. Februar 2014 um 0:00 Uhr
-
Ein anderer Stackoverflow-Kommentar erwähnte, dass Sie diesen Fehler durch Überschreiben beheben können new__() “` Klasse SingletonMeta(Typ): def _new__(cls, name, bases, dict): dict[‘_deepcopy‘] = Diktat[‘copy‘] = lambda self, *args: self return super(SingletonMeta, cls).__new__(cls, name, bases, dict) “` – stackoverflow.com/a/9887928/748503
– James McGuigan
24. November 2017 um 18:38 Uhr
Das Python-Dokumentation deckt das ab:
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
Ich würde es wahrscheinlich so umschreiben, dass es eher so aussieht:
class Singleton(object):
"""Use to create a singleton"""
def __new__(cls, *args, **kwds):
"""
>>> s = Singleton()
>>> p = Singleton()
>>> id(s) == id(p)
True
"""
it_id = "__it__"
# getattr will dip into base classes, so __dict__ must be used
it = cls.__dict__.get(it_id, None)
if it is not None:
return it
it = object.__new__(cls)
setattr(cls, it_id, it)
it.init(*args, **kwds)
return it
def init(self, *args, **kwds):
pass
class A(Singleton):
pass
class B(Singleton):
pass
class C(A):
pass
assert A() is A()
assert B() is B()
assert C() is C()
assert A() is not B()
assert C() is not B()
assert C() is not A()
Es sollte relativ sauber sein, dies zu erweitern:
class Bus(Singleton):
def init(self, label=None, *args, **kwds):
self.label = label
self.channels = [Channel("system"), Channel("app")]
...
-
+1, weil er der einzige ist, der die Implementierung von Guido van Rossum erwähnt. Ihre eigene Version ist jedoch falsch: Sie sollten nicht verwenden
hasattr
undgetattr
Innerhalb__new__
wie sie beide rufenobject.__getattribute__
die wiederum Ihre nachschlägt"__self__"
-Attribut durch die gesamte Klassenhierarchie statt nur durch die aktuelle Klasse. Wenn Guido verwendet__dict__
für den Attributzugriff, der einen Grund hat. Versuchen:class A(GuidoSingleton): pass
,class B(A): pass
,class C(YourSingleton): pass
,class D(C): pass
,print(A(), B(), C(), D())
. Alle Unterklassen verweisen auf dieselbe Instanz mitYourSingleton
!– Maggyero
15. Dezember 2017 um 16:56 Uhr
-
+1, um uns daran zu erinnern, dass die Python-Dokumentation immer der beste Ort ist, um mit der Suche nach Singleton- und anderen Entwurfsmustern zu beginnen.
– Benutzer-Sternchen
13. November 2018 um 0:58 Uhr
Singletons sind pathologische Lügnernicht wahr?
– Jonas Byström
5. Juli 2012 um 15:01 Uhr
“Diese Frage passt nicht gut zu unserem Q & A-Format” – Ich denke, dies ist keine subjektive Frage. Gibt es eine Möglichkeit, solche Fragen so zu stellen, dass sie in das SO Q & A-Format passen?
– binithb
13. September 2014 um 22:13 Uhr
Ich stimme nicht zu, dass dies nicht konstruktiv ist. Könnte es wieder geöffnet werden, wenn es verschoben wird programers.stackexchange.com ?
– langlauf.io
6. August 2015 um 9:35 Uhr
@stackoverflowwww nein, weil es meinungsbasiert ist und progs.SE das nicht mag.
– Ratschenfreak
6. August 2015 um 9:44 Uhr
@ratchetfreak Was die Frage populär macht, ist, dass Leute wie ich nach verschiedenen Möglichkeiten suchen, Singletons in Python zu erstellen. Es gibt Alternativen mit Vor- und Nachteilen oder die nur in bestimmten Situationen geeignet sind. Die Frage könnte umformuliert werden a la “Welche verschiedenen Möglichkeiten gibt es in Python, um ein Singleton zu erstellen? Mich interessiert besonders der Unterschied zwischen Lösungen, die auf einer Klasse basieren, und solchen, die auf einer Klasseninstanz basieren.”
– langlauf.io
6. August 2015 um 9:49 Uhr