11
def do_something():
    print 'doing something...'

def maybe_do_it(hesitant=False):
    if hesitant:
        do_something = lambda: 'did nothing'
    result = do_something()
    print result

maybe_do_it()

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

  File "scope_test.py", line 10, in <module>
    maybe_do_it()
  File "scope_test.py", line 7, in maybe_do_it
    result = do_something()
UnboundLocalError: local variable 'do_something' referenced before assignment

しかし、このコードは期待どおりに「何かをしました...」と出力します。

def do_something():
    print 'doing something...'

def maybe_do_it(hesitant=False):
    result = do_something()
    print result

maybe_do_it()

if ステートメント内の条件が実行されなかったにもかかわらず、関数はどのようにオーバーライドされたのでしょうか? これは Python 2.7 で発生します -- Python 3 でも同じですか?

4

4 に答える 4

8

if ステートメント内の条件が実行されなかったにもかかわらず、関数はどのようにオーバーライドされたのでしょうか?

変数がローカルかグローバルかは、コンパイル時に決定されます。関数内のどこかに変数への割り当てがある場合、割り当てが実行されたかどうかに関係なく、それはローカル変数です。

これは Python 2.7 で発生します -- Python 3 でも同じですか?

はい。

ちなみに、Python 2 では、以下を使用してこの動作をオーバーライドできますexec(推奨されません)。

def do_something():
    print 'doing something...'

def maybe_do_it(hesitant=False):
    if hesitant:
        exec "do_something = lambda: 'did nothing'"
    result = do_something()
    print result

maybe_do_it(False)    # doing something...
maybe_do_it(True)    # did nothing

関数内のexecは、大まかに言えば、変数をグローバルにルックアップするかローカルにルックアップするかの決定を実行時まで延期します。

于 2013-09-05T23:06:16.687 に答える
6

Python Execution Modelのドキュメントに記載されているとおり:

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

これは言語のルールです。それがまさにその通りです。:D

于 2013-09-05T23:09:09.033 に答える