Множество идей в ответах здесь, но я думаю, что дополнительный момент здесь явно не упоминается. Цитирование из документации по питону https://docs.python.org/2/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python
"В Python переменные, на которые ссылаются только внутри функции, неявно глобальны. Если переменной присваивается новое значение где-либо в теле функции, она считается локальной. Если переменной когда-либо назначается новое значение внутри функция, переменная неявно локальна, и вам нужно явно объявить ее как «глобальную».
Хотя поначалу это немного удивляет, это объясняется моментальным рассмотрением. С одной стороны, требование наличия глобальных для назначенных переменных обеспечивает защиту от непреднамеренных побочных эффектов. С другой стороны, если глобальный требовался для всех глобальных ссылок, вы бы использовали global все время. Вы должны были бы объявить как глобальную каждую ссылку на встроенную функцию или компонент импортируемого модуля. Этот беспорядок отрицательно скажется на полезности глобальной декларации для выявления побочных эффектов. "
Даже при передаче изменяемого объекта в функцию это все равно применяется. И мне ясно объясняется причина различий в поведении между назначением объекта и воздействием на объект в функции.
def test(l):
print "Received", l , id(l)
l = [0, 0, 0]
print "Changed to", l, id(l) # New local object created, breaking link to global l
l= [1,2,3]
print "Original", l, id(l)
test(l)
print "After", l, id(l)
дает:
Original [1, 2, 3] 4454645632
Received [1, 2, 3] 4454645632
Changed to [0, 0, 0] 4474591928
After [1, 2, 3] 4454645632
Назначение глобальной переменной, которая не объявлена глобальной, поэтому создает новый локальный объект и разрывает ссылку на исходный объект.