web-dev-qa-db-ja.com

グローバル辞書は、それらを変更するためにキーワードglobalを必要としませんか?

可能性のある複製:
この場合、キーワードglobalは必要ないのはなぜですか

globalキーワードなしでグローバル辞書を変更できるのはなぜですか?他のタイプに必須なのはなぜですか?この背後に何らかのロジックがありますか?

例えば。コード:

#!/usr/bin/env python3

stringvar = "mod"
dictvar = {'key1': 1,
           'key2': 2}

def foo():
    dictvar['key1'] += 1

def bar():
    stringvar = "bar"
    print(stringvar)

print(dictvar)
foo()
print(dictvar)

print(stringvar)
bar()
print(stringvar)

次の結果が得られます。

me@pc:~/$ ./globalDict.py 
{'key2': 2, 'key1': 1}
{'key2': 2, 'key1': 2}  # Dictionary value has been changed
mod
bar
mod

私が期待するところ:

me@pc:~/$ ./globalDict.py 
{'key2': 2, 'key1': 1}
{'key2': 2, 'key1': 1}  # I didn't use global, so dictionary remains the same
mod
bar
mod
31
Jovik

その理由は、

stringvar = "bar"

あいまいで、グローバル変数を参照している可能性がありますまたはstringvarという新しいローカル変数を作成している可能性があります。この場合、Pythonは、globalキーワードが既に使用されていない限り、デフォルトでローカル変数であると想定します。

ただし、行

dictvar['key1'] += 1

完全に明確です。ステートメントがエラーをスローしないためには、dictvarがすでに存在している必要があるため、グローバル変数dictvarのみを参照できます。

これは辞書に固有のものではありません。リストにも同じことが言えます。

listvar = ["hello", "world"]

def listfoo():
    listvar[0] = "goodbye"

または他の種類のオブジェクト:

class MyClass:
    foo = 1
myclassvar = MyClass()

def myclassfoo():
    myclassvar.foo = 2

再バインド操作ではなく、変更操作が使用される の場合は常にtrueです。

41
David Robinson

globalキーワードを使用せずに、任意の可変オブジェクトを変更できます。

これはPythonで可能です。なぜなら、globalは、グローバルスコープで既に使用されている変数名に新しいオブジェクトを再割り当てしたり、新しいグローバル変数を定義するために使用されるためです。

しかし、変更可能なオブジェクトの場合、何も再割り当てするのではなく、インプレースで変更するだけなので、Pythonは単にグローバルスコープからそれらをロードして変更します。

As docs say:

グローバルなしでグローバル変数に割り当てることは不可能です。

In [101]: dic = {}

In [102]: lis = []

In [103]: def func():
    dic['a'] = 'foo'
    lis.append('foo') # but  fails for lis += ['something']
   .....:     

In [104]: func()

In [105]: dic, lis
Out[105]: ({'a': 'foo'}, ['foo'])

dis.dis

In [121]: dis.dis(func)
  2           0 LOAD_CONST               1 ('foo')
              3 LOAD_GLOBAL              0 (dic)     # the global object dic is loaded
              6 LOAD_CONST               2 ('a')
              9 STORE_SUBSCR                         # modify the same object

  3          10 LOAD_GLOBAL              1 (lis)    # the global object lis is loaded
             13 LOAD_ATTR                2 (append)
             16 LOAD_CONST               1 ('foo')
             19 CALL_FUNCTION            1
             22 POP_TOP             
             23 LOAD_CONST               0 (None)
             26 RETURN_VALUE  
7