Search code examples
pythondictionaryscopeglobal-variablesglobal

Global dictionaries don't need keyword global to modify them?


I wonder why I can change global dictionary without global keyword? Why it's mandatory for other types? Is there any logic behind this?

E.g. 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)

Gives following results:

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

where I would expect:

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

Solution

  • The reason is that the line

    stringvar = "bar"
    

    is ambiguous, it could be referring to a global variable, or it could be creating a new local variable called stringvar. In this case, Python defaults to assuming it is a local variable unless the global keyword has already been used.

    However, the line

    dictvar['key1'] += 1
    

    Is entirely unambiguous. It can be referring only to the global variable dictvar, since dictvar must already exist for the statement not to throw an error.

    This is not specific to dictionaries- the same is true for lists:

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

    or other kinds of objects:

    class MyClass:
        foo = 1
    myclassvar = MyClass()
    
    def myclassfoo():
        myclassvar.foo = 2
    

    It's true whenever a mutating operation is used rather than a rebinding one.