Я думаю, что совершенно очевидно, что происходит, когда вы думаете о i
как имя , а не какое-то значение .Ваша лямбда-функция делает что-то вроде «возьми x: посмотри значение i, посчитай i ** x» ... поэтому, когда ты на самом деле запускаешь функцию, она смотрит i
только тогда так i
is 4
.
Вы также можете использовать текущий номер, но вы должны заставить Python связать его с другим именем:
def makeActions():
def make_lambda( j ):
return lambda x: j * x # the j here is still a name, but now it wont change anymore
acts = []
for i in range(5):
# now you're pushing the current i as a value to another scope and
# bind it there, under a new name
acts.append(make_lambda(i))
return acts
Это может показаться запутанным, потому что вы частонаучите, что переменная и ее значение - это одно и то же, что верно, но только в тех языках, которые действительно используют переменные.В Python нет переменных, но есть имена.
По поводу вашего комментария, на самом деле я могу проиллюстрировать это немного лучше:
i = 5
myList = [i, i, i]
i = 6
print(myList) # myList is still [5, 5, 5].
Вы сказали, что изменили меня на 6 это не то, что на самом деле произошло: i=6
означает «у меня есть значение, 6
, и я хочу назвать его i
».Тот факт, что вы уже использовали i
в качестве имени, не имеет значения для Python, он просто переназначит имя , а не изменит его значение (работает только с переменными).
Можно сказать, что в myList = [i, i, i]
любое значение i
, на которое в данный момент указывает (число 5), получает три новых имени: mylist[0], mylist[1], mylist[2]
.То же самое происходит и при вызове функции: аргументам присваиваются новые имена.Но это, вероятно, идет вразрез с любой интуицией о списках ...
Это может объяснить поведение в следующем примере: вы присваиваете mylist[0]=5
, mylist[1]=5
, mylist[2]=5
- неудивительно, что они не меняются, когдаВы переназначаете i
.Если бы i
было чем-то изменяемым, например, списком, то изменение i
отразилось бы и на всех записях в myList
, потому что у вас просто есть разных имен для одного и того же значения !
Простой факт, что вы можете использовать mylist[0]
слева от =
, доказывает, что это действительно имя.Мне нравится вызывать =
оператор присваивания имени : он принимает имя слева и выражение справа, затем оценивает выражение (функция вызова, ищет значения за именами) до тех пор, покаимеет значение и, наконец, дает имя значению. ничего не меняет .
Для комментариев Маркса о компиляции функций:
Ну, ссылки (и указатели) имеют смысл только тогда, когда у нас есть какая-то адресуемая память.Значения хранятся где-то в памяти, и ссылки ведут вас туда.Использование ссылки означает переход в это место в памяти и что-то с ним делать.Проблема в том, что нет этих понятий используется Python!
В Python VM нет понятия памяти - значения плавают где-то в пространстве , а имена - это маленькие тегиподключен к ним (с помощью маленькой красной нити).Имена и значения существуют в разных мирах!
Это имеет большое значение при компиляции функции.Если у вас есть ссылки, вы знаете расположение памяти объекта, на который ссылаетесь.Тогда вы можете просто заменить ссылку на это место.Имена с другой стороны не имеют местоположения, поэтому вам нужно (во время выполнения) следовать этой маленькой красной строке и использовать то, что находится на другом конце.Вот как Python компилирует функции: где бы ни было имя в коде, он добавляет инструкцию, которая выяснит, что означает это имя.
Таким образом, в основном Python полностью компилирует функции, но имена компилируютсяв качестве поиска во вложенных пространствах имен, , а не в качестве некоторой ссылки на память.
Когда вы используете имя, компилятор Python попытается выяснить, к какому пространству имен оно принадлежит.В результате получается инструкция для загрузки этого имени из найденного им пространства имен.
Что возвращает вас к исходной проблеме: в lambda x:x**i
i
компилируется как поиск в пространстве имен makeActions
(потому что там использовался i
). Python понятия не имеет и не заботится о значении, стоящем за ним (оно даже не должно быть действительным именем). Тот код, который запускает i
, ищется в его оригинальном пространстве имен и дает более или менее ожидаемое значение.