2010-04-26 18 views
95

Ho classi Python, di cui ho bisogno di una sola istanza in runtime, quindi sarebbe sufficiente avere gli attributi solo una volta per classe e non per istanza. Se ci fosse più di un'istanza (che non accadrà), tutte le istanze dovrebbero avere la stessa configurazione. Mi chiedo quale delle seguenti opzioni sarebbe migliore o più Python "idiomatico".Variabili di istanza rispetto a variabili di classe in Python

variabili di classe:

class MyController(Controller): 

    path = "something/" 
    children = [AController, BController] 

    def action(self, request): 
    pass 

variabili di istanza:

class MyController(Controller): 

    def __init__(self): 
    self.path = "something/" 
    self.children = [AController, BController] 

    def action(self, request): 
    pass 
+4

Dopo aver letto questa domanda e aver visto la risposta, una delle mie prime domande è stata: "Come posso accedere alle variabili di classe?" - Questo perché fino a questo punto ho usato solo variabili d'istanza. In risposta alla mia domanda, lo fai tramite il nome della classe stessa, anche se tecnicamente puoi farlo anche tramite un'istanza. Ecco un link da leggere per chiunque altro con la stessa domanda: http://stackoverflow.com/a/3434596/4561887 –

risposta

138

Se si dispone di una sola istanza in ogni caso, è meglio per fare tutte le variabili per-esempio, semplicemente perché saranno accessibili (una un po ') più veloce (un livello in meno di "ricerca" a causa dell'ereditarietà da una classe all'altra) e non ci sono aspetti negativi da valutare rispetto a questo piccolo vantaggio.

+6

Mai sentito parlare del pattern Borg? Solo avere un'istanza era il modo sbagliato per averlo in primo luogo. –

+378

@Devin, sì, ho sentito parlare del pattern Borg, dal momento che sono io che l'ho introdotto (nel 2001, cfr http://code.activestate.com/recipes/66531-singleton-we-dont-need -no-stinkin-singleton-the-bo/;-). Ma non c'è nulla di sbagliato, in casi semplici, semplicemente con una singola istanza senza applicazione. –

+0

Ci sono dei parametri? – user1767754

18

In caso di dubbio, probabilmente si desidera un attributo di istanza.

Gli attributi di classe sono meglio riservati per casi speciali in cui hanno senso. L'unico caso d'uso molto comune sono i metodi. Non è non comune utilizzare gli attributi di classe per le costanti di sola lettura che le istanze devono conoscere (anche se l'unico vantaggio è se si desidera anche l'accesso da all'esterno della classe), ma si dovrebbe essere cauti nell'archiviazione qualsiasi stato in loro, che è raramente quello che vuoi. Anche se avrai solo un'istanza, dovresti scrivere la classe come faresti con qualsiasi altra, che di solito significa usare gli attributi di istanza.

+0

Le variabili di classe sono un tipo di costanti di sola lettura. Se Python mi permette di definire le costanti, l'avrei scritto come costanti. – deamon

+1

@deamon, sono leggermente più propensi a mettere le mie costanti completamente al di fuori delle definizioni di una classe e nominarle in maiuscolo. Metterli nella classe va bene. Rendendoli attributi di istanza non farà male nulla, ma potrebbe essere un po 'strano. Non penso che questo sia un problema in cui la community ottiene troppo spesso una delle opzioni. –

+0

@MikeGraham FWIW, [Style Guide Python di Google] (http://google-styleguide.googlecode.com/svn/trunk/pyguide.html?showone=Global_variables#Global_variables) suggerisce di evitare di variabili globali a favore di variabili di classe. Ci sono tuttavia delle eccezioni. – Dennis

36

eco ulteriori consigli di Mike e Alex e aggiungendo il mio colore ...

utilizzando gli attributi istanza sono il tipico, Python più idiomatica. gli attributi di classe non sono spesso usati - almeno non nel codice di produzione negli ultimi 13 anni consecutivi di Python. lo stesso vale per i metodi statici e di classe ... non molto comuni a meno che non ci sia un caso d'uso specifico o un programmatore aberrante che vuole mostrare di conoscere qualche angolo oscuro della programmazione Python.

alex cita nella sua risposta che l'accesso sarà (un po ') più veloce a causa di un livello inferiore di ricerca ... chiarisco ulteriormente per coloro che non sanno come funziona ancora, è molto simile per l'accesso variabili - la ricerca avviene in questo modo:

  1. locali
  2. nonlocals
  3. GLOBALS
  4. built-in

per l'accesso di attributo, l'ordine è:

  1. esempio
  2. classe
  3. classi base come determinato dal MRO (ordine di risoluzione metodo)

nel tuo esempio sopra, diciamo che si' sto cercando l'attributo path. quando incontra un riferimento come "self.path", Python esaminerà prima gli attributi di istanza per una corrispondenza; quando fallisce, controlla la classe da cui è stato istanziato l'oggetto.infine, cercherà le classi base. come ha affermato alex, se il tuo attributo si trova nell'istanza, non verrà rimandato alla classe, quindi il tuo piccolo risparmio di tempo.

tuttavia, se ti ostini a attributi di classe, si dovrà rinunciare a questo piccolo pezzo di prestazioni, o, l'altra alternativa è quella di fare riferimento all'oggetto tramite la classe al posto dell'istanza, ad esempio, MyController.path invece di self.path. questa è una ricerca diretta che aggirerà la ricerca differita, ma come menziona alex sotto, questa è una variabile globale, quindi perdi quel pezzo che pensavi di voler salvare (a meno che non crei un riferimento locale al nome della classe [globale]).

+0

@wescpy, ma 'MyController' è cercato nelle globali, quindi il costo totale è superiore a' self.path' dove 'path' è una variabile di istanza (poiché' self' è _local_ al metodo == super-veloce consultare). –

+0

ah, vero. buona pesca. Immagino che l'unica soluzione è creare un riferimento locale ... a questo punto, non ne vale la pena. – wescpy

Problemi correlati