Singleton est l'un des modèles de conception qui permet à une classe de n'avoir qu'un seul objet d'instance. En utilisant cela, par exemple, en créant une classe pour la connexion à la base de données, vous pouvez écrire du code en supposant que plusieurs instances n'opèrent pas la base de données en même temps, afin que vous puissiez gérer la synchronisation et les données en mémoire. Vous pourrez. Cela facilite également le contrôle du parallélisme. Par exemple, si vous avez un document qui réserve un ID de document unique, il est préférable d'avoir un seul utilitaire pour faire le travail, il est donc préférable d'adopter le modèle Singleton.
__new__ ()
Vous pouvez remplacer la méthode __new__ ()
et l'implémenter comme suit:
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
Créez plusieurs instances à partir de cette classe et vérifiez l'ID. Vous pouvez voir que le même objet a été créé.
obj1 = Singleton()
obj2 = Singleton()
print(id(obj1) == id(obj2))
# True
print(obj1 == obj2)
# True
Cependant, cette méthode comporte quelques écueils. Créez des sous-classes qui héritent de cette classe et créez des instances pour chacune.
class SubSingleton(Singleton):
pass
print(Singleton())
# <__main__.Singleton object at 0x10cfda9e8>
print(SubSingleton())
# <__main__.Singleton object at 0x10cfda9e8>
En regardant ce résultat, l'instance de sous-classe est créée en tant qu'instance de la classe de base. Non seulement cela, il y a aussi le problème que le comportement change en fonction de l'ordre dans lequel les instances sont créées.
class SubSingleton(Singleton):
pass
print(SubSingleton())
# <__main__.SubSingleton object at 0x10c3f57b8>
print(Singleton())
# <__main__.Singleton object at 0x10c3f5748>
Si le comportement est différent selon l'ordre, il sera difficile de prédire le comportement. Surtout pour les grandes applications, il devient difficile de déboguer. En effet, l'application peut être détruite en fonction des actions de l'utilisateur et de l'ordre d'importation.
En général, vous devez éviter d'hériter et d'utiliser la classe Singleton. La méthode d'écrasement de la méthode __new__ ()
est également une implémentation sûre sauf si vous créez des sous-classes. Dans certains langages, par exemple, en C #, vous pouvez interdire l'héritage en utilisant le modificateur scellé. Cependant, Python ne peut pas interdire l'héritage et peut être implémenté de manière incorrecte. Par conséquent, il est plus sûr de considérer le cas de l'héritage.
Vous pouvez créer une classe Singleton en écrasant la méthode __call__ ()
de la métaclasse.
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>
#Essayez d'inverser l'ordre de génération
print(SubSingleton())
# <__main__.SubSingleton object at 0x10ce84c18>
print(Singleton())
# <__main__.Singleton object at 0x10ce84cf8>
Si vous vérifiez l'implémentation ci-dessus, une seule instance est générée à partir de chaque classe, et vous pouvez l'implémenter quel que soit l'ordre de génération, donc c'est mieux que la méthode d'écrasement de la méthode __new __ ()
. Je pense que c'est sûr.
Cette méthode a été proposée par Alex Martelli, l'auteur de "Python Cookbook". Il se comporte comme un Singleton, mais avec une structure différente, de sorte que __dict__
partage toutes les instances de classe. Cela s'appelle Borg, ou 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
La création de plusieurs classes Borg créera différentes instances. Néanmoins, il peut être utilisé comme alternative à Singleton car plusieurs instances se comportent comme si elles n'en étaient qu'une. Singleton garantit une instance, mais plus important encore, il garantit un comportement. Ainsi Borg, qui peut garantir l'unicité du comportement, est une alternative à Singleton.
Cependant, cette méthode a également un piège. Vous pouvez résoudre le problème que vous pouvez mettre dans la sous-classe, mais cela dépend de l'implémentation de la sous-classe. Par exemple, si vous avez écrasé __getattr__
, qui est le processus pour obtenir des attributs avec .
dans une sous-classe, Borg ne fonctionnera pas correctement.
Jusqu'à présent, nous avons introduit diverses méthodes, mais la méthode la plus simple est de préparer un module avec des fonctions. Parce que les modules Python sont à l'origine des objets Singleton. La méthode d'implémentation ci-dessus est requise si vous utilisez un framework tel que Java. Je ne pense donc pas que le modèle Singleton soit nécessaire à moins de circonstances particulières.
--Expert Python Programming Revised 2nd Edition
Recommended Posts