Глобальные словари не нуждаются в ключевом слове 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)
Дает следующие результаты:
[email protected]:~/$ ./globalDict.py
{'key2': 2, 'key1': 1}
{'key2': 2, 'key1': 2} # Dictionary value has been changed
mod
bar
mod
где я ожидал бы:
[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
Ответы
Ответ 1
Причина в том, что строка
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
Это правда, когда используется мутирующая операция, а не перевязка.
Ответ 2
Вы можете изменить любой изменяемый объект без использования ключевого слова global
.
Это возможно в Python, потому что global
используется, когда вы хотите переназначить новые объекты на имена переменных, уже используемые в глобальной области видимости или для определения новых глобальных переменных.
Но в случае измененных объектов вы не перенаправляете ничего, вы просто модифицируете их на месте, поэтому Python просто загружает их из глобальной области и изменяет их.
Как docs сказать:
Невозможно назначить глобальную переменную без глобального.
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