2
prev, prev_re = '', (None) # these are globals

def find(h, p='', re=None):
    print h, p, re
    #global prev, prev_re
    if p == '' and prev == h: return prev_re
    prev, prev_re = h, re
    return re
print find ("abc")

このエラーが発生します:

    if p == '' and prev == h: return prev_re
UnboundLocalError: local variable 'prev' referenced before assignment
$ 

しかし、前の最後の行にコメントするとfind

prev, prev_re = '', (None)

def find(h, p='', re=None):
    print h, p, re
    #global prev, prev_re
    if p == '' and prev == h: return prev_re
    #prev, prev_re = h, re
    return re
print find ("abc")

コードは、エラーなしで、期待どおりに正しく実行されます。

私の質問は、最初のケースでグローバル変数が見つからない prev理由と、2番目のケースでif-conditionでグローバル変数が見つからない理由です。

編集:インタプリタが変数を見つけられない理由を理解するために、環境の構造の詳細を理解するのを手伝ってください。

4

4 に答える 4

7

問題と解決策

MAK が述べたように、 prev(値を確認した後) に値を割り当てるため、ローカルとして扱われます。解決策は、これら 2 つの変数を明示的にグローバルとして宣言することです。

prev, prev_re = '', (None) # these are globals

def find(h, p='', re=None):
    global prev, prev_re
    print h, p, re
    #global prev, prev_re  # basically what you have done before commenting this
    if p == '' and prev == h: return prev_re
    prev, prev_re = h, re
    return re
print find ("abc")

ご質問への回答

最初のケースでグローバル変数が見つからない理由

それを見つけますが、globalステートメントが先行していない代入を見つけます。したがって、変数はlocalとして扱われます。の行のコメントを外すglobalと修正されます。または、ローカル割り当てに別の変数を使用します。値を関数の属性として保存することもできます (関数もオブジェクトです!)。

2 番目のケースでは、if 条件でグローバル変数が検出されるのはなぜですか

それはグローバルとして扱われます(それを読み取るだけで関数内で定義しないため、ローカル変数によって隠されません)。

もっと読む

この動作が言及されている場合、ドキュメント内の場所を尋ねました。エラーの意味と、この特定のケースが発生する理由が明示的に述べられている場所は見つかりませんでしたが、十分な実行モデルの非常に良い説明があります。

コード ブロック内の任意の場所で名前バインディング操作が発生した場合、ブロック内の名前のすべての使用は、現在のブロックへの参照として扱われます。これは、名前がバインドされる前にブロック内で使用されると、エラーを引き起こす可能性があります。 このルールは微妙です。Python には宣言がなく、コード ブロック内の任意の場所で名前バインディング操作を実行できます。コード ブロックのローカル変数は、ブロックのテキスト全体をスキャンして名前バインディング操作を行うことによって決定できます。

グローバル ステートメントがブロック内で発生する場合、ステートメントで指定された名前のすべての使用は、最上位の名前空間でのその名前のバインディングを参照します。名前は、グローバル名前空間 (つまり、コード ブロックを含むモジュールの名前空間) と組み込み名前空間 (モジュールの名前空間) を検索することによって、最上位の名前空間で解決されます__builtin__。グローバル名前空間が最初に検索されます。そこに名前が見つからない場合は、ビルトイン名前空間が検索されます。このglobalステートメントは、名前のすべての使用の前に置く必要があります

だから基本的に:

  • 割り当てが特定の関数内で発生する場合、変数はlocalとして扱われます...
  • 変数の使用がglobalステートメントの前にある場合、変数はlocalとして扱われます。
  • 割り当てがない場合、変数は最初にローカル名前空間で検索され、次にグローバル名前空間で検索され、次に__builtin__モジュールで検索されます。

nonlocalまた、Python 3 には、変数が外側のスコープ (現在のものではなく、必ずしもグローバルなものではない) からのものであることをインタープリターに伝えるステートメントがあることに注意してください。

于 2012-12-28T02:47:15.260 に答える
4

prevグローバルとして宣言していません。変数に対して読み取りアクションのみを実行した場合、python は変数をグローバルとして処理しようとします。ただし、割り当てを行うため、python はこれを検出しprevてローカル変数を作成します。

詳細については、 http://docs.python.org/2/reference/simple_stmts.html#assignment-statementsを参照してください。具体的には、次のように記載されている部分です。

単一のターゲットへのオブジェクトの割り当ては、次のように再帰的に定義されます。

ターゲットが識別子 (名前) の場合:

  • 名前が現在のコード ブロックのグローバル ステートメントに出現しない場合: 名前は、現在のローカル名前空間のオブジェクトにバインドされます。
  • それ以外の場合: 名前は現在のグローバル名前空間のオブジェクトにバインドされます。

変数名でグローバルを参照する場合は、globalステートメントでそれをグローバルとして宣言する必要があります。

于 2012-12-28T02:49:33.573 に答える
3

このglobalステートメントは、関数のスコープでグローバル変数を使用できるようにします。グローバルなものを宣言しない場合、Python は、グローバルを参照しているのか、新しいローカルを作成しているのかを知る方法がありません。

発生しているエラーは、Python が変数を設定する前に変数を使用していることを認識したことを意味します。グローバル変数がまったく定義されていない場合でも、同じエラーが発生します。

于 2012-12-28T02:50:51.647 に答える
2

IINM では、Python インタープリターは変数が関数の後半に割り当てられていることを検出し、それをローカルとして扱います。

回避策は、クラスを使用し、クラスのインスタンス変数として prev と prev_re を持つことです。

于 2012-12-28T02:41:02.973 に答える