2010-12-11 16 views
1

なぜ地球上でPythonは関数内でグローバル宣言リストを変更できないのですか?グローバルを変更してもエラーが発生しないのはなぜですか?

RE-UPDATED私はそのライン前に、同じ名前の変数にアクションをassignementを置く場合

numbers = [] 
num = 4 

def add(n, thisnum=None): 
    # changing global list without global declaration! 
    numbers.append(n) 
    if thisnum: 
     num = thisnum 
     print 'num assigned', thisnum 
    ##numbers = ('one', 'two', 'three') 
    ## adding this line makes error: 
"""Traceback (most recent call last): 
    File "J:\test\glob_vals.py", line 13, in <module> 
    add(i) 
    File "J:\test\glob_vals.py", line 6, in add 
    numbers.append(n) 
UnboundLocalError: local variable 'numbers' referenced before assignment 
""" 

for i in (1,2,3,564,234,23): 
    add(i) 

print numbers 
add(10, thisnum= 19) 
# no error 
print num 
# let the fun begin 
num = [4] 
add(10, num) 
print num 

# prints: 
"""[1, 2, 3, 56, 234, 23] 
num assigned 19 
4 
num assigned [4] 
[4] 

""" 

はない追加された行(バイトコードコンパイラスポット、それを、私は推測)、エラーになります。

+0

スコープ規則について混乱しているようです。これについていくつかの質問がありますが、SOの向こう側に広がっている質の高い回答があり、docs.python.orgでもこれをカバーしています。 – delnan

+0

私はまだこれが些細なものではないと思います。私は多くのことを学び、教師であり、1984年からコンピュータサイエンスを学んだドキュメンテーションからはっきりとは思えません。 –

+0

私は1つと思っています - ほとんどの言語ではスコープルールよりも複雑です厄介な例外を除いて、一握りのルール。 – delnan

答えて

5

グローバル変数に割り当てておらず、その内容を変更するメソッドを呼び出しています。これは許可されています。あなたはglobalキーワードを指定せずに行うことができない何

はこれです:

def add(n): 
    #global numbers 
    numbers = numbers + [n] 

結果:

 
Traceback (most recent call last): 
    File "C:\Users\Mark\Desktop\stackoverflow\python\test.py", line 8, in 
    add(i) 
    File "C:\Users\Mark\Desktop\stackoverflow\python\test.py", line 5, in add 
    numbers = numbers + [n] 
UnboundLocalError: local variable 'numbers' referenced before assignment 

違いは、ここで私は、既存のリストを変異わけではないということです - 私がしようとしています新しいリストを作成して、グローバルスコープに再割り当てします。しかし、これはglobalキーワードなしでは実行できません。あなたの更新について


:それは関数のスコープに新しいローカル名numを作成するため

次の行はOKです。これは、グローバルスコープでの変数の値には影響しません。

num = thisnum 
0

あなただけリストにを追加しているので。

アクセスと割り当ては異なる概念です。リストを追加するときには、値を変更するメソッドを呼び出すだけです。あなたが+=をやったとすれば、それは割り当てられるでしょう。

あなたがこれを行うにした場合:

>>> numbers = [] 
>>> def add(n): 
     numbers += n 

>>> n = [1, 2] 
>>> add(n) 

これは割り当てがあるので、それは失敗します。この問題を解決するには

add()機能では、追加:

>>> def add(n): 
     global numbers 
     numbers += n 
1

global xのみ affests x = ...を(すなわち、それは、この代わりにx独立した地元の作成x世界を再割り当てます)。 Python(このは静的対動的の問題ではないため、btwは問題ありません)はこれらのメソッドが変更されていることを知ることはできません(および気にしません)self何らかの形で - グローバル変数が指すオブジェクトに対するメソッド呼び出しを防ぐ必要があります...もちろん無意味です。

は、更新について:あなたがnum = thisnumを行うと 、あなたはnumbers.append(n)とは完全に異なる何かをしている - あなたは(あなたがglobal numを宣言していなかったので)ローカル変数を作成し、それにいくつかの値を代入しています。これは決してグローバルnumに触れません。

+0

再更新を参照してください。今すぐ更新されます。 –

+0

@トニー:私の最初の文章を見てください - Pythonは 'x'が関数内のどこかに割り当てられていると仮定し、エラーメッセージが示すようにローカルの' numbers'(*は*関数内で 'global 'と宣言されていない)は、その時点で値が割り当てられていません。 – delnan

+0

私は理解していますが、それは後の行のために前にOKだった行を失敗させてしまう "後ろに"効果があります。バイトコンパイルステップの存在を強調します。直接引数と同じ値を書くのではなく、変数としてリストを渡すことで、呼び出し元に副作用が返されます。 –

関連する問題