2012-02-13 6 views
93

Cosa sto facendo male qui?UnboundLocalError in Python

counter = 0 

def increment(): 
    counter += 1 

increment() 

Il codice sopra riportato genera UnboundLocalError.

+11

@ZeroPiraeus: perché hai piantare un domanda con 40k + vista, che è il primo risultato per "UnboundLocalError" in Google, come duplicato di una nuova domanda quasi identica a cui hai risposto invece di pubblicare semplicemente la tua risposta * qui *? – vaultah

+1

Questa domanda e quella attualmente contrassegnata come duplicata sono in discussione nella [Chatroom Python] (http://chat.stackoverflow.com/transcript/message/34899645#34899645). –

+3

Molte delle risposte qui dicono di usare 'global', e anche se ciò funziona, l'uso di globali modificabili è generalmente _non_ consigliato quando esistono altre opzioni. –

risposta

97

Python non ha dichiarazioni di variabili, quindi deve capire il scope di variabili stesso. Lo fa con una semplice regola: se c'è un assegnamento a una variabile all'interno di una funzione, quella variabile è considerata locale. [1] Così, la linea

counter += 1 

rende implicitamente counter locale per increment(). Cercando di eseguire questa linea, tenterà comunque di leggere il valore della variabile locale counter prima che venga assegnato, risultando in un UnboundLocalError. [2]

Se counter è una variabile globale, la parola chiave global aiuterà. Se increment() è una funzione locale e una variabile locale, è possibile utilizzare nonlocal in Python 3.x.

+2

python 3 docs ha una [pagina faq su why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value] (https://docs.python.org/3/faq/programming .html # why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value) tramite [unboundlocalerror-local-variable-l-referenced-before-assignment-python] (http: // stackoverflow.com/questions/21456739/unboundlocalerror-local-variable-l-referenced-before-assignment-python) – here

+0

Una nota che mi ha catturato, ho avuto una variabile dichiarata nella parte superiore del file che posso leggere all'interno di una funzione senza problemi, comunque per scrivere su una variabile che ho dichiarato all'inizio del file, ho dovuto usare global. – mouckatron

3

Per modificare una variabile globale all'interno di una funzione, è necessario utilizzare la parola chiave globale.

Quando si tenta di fare questo senza la linea

global counter 

all'interno della definizione di incremento, un contatore variabile locale di nome è stato creato in modo da impedirti di pasticciare la variabile contatore che l'intero programma può dipende da.

Si noti che è necessario utilizzare solo globale quando si modifica la variabile; è possibile leggere il contatore dall'interno dell'incremento senza la necessità dell'istruzione globale.

51

È necessario utilizzare il global statement in modo che si sta modificando il contatore variabile globale, invece di una variabile locale:

counter = 0 

def increment(): 
    global counter 
    counter += 1 

increment() 

Se l'ambito di inclusione che counter è definito in non è la portata globale, su Python 3.x è possibile utilizzare nonlocal statement. Nella stessa situazione su Python 2.x si avrebbe alcun modo di riassegnare al nome non locale counter, in modo che avrebbe bisogno di fare counter mutevole e modificarlo:

counter = [0] 

def increment(): 
    counter[0] += 1 

increment() 
print counter[0] # prints '1' 
+0

Cool .. Ha funzionato +1 –

+0

Funziona grazie. –

2

provare questo

counter = 0 

def increment(): 
    global counter 
    counter += 1 

increment() 
0
+0

Sebbene questo collegamento possa rispondere alla domanda, è meglio includere qui le parti essenziali della risposta e fornire il link per riferimento. Le risposte di solo collegamento possono diventare non valide se la pagina collegata cambia. - [Dalla recensione] (/ recensione/post di bassa qualità/19036082) – munk

+0

@munk Cool, ti rendi conto che questo è un link ad un'altra risposta su SO? – Marcin

3

Python ha uno scope lessicale di default, il che significa che sebbene un ambito chiuso possa accedere a valori nel suo ambito di chiusura, non può modificarli (a meno che non siano dichiarati globali con la parola chiave global).

Una chiusura lega valori nella racchiude ambiente ai nomi nel ambiente locale . L'ambiente locale può quindi utilizzare il valore associato e persino riassegnare quel nome a qualcos'altro, ma non può modificare l'associazione nell'ambiente di chiusura.

Nel tuo caso si sta tentando di trattare counter come una variabile locale piuttosto che un valore associato. Si noti che questo codice, che lega il valore di x assegnato nell'ambiente racchiude, funziona bene:

>>> x = 1 

>>> def f(): 
>>> return x 

>>> f() 
1 
11

Per rispondere alla domanda in oggetto, * sì, ci sono chiusure in Python, ad eccezione si applicano solo all'interno una funzione, e anche (in Python 2.x) sono di sola lettura; non è possibile associare nuovamente il nome a un oggetto diverso (sebbene se l'oggetto è modificabile, è possibile modificarne il contenuto). In Python 3.x, è possibile utilizzare la parola chiave nonlocal per modificare una variabile di chiusura.

def incrementer(): 
    counter = 0 
    def increment(): 
     nonlocal counter 
     counter += 1 
     return counter 
    return increment 

increment = incrementer() 

increment() # 1 
increment() # 2 

* Il titolo della domanda originale ha chiesto informazioni sulle chiusure in Python.

6

Il motivo per cui il codice genera uno UnboundLocalError è già spiegato in altre risposte.

Ma mi sembra che tu stia cercando di costruire qualcosa che funzioni come itertools.count().

Allora perché non provare, e vedere se si adatta al vostro caso:

>>> from itertools import count 
>>> counter = count(0) 
>>> counter 
count(0) 
>>> next(counter) 
0 
>>> counter 
count(1) 
>>> next(counter) 
1 
>>> counter 
count(2) 
Problemi correlati