web-dev-qa-db-ja.com

Pythonでの割り当ての前に参照されるローカル変数?

PyQtライブラリを使用してWebページのスクリーンショットを撮り、さまざまなURLのCSVファイルを読んでいます。 URLが処理されるたびに増加する可変フィードを保持しているため、URLの数に応じて増加します。

コードは次のとおりです。

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

それは私にエラーを与えます:

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

理由は何ですか?

36
Scooby

Pythonが関数定義の本体を解析し、次のような割り当てに遭遇したとき

feed = ...

Pythonはfeedをデフォルトでローカル変数として解釈します。ローカル変数にしたくない場合は、

global feed

関数定義で。グローバルステートメントは、関数定義の先頭にある必要はありませんが、通常はそこに配置されます。どこに配置されても、グローバル宣言はfeedをグローバル変数everywhereにします。

グローバルステートメントがない場合、Pythonが実行されると、feedがローカル変数と見なされるため

feed = feed + 1,

Pythonは最初に右側を評価し、フィードの値を検索しようとします。最初にfeedが未定義であることがわかりました。したがって、エラー。

コードを修正する最短の方法は、global feedonLoadFinishedの先頭に追加することです。より良い方法は、クラスを使用することです:

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

グローバル変数を変更する関数を持つことの問題は、コードを理解するのが難しくなることです。関数はもはや孤立したユニットではありません。それらの相互作用は、グローバル変数に影響を与えるか、またはグローバル変数の影響を受けるすべてに拡張されます。したがって、大きなプログラムを理解するのが難しくなります。

グローバルの変更を回避することにより、長期的にはコードの理解、テスト、保守が容易になります。

60
unutbu

関数の先頭にグローバルステートメントを配置すると、うまくいくはずです。

def onLoadFinished(result):
    global feed
    ...

私が意味することを実証するために、この小さなテストを見てください。

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

これは、次の場合とまったく同じエラーで爆発します。

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

ではない。

その理由は、tの内部で、Pythonはxがローカル変数であると考えるからです。さらに、xがグローバルであることを明示的に伝えない限り、x += 1xという名前のローカル変数を使用しようとします。ただし、xのローカルスコープにtが定義されていないため、エラーがスローされます。

28
iCodez

Pythonインタープリターが関数の定義(または、インデントされたコードのブロックですら)を読み取ると、に割り当てられているすべての変数が関数内で、その関数のローカルに追加されます。ローカルに割り当ての前に定義がない場合、Pythonインタープリターは何をすべきかを知らないため、このエラーがスローされます。

ここでの解決策は、追加することです

global feed

フィード変数がこの関数に対してローカルではないことをインタープリターに示すために、関数(通常は上部近く)に追加します。

8
lmjohns3