Singleton ist eines der Entwurfsmuster, mit denen eine Klasse nur ein Instanzobjekt haben kann. Wenn Sie dies beispielsweise verwenden, indem Sie eine Klasse für die Verbindung mit der Datenbank erstellen, können Sie Code unter der Annahme schreiben, dass mehrere Instanzen die Datenbank nicht gleichzeitig betreiben, sodass Sie Synchronisation und Daten im Speicher verwalten können. Sie werden in der Lage sein. Dies erleichtert auch die Steuerung der Parallelität. Wenn Sie beispielsweise ein Dokument haben, das eine eindeutige Dokument-ID reserviert, ist es besser, ein Dienstprogramm zu haben, um die Arbeit zu erledigen. Daher ist es besser, das Singleton-Muster zu übernehmen.
Sie können die Methode new () `überschreiben und wie folgt implementieren:
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance
Erstellen Sie mehrere Instanzen aus dieser Klasse und überprüfen Sie die ID. Sie können sehen, dass dasselbe Objekt erstellt wurde.
obj1 = Singleton()
obj2 = Singleton()
print(id(obj1) == id(obj2))
# True
print(obj1 == obj2)
# True
Diese Methode weist jedoch einige Fallstricke auf. Erstellen Sie Unterklassen, die von dieser Klasse erben, und erstellen Sie jeweils Instanzen.
class SubSingleton(Singleton):
pass
print(Singleton())
# <__main__.Singleton object at 0x10cfda9e8>
print(SubSingleton())
# <__main__.Singleton object at 0x10cfda9e8>
Bei Betrachtung dieses Ergebnisses wird die Unterklasseninstanz als Instanz der Basisklasse erstellt. Darüber hinaus besteht das Problem, dass sich das Verhalten in Abhängigkeit von der Reihenfolge ändert, in der die Instanzen erstellt werden.
class SubSingleton(Singleton):
pass
print(SubSingleton())
# <__main__.SubSingleton object at 0x10c3f57b8>
print(Singleton())
# <__main__.Singleton object at 0x10c3f5748>
Wenn das Verhalten je nach Reihenfolge unterschiedlich ist, ist es schwierig, das Verhalten vorherzusagen. Insbesondere für große Anwendungen wird das Debuggen schwierig. Dies liegt daran, dass die Anwendung abhängig von den Aktionen des Benutzers und der Reihenfolge des Imports zerstört werden kann. Im Allgemeinen sollten Sie vermeiden, die Singleton-Klasse zu erben und zu verwenden. Die Methode zum Überschreiben der Methode new () `ist ebenfalls eine sichere Implementierung, sofern Sie keine Unterklassen erstellen. In einigen Sprachen, z. B. in C #, können Sie die Vererbung mithilfe des versiegelten Modifikators verbieten. Python kann die Vererbung jedoch nicht verbieten und kann falsch implementiert werden. Daher ist es sicherer, den Fall der Vererbung zu betrachten.
Sie können eine Klasse Singleton erstellen, indem Sie die Methode call () der Metaklasse überschreiben.
class MetaSingleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class Singleton(metaclass = MetaSingleton):
pass
class SubSingleton(Singleton):
pass
print(Singleton() == Singleton())
# True
print(SubSingleton() == SubSingleton())
# True
print(Singleton())
# <__main__.Singleton object at 0x10ce84ef0>
print(SubSingleton())
# <__main__.SubSingleton object at 0x10ce84e48>
#Versuchen Sie, die Generierungsreihenfolge umzukehren
print(SubSingleton())
# <__main__.SubSingleton object at 0x10ce84c18>
print(Singleton())
# <__main__.Singleton object at 0x10ce84cf8>
Wenn Sie die obige Implementierung überprüfen, wird aus jeder Klasse nur eine Instanz generiert, und Sie können sie unabhängig von der Generierungsreihenfolge implementieren. Dies ist also besser als die Methode zum Überschreiben der Methode "new ()". Ich denke es ist sicher.
Diese Methode wurde von Alex Martelli, dem Autor von "Python Cookbook", vorgeschlagen. Es verhält sich wie ein Singleton, jedoch mit einer anderen Struktur, sodass __dict__
alle Klasseninstanzen gemeinsam nutzt. Dies nennt man Borg oder Monostate.
class Borg(object):
_state = {}
def __new__(cls, *args, **kwargs):
ob = super().__new__(cls, *args, **kwargs)
ob.__dict__ = cls._state
return ob
print(Borg() == Borg())
# False
Durch das Erstellen mehrerer Borg-Klassen werden unterschiedliche Instanzen erstellt. Es kann jedoch als Alternative zu Singleton verwendet werden, da sich mehrere Instanzen so verhalten, als wären sie eine. Singleton garantiert eine Instanz, aber was noch wichtiger ist, es garantiert ein Verhalten. Borg, das die Einzigartigkeit des Verhaltens garantieren kann, ist also eine Alternative zu Singleton. Diese Methode hat jedoch auch eine Falle. Sie können das Problem lösen, das Sie in die Unterklasse einfügen können, dies hängt jedoch von der Implementierung der Unterklasse ab. Wenn Sie beispielsweise "getattr" überschrieben haben, um Attribute mit "." In einer Unterklasse abzurufen, funktioniert Borg nicht ordnungsgemäß.
Bisher haben wir verschiedene Methoden eingeführt, aber die einfachste Methode besteht darin, ein Modul mit Funktionen vorzubereiten. Weil Python-Module ursprünglich Singleton-Objekte sind. Die obige Implementierungsmethode ist erforderlich, wenn Sie ein Framework wie Java verwenden. Daher denke ich nicht, dass das Singleton-Muster notwendig ist, es sei denn, es gibt besondere Umstände.
--Expert Python Programming Revised 2nd Edition
Recommended Posts