2013-08-01 8 views
24

Sto utilizzando la libreria PyQt per acquisire uno screenshot di una pagina Web, quindi la lettura di un file CSV di URL diversi. Sto mantenendo un feed variabile che incrementa ogni volta che un URL viene elaborato e quindi dovrebbe incrementare il numero di URL.Variabile locale di riferimento prima dell'assegnazione in Python?

Ecco il codice:

webpage = QWebPage() 
fo = open("C:/Users/Romi/Desktop/result1.txt", "w") 
feed = 0 
def onLoadFinished(result): 
    #fo.write(column1[feed])#, column2[feed], urls[feed]) 
    #feed = 0 
    if not result: 
     print "Request failed" 
    fo.write(column1[feed]) 
    fo.write(',') 
    fo.write(column2[feed]) 
    fo.write(',') 
    #fo.write(urls[feed]) 
    fo.write(',') 
    fo.write('404,image not created\n') 
    feed = feed + 1 
     sys.exit(1) 
     save_page(webpage, outputs.pop(0)) # pop output name from list and save 
    if urls: 
     url = urls.pop(0) # pop next url to fetch from list 
     webpage.mainFrame().load(QUrl(url)) 
    fo.write(column1[feed])#,column2[feed],urls[feed],'200','image created','/n') 
    fo.write(',') 
    fo.write(column2[feed]) 
    fo.write(',') 
    #fo.write(urls[feed]) 
    fo.write(',') 
    fo.write('200,image created\n') 
    feed = feed + 1 
    else: 
     app.quit() # exit after last url 

webpage.connect(webpage, SIGNAL("loadFinished(bool)"), onLoadFinished) 
webpage.mainFrame().load(QUrl(urls.pop(0))) 
#fo.close() 
sys.exit(app.exec_()) 

Mi dà l'errore:

local variable feed referenced before the assignment at fo.write(column1[feed])#,column2[feed],urls[feed],'200','image created','/n') 

Qualsiasi idea del perché?

+1

Possibile duplicato di [Errore scope variabile Python] (https://stackoverflow.com/questions/370357/python-variable-scope-error) – Nae

risposta

49

Quando pitone analizza il corpo di una definizione di funzione e rileva un'assegnazione come

feed = ... 

Python interpreta feed come variabile locale di default. Se non si desidera che sia una variabile locale, è necessario inserire

global feed 

nella definizione della funzione. L'istruzione globale non deve essere all'inizio della definizione della funzione, ma è quella in cui viene solitamente posizionata. Ovunque sia posizionato, la dichiarazione globale rende feed una variabile globale ovunque nella funzione.

Senza la dichiarazione globale, dal momento feed è preso per essere una variabile locale, quando Python esegue

feed = feed + 1, 

Python valuta il lato destro prima e cerca di guardare in alto il valore degli alimenti. La prima volta che trova il documento feed non è definito. Quindi l'errore.

Il metodo più breve per correggere il codice è aggiungere global feed all'inizio di onLoadFinished. Il modo più bello è quello di utilizzare una classe:

class Page(object): 
    def __init__(self): 
     self.feed = 0 
    def onLoadFinished(self, result): 
     ... 
     self.feed += 1 

Il problema di avere funzioni che mutano le variabili globali è che essa rende più difficile Grok codice. Le funzioni non sono più unità isolate. La loro interazione si estende a tutto ciò che influisce o è influenzato dalla variabile globale. In questo modo è più difficile capire i programmi più grandi.

Evitando le variabili globali mutanti, a lungo termine il codice sarà più facile da comprendere, testare e mantenere.

+0

come mai non è necessario eseguire questa operazione per Dict? – HoKy22

+0

@ HoKy22: stai chiedendo perché 'dct [chiave] = val' non genera un errore di" variabile locale referenziata prima dell'assegnazione "? Il motivo è che questo non è un * nome nullo * incarico. Invece, fa in modo che Python faccia in modo che la funzione chiami 'dct .__ setitem __ (key, val)'. – unutbu

+0

sì, questo è quello che sto chiedendo. per esempio, in un file, tutto in alto, hai appena messo dict = {} e poi in un metodo, hai impostato dict ['apple'] = 5 e in un altro metodo puoi stampare (dict ['apple ']). questo perché dict chiama __setitem __ ('apple', 5) quando si dice ['apple'] = 5? – HoKy22

20

mettere una dichiarazione globale in cima alla vostra funzione e si dovrebbe essere buono:

def onLoadFinished(result): 
    global feed 
    ... 

Per dimostrare quello che voglio dire, guardate questo piccolo test:

x = 0 
def t(): 
    x += 1 
t() 

questa esplode con lo stesso esatto errore dove:

x = 0 
def t(): 
    global x 
    x += 1 
t() 

no.

La ragione di ciò è che, all'interno di t, Python pensa che x sia una variabile locale. Inoltre, a meno che tu non dica esplicitamente che x è globale, cercherà di utilizzare una variabile locale denominata x in x += 1. Tuttavia, poiché non è stato definito x nell'ambito locale di t, viene generato un errore.

5

Poiché l'interprete Python legge la definizione di una funzione (o, penso, anche un blocco di codice indentato), tutte le variabili che sono assegnate a all'interno della funzione vengono aggiunte ai locals per quella funzione. Se un locale non ha una definizione prima di un compito, l'interprete Python non sa cosa fare, quindi genera questo errore.

La soluzione è quella di aggiungere

global feed 

alla funzione (di solito vicino alla parte superiore) per indicare all'interprete che la variabile di alimentazione non è locale a questa funzione.

Problemi correlati