質問

最近 UnboundLocalError のケースに出くわしましたが、奇妙に思えます:

import pprint

def main():
    if 'pprint' in globals(): print 'pprint is in globals()'
    pprint.pprint('Spam')
    from pprint import pprint
    pprint('Eggs')

if __name__ == '__main__': main()

生成されるもの:

pprint is in globals()
Traceback (most recent call last):
  File "weird.py", line 9, in <module>
    if __name__ == '__main__': main()
  File "weird.py", line 5, in main
    pprint.pprint('Spam')
UnboundLocalError: local variable 'pprint' referenced before assignment

pprint globals に明確にバインドされており、次のステートメントの locals にバインドされます。誰かが pprint globals のバインディングに解決できない理由の説明をここで提供できますか?

編集:適切な回答のおかげで、関連する用語で質問を明確にできます:

コンパイル時に、識別子 pprint がフレームに対してローカルとしてマークされます。実行モデルには、ローカル識別子がバインドされているフレーム内のどこの区別はありませんか? 「このバイトコード命令までグローバルバインディングを参照し、その時点でローカルバインディングにリバウンドされている」と言えますか?または実行モデルはこれを考慮しませんか?

役に立ちましたか?

解決

Pythonのように見える from pprint import pprint 行を見て、 main() before <のローカル名として pprint をマークします/ em>任意のコードを実行します。 Pythonはpprintをローカル変数と見なすので、「割り当て」の前に pprint.pprint()でそれを参照します。 from..import ステートメントを使用すると、そのエラーがスローされます。

それは、私ができる限り理にかなっています。

モラルは、もちろん、これらの import ステートメントを常にスコープの先頭に置くことです。

他のヒント

驚きはどこですか?そのスコープ内で再割り当てしたスコープに対してグローバルな任意変数は、コンパイラによってそのスコープに対してローカルとしてマークされます。

インポートの処理が異なる場合、それは意外な見方です。

ただし、そこで使用されているシンボルに基づいてモジュールに名前を付けない、またはその逆を行う場合があります。

まあ、それは私が少し実験するのに十分面白かったので、 http:/を読みました。 /docs.python.org/reference/executionmodel.html

その後、あちこちでコードをいじくり回しました。これは私が見つけることができるものです:

コード:

import pprint

def two():
    from pprint import pprint
    print globals()['pprint']
    pprint('Eggs')
    print globals()['pprint']

def main():
    if 'pprint' in globals():
        print 'pprint is in globals()'
    global  pprint
    print globals()['pprint']
    pprint.pprint('Spam')
    from pprint import pprint
    print globals()['pprint']
    pprint('Eggs')

def three():
    print globals()['pprint']
    pprint.pprint('Spam')

if __name__ == '__main__':
    two()
    print('\n')
    three()
    print('\n')
    main()

出力:

<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Eggs'
<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>

<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Spam'

pprint is in globals()
<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Spam'
<function pprint at 0xb7d596f4>
'Eggs'

two() pprint import pprint のメソッドでは、 globals の名前 pprint をオーバーライドしません、 global キーワードは two()の範囲では使用されないためです。

メソッド three()では、ローカルスコープに pprint 名の宣言がないため、デフォルトのグローバル名 pprint になります。モジュール

main()では、最初にキーワード global が使用されるので、 pprint へのすべての参照はメソッド main()のスコープは、 global の名前 pprint を参照します。ご覧のとおり、最初はモジュールであり、 from pprint import pprint <を実行するときのメソッドで global namespace でオーバーライドされます

これは質問自体に答えているわけではないかもしれませんが、それでも私が思うに興味深い事実がいくつかあります。

=====================

編集別の興味深いこと。

モジュールがある場合:

mod1

from datetime import    datetime

def foo():
    print "bar"

および別の方法:

mod2

import  datetime
from mod1 import *

if __name__ == '__main__':
    print datetime.datetime.now()

モジュール datetime mod2 にインポートしたため、一見正しいと思われます。

mod2をスクリプトとして実行しようとすると、エラーがスローされます:

Traceback (most recent call last):
  File "mod2.py", line 5, in <module>
    print datetime.datetime.now()
AttributeError: type object 'datetime.datetime' has no attribute 'datetime'

mod2 import *からの2番目のインポート * がネームスペースの名前 datetime をオーバーライドしたため、最初の import datetime はもう有効ではありません。

モラル:したがって、インポートの順序、インポートの性質(x import *から)、およびインポートされたモジュール内のインポートの認識-事項

この質問は数週間前に回答されましたが、回答を少し明確にできると思います。最初にいくつかの事実。

1:Pythonでは、

import foo

とほぼ同じ

foo = __import__("foo", globals(), locals(), [], -1)

2:関数でコードを実行するときに、Pythonが関数でまだ定義されていない変数を検出すると、グローバルスコープを検索します。

3:Pythonには、「ローカル」と呼ばれる関数に使用する最適化があります。 Pythonが関数をトークン化するとき、割り当てられたすべての変数を追跡します。これらの各変数に、単調に増加するローカル整数からの番号を割り当てます。 Pythonは関数を実行するときに、ローカル変数と同じ数のスロットを持つ配列を作成し、「まだ割り当てられていない」ことを意味する特別な値を各スロットに割り当てます。 。まだ割り当てられていないローカルを参照すると、Pythonはその特別な値を認識し、UnboundLocalValue例外をスローします。

これでステージが設定されました。 「pprint from pprintから」割り当ての形式です。そのため、Pythonは&quot; pprint&quot;というローカル変数を作成します。グローバル変数を隠します。次に、「pprint.pprint」を参照すると、関数内で特別な値をヒットすると、Pythonが例外をスローします。関数にそのimportステートメントがなかった場合、Pythonは通常のlook-in-locals-first-then-look-in-globals解決を使用し、グローバルでpprintモジュールを見つけます。

これを明確にするには、「グローバル」を使用できます。キーワード。もちろん、今ではあなたはすでにあなたの問題を乗り越えて働いています。または他のアプローチが必要な場合。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top