Проблема в том, что когда вы присваиваете имя переменной внутри функции, Python предполагает, что вы пытаетесь создать новую локальную переменную, которая будет маскировать переменную с аналогичным именем во внешней области видимости.Поскольку +=
должен получить значение mylist
, прежде чем он сможет его изменить, он жалуется, потому что локальная версия mylist
еще не определена. Ответ MRAB дает четкое объяснение семантики.
С другой стороны, когда вы делаете mylist.__iadd__([1])
, вы не назначаете имя новой переменной внутри функции.Вы просто используете встроенный метод для изменения уже назначенного имени переменной.Пока вы не попытаетесь присвоить новое значение mylist
, у вас не будет проблем.По той же причине строка mylist[0] = 5
также будет работать внутри inner
, если бы определение mylist
в outer
было mylist = [1]
.
Обратите внимание, однако, что если вы попытаетесь присвоить новое значение для mylist
в любом месте функции, mylist.__iadd__([1])
действительно потерпит неудачу:
>>> outer()
>>> def outer():
... mylist = []
... def inner():
... mylist.__iadd__([1])
... mylist = []
... inner()
...
>>> outer()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in outer
File "<stdin>", line 4, in inner
UnboundLocalError: local variable 'mylist' referenced before assignment
Если вы хотите назначить новоезначение переменной из содержащей области, в 3.0+ вы можете использовать nonlocal
, точно так же, как вы используете global
, чтобы назначить новое значение переменной в глобальной области.Поэтому вместо этого:
>>> mylist = []
>>> def inner():
... global mylist
... mylist += [1]
...
>>> inner()
>>> mylist
[1]
Вы делаете это:
def outer():
mylist = []
def inner():
nonlocal mylist
mylist += [1]
inner()
print(mylist)
outer()