Come posso accedere a variabili di classe "statiche" all'interno dei metodi di classe in Python?


Risposte:


166

Invece di barusare self.baro Foo.bar. L'assegnazione a Foo.barcreerà una variabile statica e l'assegnazione a self.barcreerà una variabile di istanza.


12
Foo.bar funzionerà, ma self.bar crea una variabile di istanza, non statica.
bedwyr

47
bedwyr, "print self.bar" non creerà alcuna variabile di istanza (anche se l'assegnazione a self.bar lo farà).
Constantin,

@Constantin - Non me ne sono reso conto, è una distinzione interessante. Grazie per la correzione :-)
bedwyr

2
Ma se non intendi che ci sia un ivar, è più chiaro usare Foo.classmember.
Mc

2
quando si usano variabili statiche, è una buona idea leggere i gotcha da qui: stackoverflow.com/questions/68645/… . @Constantin dà uno dei tanti gotchas.
Trevor Boyd Smith,

84

Definisci metodo di classe:

class Foo(object):
    bar = 1
    @classmethod
    def bah(cls):    
        print cls.bar

Ora, se bah()deve essere un metodo di istanza (cioè avere accesso a sé), puoi comunque accedere direttamente alla variabile di classe.

class Foo(object):
    bar = 1
    def bah(self):    
        print self.bar

3
Perché non solo Foo.bar, invece di self.__class__.bar?
Mc

15
@ Mk12: quando hai l'eredità di classe, una "variabile di classe" potrebbe trovarsi in una classe di base o in una sottoclasse. A quale vuoi fare riferimento? Dipende da cosa stai cercando di fare. Foo.bar si riferirebbe sempre ad un attributo della classe specificata, che potrebbe essere una classe base o una sottoclasse. self.__class__.bar farebbe riferimento a qualsiasi classe dell'istanza sia un tipo di.
Craig McQueen,

7
Ora abbiamo raggiunto quel punto sfortunato quando diventiamo così consapevoli dei dettagli del linguaggio che possiamo discriminare tra due casi d'uso finemente sintonizzati. Dipende davvero da cosa vuoi fare, ma molte persone non si occuperanno di tali sottigliezze.
Holdenweb,

2
A proposito, questo è un utilizzo RARO della "variabile di classe". Molto più comune averlo definito in una classe specifica, qui Foo. Queste sono informazioni utili per alcune situazioni di programmazione avanzata. Ma quasi certamente non quello che la domanda originale voleva come risposta (chiunque abbia bisogno di QUESTA risposta saprà già come fare Foo.bar). +1 perché ho imparato qualcosa da questo.
ToolmakerSteve

3
Sto imparando quando utilizzare variabili e metodi di classe (al contrario di variabili e metodi di istanza). Quando si desidera accedere a una variabile di classe in un metodo di istanza, è necessario utilizzare self.__class__.bar? Ho notato che self.bar funziona anche se bar è una variabile di classe e non una variabile di istanza.
Bill

13

Come per tutti i buoni esempi, hai semplificato ciò che stai effettivamente cercando di fare. Questo è buono, ma vale la pena notare che python ha molta flessibilità quando si tratta di variabili di classe rispetto a istanze. Lo stesso si può dire dei metodi. Per un buon elenco di possibilità, raccomando di leggere la presentazione del nuovo stile di Michael Fötsch , in particolare le sezioni da 2 a 6.

Una cosa che richiede molto lavoro da ricordare quando si inizia è che Python non è Java. Più che un semplice cliché. In Java, viene compilata un'intera classe, semplificando la risoluzione dello spazio dei nomi: qualsiasi variabile dichiarata al di fuori di un metodo (ovunque) è variabile di istanza (o, se statica, classe) e è implicitamente accessibile all'interno dei metodi.

Con Python, la grande regola empirica è che ci sono tre spazi dei nomi che vengono ricercati, in ordine, per le variabili:

  1. La funzione / metodo
  2. Il modulo attuale
  3. builtins

{begin pedagogy}

Ci sono limitate eccezioni a questo. Quello principale che mi viene in mente è che, quando viene caricata una definizione di classe, la definizione di classe è il suo spazio dei nomi implicito. Ma questo dura solo fino a quando il modulo viene caricato, ed è completamente bypassato all'interno di un metodo. Così:

>>> class A(object):
        foo = 'foo'
        bar = foo


>>> A.foo
'foo'
>>> A.bar
'foo'

ma:

>>> class B(object):
        foo = 'foo'
        def get_foo():
            return foo
        bar = get_foo()



Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    class B(object):
  File "<pyshell#11>", line 5, in B
    bar = get_foo()
  File "<pyshell#11>", line 4, in get_foo
    return foo
NameError: global name 'foo' is not defined

{end pedagogy}

Alla fine, la cosa da ricordare è che non ha accesso a nessuna delle variabili che si desidera accedere, ma probabilmente non in modo implicito. Se i tuoi obiettivi sono semplici e chiari, probabilmente sarà sufficiente scegliere Foo.bar o self.bar. Se il tuo esempio sta diventando più complicato, o vuoi fare cose fantasiose come l'ereditarietà (puoi ereditare metodi statici / di classe!) O l'idea di fare riferimento al nome della tua classe all'interno della classe stessa ti sembra sbagliata, dai un'occhiata l'intro che ho collegato.


IIRC, ci sono tecnicamente 3 (+) spazi dei nomi cercati - funzione-locale, modulo / globale e builtin. Scopi nidificati significa che è possibile cercare più ambiti locali, ma questo è uno dei casi eccezionali. (...)
Jeff Shannon

Inoltre, starei attento a dire "modulo principale", poiché è il modulo contenente la funzione che viene cercato, non il modulo principale ... E cercare l'attributo da un riferimento all'istanza è una cosa diversa, ma questa risposta spiega perché è necessario il riferimento istanza / classe.
Jeff Shannon,


-2
class Foo(object):    
    bar = 1

    def bah(object_reference):
        object_reference.var = Foo.bar
        return object_reference.var


f = Foo() 
print 'var=', f.bah()

4
Sebbene questo codice possa risolvere la domanda, inclusa una spiegazione di come e perché questo risolva il problema, contribuirebbe davvero a migliorare la qualità del tuo post e probabilmente darebbe più voti positivi. Ricorda che stai rispondendo alla domanda per i lettori in futuro, non solo per la persona che chiede ora. Si prega di modificare la risposta per aggiungere spiegazioni e dare un'indicazione di ciò si applicano le limitazioni e le assunzioni. Dalla recensione
Doppio segnale acustico
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.