2012-02-29 9 views
9

Leggendo la documentation mi sono imbattuto nel seguente paragrafo:L'ambito dei nomi definiti nel blocco di classe non si estende ai blocchi dei metodi. Perché?

Un ambito definisce la visibilità di un nome all'interno di un blocco. Se una variabile locale è definita in un blocco, il suo ambito include quel blocco. Se la definizione si verifica in un blocco funzione, l'ambito si estende a tutti i blocchi contenuti all'interno di quello definitivo, a meno che un blocco contenuto non presenti un binding diverso per il nome. L'ambito dei nomi definiti in un blocco di classe è limitato al blocco di classe; non si estende ai blocchi di codice dei metodi - questo include le espressioni e le espressioni del generatore poiché sono implementati utilizzando un ambito di funzione.

ho deciso di provare ad accedere a variabile di classe da un metodo di me stesso:

>>> class A(): 
    i = 1 
    def f(self): 
     print(i)    

>>> a = A() 

>>> a.i 
1 

>>> a.f() 
Traceback (most recent call last): 
    File "<pyshell#7>", line 1, in <module> 
    a.f() 
    File "<pyshell#4>", line 4, in f 
    print(i) 
NameError: global name 'i' is not defined 

So che la variabile i sono accessibili tramite esplicitamente indicando il nome della classe A.i:

>>> a = A() 
>>> class A(): 
    i = 1 
    def f(self): 
     print(A.i)   
>>> a = A() 
>>> a.f() 
1 

La domanda è: perché gli sviluppatori del linguaggio hanno reso le variabili di classe non visibili dai metodi? Qual è la logica dietro di esso?

risposta

8

Questo sembra essere correlato all'uso di un parametro esplicito self e al requisito che tutte le chiamate di metodo e gli accessi di istanza accedano esplicitamente a self. Sarebbe quantomeno strano se il caso raro di accedere a una funzione dell'oscilloscopio di classe come una funzione normale sarebbe molto più facile del caso comune di accedervi come metodo tramite self. Le variabili di classe sono normalmente accessibili anche tramite l'istanza in Python.

In C++, al contrario, l'ambito della classe è visibile in tutti i metodi, ma la chiamata di un metodo passa implicitamente allo this. Questa sembra essere l'altra scelta sana.

+0

Sì. Io vedo. Quindi cercano di imporre l'uso di 'self' per accedere alle variabili di classe. È possibile che consentire l'accesso alle variabili di classe dai metodi avrebbe altre ripercussioni? – ovgolovin

+0

@ovgolovin: Bene, aspettiamo quali spiegazioni escano altre persone. Forse qualcuno trova un buon collegamento web. –

+0

In realtà, questo è un po 'di congetture congetturate "- controlla la risposta di Ben per capire cosa sta succedendo in Python – jsbueno

9

Un blocco di classe è zucchero sintattico per la costruzione di un dizionario, che viene quindi passato al metaclasse (solitamente type) per costruire l'oggetto classe.

class A: 
    i = 1 
    def f(self): 
     print(i) 

è più o meno equivalente a:

def f(self): 
    print(i) 
attributes = {'f': f, 'i': 1) 
A = type('A', (object,) attributes) 

Visto in questo modo, non v'è alcun margine esterno il nome i a venire da. Tuttavia, ovviamente, esiste un ambito temporaneo per l'esecuzione delle istruzioni nel blocco di classe. Sarebbe possibile per quel blocco di classe a desugar a qualcosa di più simile:

def attributes(): 
    i = 1 
    def f(self): 
     print(i) 
    return locals() 
A = type('A', (object,), attributes()) 

In questo caso il riferimento esterno per i avrebbe funzionato. Tuttavia, questo andrebbe "contro la grana" della filosofia del sistema a oggetti di Python.

Python ha oggetti, che contengono attributi. Non c'è davvero alcun concetto di "variabili" diverse dalle variabili locali nelle funzioni (che possono essere annidate per creare una catena di portata). Un nome nudo viene considerato come una variabile locale, quindi in ambiti esterni (che provengono da funzioni).Attributi vengono ricercati, utilizzando la sintassi nome puntato, su altri oggetti, e sempre specificare quale oggetto di guardarsi.

C'è un protocollo per risolvere i riferimenti degli attributi, che dice che quando attribute non si trova sulla obj , obj.attribute può essere risolto cercando nella classe obj (e le sue classi base, usando l'ordine di risoluzione dei metodi). Questo è in realtà come vengono trovati i metodi; quando nell'esempio è stato eseguito a.f(), l'oggetto a non contiene alcun attributo f, quindi viene cercata la classe a (che è A) e viene trovata la definizione del metodo.

Avere gli attributi di classe automaticamente disponibili in un ambito esterno per tutti i metodi sarebbe strano, perché nessun altro attributo funziona in questo modo. Sarebbe inoltre i seguenti inconvenienti:

  1. funzioni definite all'esterno della classe e ad essa assegnati dopo sarebbe necessario utilizzare sintassi diversa per l'attributo di classe di funzioni definite come parte di una classe.
  2. Perché è più breve, avrebbe incoraggiato riferimento alla classe di attributi tra cui staticmethods e classmethods nomi come nudi: thing invece di usare Class.thing o self.thing. Questo li fa apparire come moduli globali quando non lo sono (le definizioni dei metodi sono in genere abbastanza brevi da poter vedere facilmente che non sono definite localmente).
  3. Si noti che la ricerca degli attributi su self consente loro di giocare meglio con le sottoclassi, in quanto consente alle sottoclassi di sovrascrivere l'attributo. Questo probabilmente non è un grosso problema per le "costanti di classe", ma è molto importante per i metodi statici e i metodi di classe.

Queste sono le ragioni principali che vedo, ma alla fine è solo una scelta dei designer di Python. È strano che non si abbia questa capacità implicita di fare riferimento a variabili di classe, ma trovo che l'accesso alla variabile di classe e di istanza implicita in linguaggi come C++ e Java sia strano. Persone diverse hanno opinioni diverse

+0

Oh, StackOverflow, dove le risposte corrette che richiedono più tempo per rispondere sono meno votate che errate, le risposte ambigue sono scritte in un silenzio. Spero che l'OP possa percepire che questa è molto più una risposta di quello votato più alto – jsbueno

+0

@jsbueno: Sarebbe più costruttivo indicare cosa esattamente è errato nella mia risposta (commenterò di più su questo risposta a breve.) –

+0

Sono d'accordo con i punti 2 e 3. e le osservazioni dell'interazione con l'ereditarietà - sono certamente alcune delle ragioni di questa decisione progettuale. –

Problemi correlati