Classi Python con una sola istanza: quando creare un'istanza (singola) di classe e quando invece lavorare con la classe?


11

Data una classe Python che verrà istanziata una sola volta, cioè ci sarà un solo oggetto della classe. Mi chiedevo in quali casi ha senso creare una singola istanza di classe invece di lavorare direttamente con la classe.

C'è una domanda simile , ma ha un focus diverso:

  1. si tratta di raggruppare variabili e funzioni globali in una classe e
  2. Non è specifico di Python. Quest'ultimo significa che non considera il fatto che (in Python) anche le classi siano oggetti.

AGGIORNARE:

In Python, posso fare quanto segue sia con le classi che con gli oggetti:

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

Quindi non vedo come la scelta tra una classe e un'istanza di quella classe riguardi lo stato (in Python). Posso mantenere uno stato con uno dei due.

Inoltre, la motivazione per creare la mia istanza di classe / classe non riguarda l'applicazione di un requisito Singleton.

Inoltre, non si tratta tanto di creare un nuovo tipo.

La motivazione è quella di raggruppare codice e dati correlati e avere un'interfaccia ad esso. Questo è il motivo per cui inizialmente l'ho modellato come una classe in un diagramma di classe. Solo quando si è arrivati ​​all'implementazione ho iniziato a chiedermi se creare un'istanza di questa classe o meno.

Risposte:


16

Data una classe Python che verrà istanziata una sola volta, cioè ci sarà un solo oggetto della classe. Mi chiedevo in quali casi ha senso creare una singola istanza di classe invece di lavorare direttamente con la classe.

Quindi è questo:

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

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

contro questo?

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

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

Raccomandazione

Preferirei sicuramente quello che dovrebbe essere istanziato. Quando crei un "tipo di cosa" che implica che crei cose di quel tipo.

La motivazione è quella di raggruppare codice e dati correlati e avere un'interfaccia ad esso.

Detto questo, perché non usare semplicemente un modulo poiché tutto ciò che vuoi è uno spazio dei nomi? I moduli sono singoli, codice e dati relativi al gruppo, e questo è un po 'più semplice e probabilmente sarebbe considerato più Pythonic:

var1 ='foo'

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

Quindi l'utilizzo sarebbe invece di:

from modules.singleton import Singleton
Singleton.foobar()

o

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

Fai questo:

from modules import singleton
singleton.foobar()

3
Grazie per la tua risposta. Consiglieresti davvero di creare un nuovo modulo (un nuovo file .py) per ogni funzione (incl. Variabili)? Ciò potrebbe comportare molti piccoli file .py. O raggrupperesti tutte le funzioni (almeno in qualche modo correlate) "senza classi" in un modulo?
langlauf.io,

Un'altra osservazione: scrivi "poiché tutto ciò che vuoi è uno spazio dei nomi". Quello che voglio è raggruppare il codice correlato, ovvero funzioni e dati, in un unico posto e avere un'interfaccia ad esso. Non si tratta tanto di creare un "Tipo". Durante la progettazione, ciò comporterebbe comunque una classe in un diagramma di classe, no?
langlauf.io,

2

Mi chiedevo in quali casi ha senso creare una singola istanza di classe invece di lavorare direttamente con la classe.

Questa è una di quelle cose che causeranno una guerra religiosa se ci entrerai troppo.

Ma in generale una pratica che ho visto molte volte è che i metodi di classe dovrebbero interessarsi solo alla creazione di istanze di quella classe.

Se pensi a cosa sia una classe, a quale sia il suo scopo / comportamento, allora ha senso. Lo scopo di una classe è creare istanze di oggetti basati su se stesso . È un progetto che può anche costruire l'edificio. Una classe "Utente" crea oggetti "utente". Una classe "Cane" crea oggetti "cane" ecc. Ecc

Supponiamo che questo sia il comportamento di una classe, quindi ha senso che i metodi aggiunti alla classe "X" si occupino della creazione di oggetti "x".

Quindi, anche se hai sempre bisogno di un oggetto "x", dovresti comunque istanziarlo.

L'aggiunta di metodi alla classe X che non sono correlati alla creazione di istanze di oggetti "x" può generare confusione di codice imprevisto. Naturalmente ci sono tonnellate di esempi nel mondo reale in cui le persone lo hanno fatto comunque, ma come ho detto, quel percorso porta alla guerra religiosa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.