web-dev-qa-db-fra.com

Variable locale référencée avant l’affectation en Python?

J'utilise la bibliothèque PyQt pour prendre une capture d'écran d'une page Web, puis pour lire un fichier CSV contenant différentes URL. Je garde un flux variable qui s'incrémente chaque fois qu'une adresse URL est traitée et doit donc incrémenter le nombre d'URL.

Voici le code:

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_())

Cela me donne l'erreur:

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

Une idée pourquoi?

36
Scooby

When Python analyse le corps d'une définition de fonction et rencontre une affectation telle que

feed = ...

Python interprète feed comme une variable locale par défaut. Si vous ne souhaitez pas que ce soit une variable locale, vous devez mettre

global feed

dans la définition de la fonction. L'instruction globale ne doit pas obligatoirement figurer au début de la définition de la fonction, mais c'est là qu'elle est habituellement placée. Où qu’elle soit placée, la déclaration globale fait de feed une variable globale partout dans la fonction.

Sans la déclaration globale, puisque feed est considéré comme une variable locale, lorsque Python est exécuté

feed = feed + 1,

Python évalue le côté droit en premier et tente de rechercher la valeur du fil. La première fois qu'il trouve feed n'est pas défini. D'où l'erreur.

Le moyen le plus rapide de corriger le code est d’ajouter global feed au début de onLoadFinished. La meilleure façon est d'utiliser une classe:

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

Le problème des fonctions qui mutent les variables globales est qu’il est plus difficile de coder votre code. Les fonctions ne sont plus des unités isolées. Leur interaction s'étend à tout ce qui affecte ou est affecté par la variable globale. Cela rend donc plus difficile la compréhension des grands programmes.

En évitant les globals en mutation, votre code sera plus facile à comprendre, à tester et à maintenir à long terme.

60
unutbu

Mettez une déclaration globale au sommet de votre fonction et vous devriez être bon:

def onLoadFinished(result):
    global feed
    ...

Pour démontrer ce que je veux dire, regardez ce petit test:

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

cela explose avec votre même erreur exacte que:

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

ne fait pas.

La raison en est que, dans t, Python pense que x est une variable locale. De plus, à moins que vous ne lui indiquiez explicitement que x est global, il essaiera d’utiliser une variable locale nommée x dans x += 1. Mais, comme il n'y a pas de x défini dans la portée locale de t, il génère une erreur.

28
iCodez

Comme l'interprète Python lit la définition d'une fonction (ou, je pense, même un bloc de code en retrait)), toutes les variables qui sont assignées à à l'intérieur de la fonction sont ajouté aux sections locales de cette fonction Si un local n’a pas de définition avant une affectation, l’interprète Python ne sait pas quoi faire; il renvoie donc cette erreur.

La solution ici est d'ajouter

global feed

à votre fonction (généralement près du haut) pour indiquer à l'interprète que la variable de fil n'est pas locale à cette fonction.

8
lmjohns3