web-dev-qa-db-de.com

Globale Wörterbücher benötigen kein globales Schlüsselwort, um sie zu ändern?

Mögliches Duplikat:
Warum ist das Schlüsselwort global in diesem Fall nicht erforderlich?

Ich frage mich, warum ich das globale Wörterbuch ohne das Schlüsselwort global ändern kann. Warum ist es für andere Typen obligatorisch? Gibt es eine Logik dahinter?

Z.B. Code:

#!/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)

Gibt folgende Ergebnisse:

[email protected]:~/$ ./globalDict.py 
{'key2': 2, 'key1': 1}
{'key2': 2, 'key1': 2}  # Dictionary value has been changed
mod
bar
mod

wo ich erwarten würde:

[email protected]:~/$ ./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

Der Grund ist, dass die Linie

stringvar = "bar"

ist nicht eindeutig, es könnte sich auf eine globale Variable beziehen, oder es könnte eine neue lokale Variable mit dem Namen stringvar erstellen. In diesem Fall wird bei Python standardmäßig davon ausgegangen, dass es sich um eine lokale Variable handelt, es sei denn, das Schlüsselwort global wurde bereits verwendet.

Allerdings ist die Leitung

dictvar['key1'] += 1

Ist völlig eindeutig. Es kann sich nur auf die globale Variable dictvar beziehen, da dictvar bereits vorhanden sein muss, damit die Anweisung keinen Fehler auslöst.

Dies gilt nicht nur für Wörterbücher, sondern auch für Listen:

listvar = ["hello", "world"]

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

oder andere Arten von Objekten:

class MyClass:
    foo = 1
myclassvar = MyClass()

def myclassfoo():
    myclassvar.foo = 2

Dies ist immer dann der Fall, wenn eine Mutationsoperation anstelle einer erneuten Bindung verwendet wird .

41
David Robinson

Sie können jedes veränderbare Objekt ändern, ohne das Schlüsselwort global zu verwenden.

Dies ist in Python möglich, da global verwendet wird, wenn Sie neuen Objekten Variablennamen zuweisen möchten, die bereits im globalen Bereich verwendet werden, oder um neue globale Variablen zu definieren.

Wenn Sie jedoch keine veränderbaren Objekte neu zuweisen, ändern Sie sie nur direkt. Daher lädt Python sie einfach aus dem globalen Bereich und ändert sie.

Als docs sag:

Ohne global wäre es unmöglich, eine globale Variable zuzuweisen.

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