Я думаю, что ответ на этот вопрос заключается в том, как python передает данные параметру (передача по значению или по ссылке), а не изменчивости или как python обрабатывает оператор "def".
Краткое введение. Во-первых, в Python есть два типа данных: один простой элементарный тип данных, такой как числа, а другой тип данных - объекты. Во-вторых, при передаче данных в параметры python передает элементарный тип данных по значению, то есть создает локальную копию значения в локальной переменной, но передает объект по ссылке, т.е. указатели на объект.
Принимая во внимание два вышеизложенных момента, давайте объясним, что случилось с кодом Python. Это происходит только из-за передачи по ссылке для объектов, но не имеет ничего общего с изменяемым / неизменным или, возможно, с тем фактом, что оператор def выполняется только один раз, когда он определен.
[] является объектом, поэтому python передает ссылку [] на a
, т.е. a
является только указателем на [], который лежит в памяти как объект. Существует только одна копия [] с множеством ссылок на нее. Для первого foo () список [] изменяется на 1 методом добавления. Но обратите внимание, что существует только одна копия объекта списка, и этот объект теперь становится 1 . При запуске второй функции foo () неверно то, что говорит веб-страница effbot (элементы больше не оцениваются). a
оценивается как объект списка, хотя теперь содержимое объекта равно 1 . Это эффект передачи по ссылке! Результат foo (3) может быть легко получен таким же образом.
Для дальнейшей проверки моего ответа давайте рассмотрим два дополнительных кода.
====== № 2 ========
def foo(x, items=None):
if items is None:
items = []
items.append(x)
return items
foo(1) #return [1]
foo(2) #return [2]
foo(3) #return [3]
[]
- это объект, также как и None
(первый изменчив, а второй неизменен. Но изменчивость не имеет ничего общего с вопросом). Никого нет где-то в космосе, но мы знаем, что это там, и там есть только одна копия Никого. Таким образом, каждый раз, когда вызывается foo, элементы оцениваются (в отличие от некоторого ответа, что он оценивается только один раз), чтобы быть None, чтобы быть ясным, ссылка (или адрес) None. Затем в foo элемент изменяется на [], то есть указывает на другой объект с другим адресом.
====== № 3 =======
def foo(x, items=[]):
items.append(x)
return items
foo(1) # returns [1]
foo(2,[]) # returns [2]
foo(3) # returns [1,3]
При вызове foo (1) элементы указывают на объект списка [] с адресом, скажем, 11111111. содержимое списка изменяется на 1 в функции foo в дальнейшем, но адрес не изменился, все равно 11111111. Затем приходит foo (2, []). Хотя [] в foo (2, []) имеет то же содержимое, что и параметр по умолчанию [] при вызове foo (1), их адреса разные! Поскольку мы предоставляем параметр явно, items
должен взять адрес этого нового []
, скажем, 2222222, и вернуть его после внесения некоторых изменений. Теперь foo (3) выполняется. поскольку предоставляется только x
, элементам снова нужно принять значение по умолчанию. Какое значение по умолчанию? Он устанавливается при определении функции foo: объекта списка, расположенного в 11111111. Таким образом, элементы оцениваются как адрес 11111111, имеющий элемент 1. Список, расположенный в 2222222, также содержит один элемент 2, но он не указывается элементами Больше. Следовательно, приложение 3 составит items
[1,3].
Из приведенных выше объяснений видно, что веб-страница effbot , рекомендованная в принятом ответе, не дала соответствующего ответа на этот вопрос. Более того, я думаю, что точка на веб-странице effbot неверна. Я думаю, что код относительно UI.Button правильный:
for i in range(10):
def callback():
print "clicked button", i
UI.Button("button %s" % i, callback)
Каждая кнопка может содержать отдельную функцию обратного вызова, которая будет отображать различное значение i
. Я могу привести пример, чтобы показать это:
x=[]
for i in range(10):
def callback():
print(i)
x.append(callback)
Если мы выполним x[7]()
, мы получим 7, как ожидалось, а x[9]()
даст 9, еще одно значение i
.