Сообщить об ошибке.

Поведение списков Python в разных областях видимости

Описанное ниже поведение списков в разных областях видимости часто сбивает с толку молодых разработчиков.

Рассмотрим следующий пример:

>>> lst = [1, 2, 3]
>>> def foo1():
...     lst.append(5)   # работает нормально ...
...
>>> foo1()
>>> lst
# [1, 2, 3, 5]

>>> lst = [1, 2, 3]
>>> def foo2():
...     lst += [5]      # выдает ошибку ...
...
>>> foo2()
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
#   File "<stdin>", line 2, in foo
# UnboundLocalError: local variable 'lst' referenced before assignment

Разбираемся почему вызов функции foo2() выдает исключение, а foo1() работает нормально?

Ответ более тонкий и кроется в области видимости глобальной переменной списка lst в локальной области функции foo2().

Функция foo1() не ПРИСВАИВАЕТ значение списку lst, а просто расширяет его содержимое методом list.append(), тогда как функция foo2() пытается расширить список задействовав саму переменную lst. Согласно правилам видимости переменных, в локальной области можно прочитать глобальную переменную, а при попытке присвоения, интерпретатор будет искать ее в локальной области функции, где она еще не определена и выдаст ошибку UnboundLocalError.

Вторая конструкция lst + = [5] (кстати, работает как .append() без изменения id списка) и является сокращением для lst = lst + [5], следовательно происходит присвоение значения списку lst, которое в локальной области функции foo2() определено еще не было.