Implémenter le modèle Singleton en Python

Motif singleton

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.

Comment écraser la méthode __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.

Comment utiliser la métaclasse

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.

Mise en œuvre à remplacer par Borg

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.

Mise en œuvre concise

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.

référence

--Expert Python Programming Revised 2nd Edition

Recommended Posts

Implémenter le modèle Singleton en Python
Motif singleton en Python
Apprenez le modèle de conception "Prototype" avec Python
Apprenez le modèle de conception "Builder" avec Python
Apprenez le modèle de conception "Flyweight" en Python
Apprenez le modèle de conception "Observer" en Python
Apprenez le modèle de conception "Memento" avec Python
Apprenez le modèle de conception "Commande" en Python
Apprenez le modèle de conception "Visiteur" avec Python
Apprenez le modèle de conception "Bridge" avec Python
Apprenez le modèle de conception "Mediator" avec Python
Apprenez le modèle de conception "Décorateur" avec Python
Apprenez le modèle de conception "Iterator" avec Python
Apprenez le modèle de conception «Stratégie» avec Python
Apprenez le modèle de conception "Composite" avec Python
Apprenez le modèle de conception "Singleton" avec Python
Apprenez le modèle de conception "État" en Python
Apprenez le modèle de conception "Adapter" avec Python
Motif singleton en Java
Modèle de visiteur en Python
Mettre en œuvre des recommandations en Python
Implémenter XENO avec python
Implémenter sum en Python
Implémenter Traceroute dans Python 3
Apprenez le modèle de conception "Abstract Factory" avec Python
Apprenez le modèle de conception "Méthode de modèle" en Python
Apprenez le modèle de conception "Méthode d'usine" en Python
Trouver des erreurs en Python
Implémenter Naive Bayes dans Python 3.3
Implémenter d'anciens chiffrements en python
Implémenter Redis Mutex en Python
Implémenter l'extension en Python
Mettre en œuvre un RPC rapide en Python
Implémenter l'algorithme de Dijkstra en python
Implémenter le bot de discussion Slack en Python
Apprenez le modèle de conception «Chaîne de responsabilité» en Python
Implémenter la solution de l'algèbre de Riccati en Python
Mettre en œuvre l'apprentissage de l'empilement en Python [Kaggle]
Implémenter la fonction power.prop.test de R en python
Obtenir l'API arXiv en Python
Python dans le navigateur: la recommandation de Brython
Enregistrez le fichier binaire en Python
Python Singleton
Frappez l'API Sesami en Python
Obtenez le chemin du bureau en Python
Obtenez le chemin du script en Python
Accédez à l'API Web en Python
J'ai essayé d'implémenter la fonction d'envoi de courrier en Python
J'ai écrit la file d'attente en Python
Calculer le mois précédent en Python
Examiner la classe d'un objet avec python
Obtenez le chemin du bureau en Python
Implémentez rapidement l'API REST en Python
Obtenez le nom d'hôte en Python
Accéder à l'API Twitter avec Python
La première étape de Python Matplotlib
J'ai écrit la pile en Python
Maîtriser le module lowref en Python
Est-il possible de réaliser la loi de l'inversion de dépendance (DIP) en Python en premier lieu?
Charger le SDK Python distant avec IntelliJ