Global dictionaries don't need keyword global to modify them?
Solution 1
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.
Solution 2
You can modify any mutable object without using global
keyword.
This is possible in Python because global
is used when you want to reassign new objects to variable names already used in global scope or to define new global variables.
But in case of mutable objects you're not re-assigning anything, you're just modifying them in-place, therefore Python simply loads them from global scope and modifies them.
As docs say:
It would be impossible to assign to a global variable without global.
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
Jovik
Updated on July 09, 2022Comments
-
Jovik almost 2 years
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
-
Jovik over 11 yearsI read SO: Global keyword in Python and SO: Why is keyword global not required, so I know how dictionary works without
global
, but I still fail to understand why Python has different scope approach depending on variable type? -
mmgp over 11 yearsYou haven't understood the difference between mutable and immutable objects in Python. If you read docs.python.org/2/reference/datamodel.html (at least the subsection 3.1, don't skip parts of it just because you think you already know it) then it should become clear.
-
Martijn Pieters over 11 yearsThere is nothing specific to Python 3 in this question.
-
-
Jovik over 11 yearsI understand I can do it (and mechanism behind it). What bothers me is why Python makes exceptions for
global
statement? -
Martijn Pieters over 11 years@Jovik: There is no exception being made. You are confused between variable assignment and value manipulation. You cannot do
var = 'string'
,var.insert(0, 'othertext')
because a string is not mutable, you can only replace the value the variable points to. But you can alter a mutable. You can dovar1 = {}
,var2 = var1
,var2.update({'another': 'dict'})
and you'll see thatvar1
reflects that same change. You changed a mutable value, not the variables that point to it. -
mmgp over 11 years
stringvar = "bar"
is only ambiguous if you are considering a language other than Python. The only barely positive message someone can take from this is answer is the bottom-most link. -
David Robinson over 11 years@mmgp: I think you misunderstand me. I'm not saying the behavior is ambiguous or undefined. The OP was asking why Python behaves as it does, and I was explaining why it doesn't have a choice- because it can't know when you have the line
stringvar = "bar"
whether you mean to refer to the global variable or create a local variable. It therefore defaults to creating a local variable. -
Jin over 5 yearsSo if there is a local dictionary also called
dictvar
, would that get invoked first before the global one? -
David Robinson over 5 years@Jin yes, that’s right!