2017-02-23 17 views
0

私はC、C#、Javaでプログラミングしました。今私はしばらくの間Pythonを使用していますが、今は私にとっては非常に混乱している可変スコープの理解にいくつかの問題が発生しました。例:可変スコープの混乱(外側スコープのシャドーイング変数)

def f1(): 
    print(spam) # spam magically come from outer scope. ok... 


def f2(): 
    spam = "bbb" # assignment shadows variable from outer scope (logical result of f1) 
    print(spam) # printing local spam variable 


def f3(): 
    print(spam) # ERROR: unresolved reference 'spam' 
    spam = "ccc" # in f1 function everything was fine but adding assignment AFTER 
        # printing (in opposite to f2 function) causes error in line above 


def f4(): 
    print(spam) # nothing wrong here, assignment line below is commented 
    # spam = "ccc" 

spam = "aaa" 

機能が有効範囲外の変数に到達するのはなぜですか? なぜ、外側のスコープからのシャドーイング変数は、以前はそれを使用していなかった場合にのみOKですか?

+1

ですがあなたは 'f3'で '未解決の参照エラー'を受け取るでしょうか?私はエラー 'UnboundLocalError:ローカル変数 'spam'が割り当て前に参照されていると期待します。これは自己説明的です。 – kazemakase

+0

'f2'は' aaa'から 'bbb'への変数' spam 'を変更しています – mtkilic

+0

@kazemakaseあなたが正しいと思いますが、私が書いたエラーはIDEからのものではなくランタイムからです – user3616181

答えて

1

実行前にPythonコードをバイトコードにコンパイルします。つまり、Pythonは関数がどのように変数を使用するかを分析できます。変数はグローバルまたはローカルのいずれかの関数ですが、変更することはできません。

spamは決して割り当てられていないので、f1にはグローバルです。 spamは割り当てられているため、f2にローカルです。同じことがf3になります。 spamspam='ccc'のためにf3にローカルです。 print(spam)ステートメントを使用すると、割り当て前にローカル変数にアクセスしようとします。

関数内でglobal spamを使用すると、変数名をグローバルとして強制的に宣言できます。

ローカルはローカルのままです。でも、ローカル名前空間に変数を削除した後のPython親スコープ内の名前を検索しません:

spam = 123 

def f(): 
    spam = 42 
    print(spam) # 42 
    del spam 
    print(spam) # UnboundLocalError 

f() 

をあなたがそれを宣言する必要があり、グローバル変数割り当てたい場合は:あなたは

spam = 123 

def f(): 
    global spam 
    spam = 42 
    print(spam) # 42 

f() 
print(spam) # 42 
+0

ああ、私は忘れても多くの人々は、Pythonは、実際にはコンパイル段階を持っているスクリプトから解釈されていると言う。 – user3616181

+0

しかし、なぜ関数が外部変数に到達できるのですか?これの背後にあるアイデアは何ですか?誰かが望ましい行動であると結論づけなければならないからだ。 – user3616181

+0

@ user3616181 Pythonでは変数、関数、およびその他のオブジェクトに違いがないので。関数定義の中で 'print'を呼び出せるようにしたいのですか? 'print'はグローバルオブジェクトで、' spam'もそうです。 'spam'は他の関数の中で呼び出す関数でもあります。単にグローバルルックアップを許可しない理由はありません。私はかつてこの機能を無効にすることを考えましたが、これは[悪いアイデア]であることが判明しました(http://stackoverflow.com/a/31023487/3005167)。 – kazemakase