Classes Python avec une seule instance: quand créer une instance de classe (unique) et quand travailler avec la classe à la place?

11

Étant donné une classe Python qui ne sera instanciée qu'une seule fois, c'est-à-dire qu'il n'y aura qu'un seul objet de la classe. Je me demandais dans quels cas il était logique de créer une instance de classe unique au lieu de travailler directement avec la classe à la place.

Il y a une question similaire , mais elle a un objectif différent:

  1. il s'agit de regrouper les variables et fonctions globales dans une classe et
  2. Ce n'est pas spécifique à Python. Ce dernier signifie qu'il ne tient pas compte du fait que (en Python) les classes sont également des objets.

METTRE À JOUR:

En Python, je peux faire ce qui suit avec les classes et les objets:

class A(object):
    pass

A.some_state_var = True
# Then later
A.some_state_var = False


my_a = A()

my_a.some_state_var = True
# Then later
my_a.some_state_var = False

Je ne vois donc pas comment le choix entre une classe et une instance de cette classe concerne l'état (en Python). Je peux maintenir un état avec l'un ou l'autre.

En outre, la motivation pour créer ma classe / instance de classe ne consiste pas à appliquer une exigence Singleton.

De plus, il ne s'agit pas tant de créer un nouveau type.

La motivation est de regrouper le code et les données connexes et d'avoir une interface avec eux. C'est pourquoi je l'ai initialement modélisé en tant que classe dans un diagramme de classes. Ce n'est que pour l'implémentation que j'ai commencé à me demander s'il fallait instancier cette classe ou non.

langlauf.io
la source

Réponses:

16

Étant donné une classe Python qui ne sera instanciée qu'une seule fois, c'est-à-dire qu'il n'y aura qu'un seul objet de la classe. Je me demandais dans quels cas il était logique de créer une instance de classe unique au lieu de travailler directement avec la classe à la place.

C'est donc ça:

class Singleton:
    '''don't bother instantiating me'''
    clsvar1 = 'foo'

    @classmethod
    def foobar(cls, *args, **kwargs):
        if condition():
            cls.clsvar1 = 'bar'

contre ça?

class Singleton:
    '''instantiate and use me'''
    def __init__(self):
        self.var1 = 'foo'

    def foobar(self, *args, **kwargs):
        if condition():
            self.var1 = 'bar'

Recommandation

Je préférerais certainement celui qui est destiné à être instancié. Lorsque vous créez un "type de chose", cela implique que vous créez des choses de ce type.

La motivation est de regrouper le code et les données connexes et d'avoir une interface avec eux.

Cela dit, pourquoi ne pas simplement utiliser un module car tout ce que vous voulez, c'est un espace de noms? Les modules sont des singletons, du code et des données liés au groupe, ce qui est un peu plus simple et serait probablement considéré comme plus Pythonic:

var1 ='foo'

def foobar(*args, **kwargs):
    global var1
    if condition():
        var1 = 'bar'

Donc, l'utilisation serait au lieu de:

from modules.singleton import Singleton
Singleton.foobar()

ou

from modules.singleton import Singleton
the_singleton = Singleton()
the_singleton.foobar()

faites ceci:

from modules import singleton
singleton.foobar()
Aaron Hall
la source
3
Merci pour votre réponse. Souhaitez-vous vraiment suggérer de créer un nouveau module (un nouveau fichier .py) pour chaque fonction (y compris les variables)? Cela pourrait entraîner de nombreux petits fichiers .py. Ou regrouperiez-vous toutes les fonctions et variables "sans classe" (au moins d'une manière ou d'une autre) dans un module?
langlauf.io
Encore une remarque: vous écrivez "car tout ce que vous voulez, c'est un espace de noms". Ce que je veux, c'est regrouper le code associé, c'est-à-dire les fonctions et les données, en un seul endroit et y avoir une interface. Il ne s'agit pas tant de créer un "Type". Pendant la conception, cela se traduirait de toute façon par une classe dans un diagramme de classe, n'est-ce pas?
langlauf.io
2

Je me demandais dans quels cas il était logique de créer une instance de classe unique au lieu de travailler directement avec la classe à la place.

C'est l'une de ces choses qui provoquera une guerre de religion si vous y entrez trop.

Mais en général, une pratique que j'ai vue à plusieurs reprises est que les méthodes de classe ne devraient se préoccuper que de créer des instances de cette classe.

Si vous pensez à ce qu'est une classe, quel est son but / comportement, alors cela a du sens. Le but d'une classe est de créer des instances d'objets qui sont basées sur elle-même . C'est un plan qui peut également construire le bâtiment. Une classe "Utilisateur" crée des objets "utilisateur". Une classe "Chien" crée des objets "chien" etc etc

Étant donné que c'est le comportement d'une classe, il est logique que les méthodes que vous ajoutez à la classe "X" se préoccupent de créer des objets "x".

Donc, même si vous n'avez besoin que d'un seul objet "x", vous devez toujours l'instancier.

L'ajout de méthodes à la classe X qui ne sont pas liées à la création d'instances d'objets "x" peut entraîner une confusion du code inattendu. Il y a bien sûr des tonnes d'exemples dans le monde réel où les gens l'ont fait de toute façon, mais comme je l'ai dit, ce chemin mène à la guerre de religion.

Cormac Mulhall
la source