2012-01-31 19 views
10

prendere il codice seguente:"variabile locale referenziata prima dell'assegnazione" - solo funzioni?

import something 

def Foo(): 
    something = something.SomeClass() 
    return something 

... questo è apparentemente codice non valido:

UnboundLocalError: local variable 'something' referenced before assignment 

... come variabile locale viene creata something, ma non assegnato, prima che il RHS del = viene valutata . (Vedi, ad esempio, this related answer's comment.) Mi sembra un po 'strano, ma certo, ci vado. Ora, perché è il seguente codice valido?

class Foo(object): 
    something = something.SomeClass() 

mia comprensione è che l'interno di una definizione class era essenzialmente un ambito:

interno della classe viene quindi eseguito in una nuova cornice di esecuzione (vedere la sezione denominazione e vincolante), utilizzando una nuova creato spazio dei nomi locale e lo spazio dei nomi globale originale.

Quindi, perché il codice funziona in modo diverso rispetto a quello di una funzione?

+0

"qualcosa" sembra avere più di un significato? – Johnsyweb

+0

@Johnsyweb: Sì, tipo di. Ma in entrambi i casi, ha lo stesso tipo di significato più di uno. (O, almeno, tutti i documenti che ho letto sembrano dirlo.) – Thanatos

risposta

4

consideri il seguente esempio che può aiutare a chiarire questo:

import datetime 

class Foo(object): 
    datetime = datetime.datetime 

>>> datetime 
<module 'datetime' from '/usr/lib/python2.6/lib-dynload/datetime.so'> 
>>> Foo.datetime 
<type 'datetime.datetime'> 

nota che la linea datetime = datetime.datetime è in realtà assegnando al nome Foo.datetime, che non è ambiguo con il globale datetime (come sarebbe se il lo stesso codice era nella funzione).

In sintesi, poiché le definizioni di classe creano un nuovo spazio dei nomi e un nuovo ambito, è possibile accedere direttamente a un nome in un ambito che racchiude e assegnare allo stesso nome nell'ambito locale.

+0

"Si noti che la riga' datetime = datetime.datetime' sta attualmente assegnando il nome 'Foo.datetime', che non è ambiguo con il 'datetime' globale? - No: assegna al nome' datetime': Se aggiungi due istruzioni 'print datetime', una prima di' datetime = ', e una dopo, come è il 'datetime' in quella dichiarazione * non * ambiguo, in un modo che è diverso dalle stesse affermazioni in una funzione? – Thanatos

+0

@Thanatos - Sì, posso vedere come ciò non è chiaro. Quello che stavo cercando di dire è che lo spazio dei nomi creato dalla classe consente un modo non ambiguo di accedere sia all'attributo globale che a quello di classe da altri ambiti, ma hai ragione c'è ancora ambiguità all'interno dell'ambito locale della classe. –

+0

Ma il punto cruciale della domanda è come è questo qualsiasi altro di quello che succede in una funzione? Dichiari, "poiché le definizioni di classe creano un nuovo spazio dei nomi e un nuovo ambito" - non funzioni creano un nuovo spazio dei nomi e un nuovo ambito? - "ti è permesso accedere direttamente a un nome in un ambito che racchiude "- Posso fare questo in una funzione - "e assegnare allo stesso nome nello scope locale" - Posso farlo solo in una definizione di classe ... perché? – Thanatos

6

Dal python class documentation:

Le definizioni di classe posto ancora un altro spazio dei nomi in ambito locale.

Una stranezza speciale di Python è che, se nessuna istruzione globale è in vigore, le assegnazioni ai nomi vanno sempre nello scopo più interno. Le assegnazioni non copiano i dati: si limitano a associare i nomi agli oggetti. Lo stesso vale per le eliminazioni: l'istruzione del x rimuove il legame di x dallo spazio dei nomi a cui fa riferimento l'ambito locale. Di fatto, tutte le operazioni che introducono nuovi nomi utilizzano l'ambito locale: in particolare, le istruzioni di importazione e le definizioni di funzioni associano il nome del modulo o della funzione all'ambito locale. (L'istruzione global può essere utilizzato per indicare che particolari variabili vivono nello scope globale.)

Quindi all'interno di una funzione (o un campo di applicazione) l'assegnazione crea una variabile non legato locale che si accede prima di essere legato, mentre in una definizione di classe crea una voce nel dizionario "namespace" di quella classe sull'assegnazione, consentendo la risoluzione di something nello spazio dei nomi esterno (lo spazio dei nomi del modulo).

Problemi correlati