Почему вывод следующих двух списочных представлений различен, хотя f
и lambda
функция одинакова?
f = lambda x: x*x
[f(x) for x in range(10)]
и
[lambda x: x*x for x in range(10)]
Имейте в виду, оба type(f)
и type(lambda x: x*x)
вернуть тот же тип.
[lambda x: x*x for x in range(10)]
быстрее, чем первый, так как он не вызывает функцию внешнего цикла, f повторно.[x*x for x in range(10)]
, лучше.Ответы:
Первый создает одну лямбда-функцию и вызывает ее десять раз.
Второй не вызывает функцию. Он создает 10 различных лямбда-функций. Это помещает все те в списке. Чтобы сделать его эквивалентным первому, вам нужно:
Или еще лучше:
источник
map(lambda x: x*x, range(10))
, возможно, именно это имел в виду ОП.list(map(lambda x: x*x, range(10)))
, даст вам[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Этот вопрос затрагивает очень вонючую часть «известного» и «очевидного» синтаксиса Python - то, что имеет приоритет, лямбда или для понимания списка.
Я не думаю, что целью ОП было создание списка квадратов от 0 до 9. Если бы это было так, мы могли бы дать еще больше решений:
Но это не главное. Дело в том, что W (hy) TF - это неоднозначное выражение, настолько нелогичное? И в конце у меня для вас идиотский случай, так что не отклоняйте мой ответ слишком рано (он был у меня на собеседовании).
Итак, понимание ОП вернуло список лямбд:
Это, конечно, всего 10 различных копий функции возведения в квадрат, см .:
Обратите внимание на адреса памяти лямбд - они все разные!
Конечно, вы можете иметь более «оптимальную» (ха-ха) версию этого выражения:
Видеть? 3 раза такая же лямбда.
Обратите внимание, что я использовал
_
в качествеfor
переменной. Это не имеет ничего общего сx
inlambda
(это лексически затенено!). Возьми?Я опускаю обсуждение, почему приоритет синтаксиса не таков, что все это означало:
который может быть:
[[0, 1, 4, ..., 81]]
или[(0, 1, 4, ..., 81)]
, или который я считаю наиболее логичным , это будет элементlist
из 1 -generator
возвращающий значения. Это просто не тот случай, язык так не работает.Но что, если ...
Что делать, если вы не затеняете
for
переменную и не используете ее в своей переменнойlambda
???Ну, тогда случается дерьмо. Посмотри на это:
это значит конечно:
НО это не значит:
Это просто безумие!
Лямбды в понимании списка являются закрытием по всему объему этого понимания. Лексическое закрытие, поэтому они относятся к
i
по ссылке, а не его значение , когда они были оценены!Итак, это выражение:
Примерно эквивалентно:
Я уверен, что мы могли бы увидеть больше здесь, используя декомпилятор Python (я имею в виду, например,
dis
модуль), но для обсуждения Python-VM-agnostic этого достаточно. Так много для вопроса собеседования.Теперь, как сделать
list
из лямбда-множителей, которые действительно умножаются на последовательные целые числа? Ну, как и в случае с принятым ответом, нам нужно разорвать прямую связьi
, завернув ее в другойlambda
, вызываемый внутри. выражения понимания списка:Перед:
После:
(У меня была и внешняя лямбда-переменная =
i
, но я решил, что это более ясное решение - я представилy
чтобы мы все могли видеть, какая ведьма какая).Изменить 2019-08-30:
Следуя предложению @josoler, которое также присутствует в ответе @sheridp - значение «петлевой переменной» для понимания списка может быть «встроено» в объект - ключ для доступа к нему в нужное время. Раздел «После» выше делает это, оборачивая его в другой
lambda
и вызывая его немедленно с текущим значениемi
. Другой способ (немного проще для чтения - он не производит эффекта «WAT») - сохранить значениеi
внутриpartial
объекта, а «внутренний» (исходный)lambda
принять его в качестве аргумента (передаваемый отpartial
объектом в время звонка), т.е.После 2:
Отлично, но есть еще маленький поворот для вас! Допустим, мы не хотим облегчить чтение кода и передаем фактор по имени (в качестве ключевого аргумента
partial
). Давайте сделаем переименование:После 2.5:
WAT?
Подождите ... Мы меняем число аргументов на 1 и переходим от «слишком много» к «слишком мало»?
Ну, это не настоящий WAT, когда мы переходим
coef
кpartial
таким образом, становится ключевым словом аргумент, поэтому он должен прийти после того , как позиционнаяx
аргумента, например так:После 3:
Я бы предпочел последнюю версию над вложенной лямбдой, но каждому свою ...
источник
[partial(lambda i, x: i * x, i) for i in (1, 2)]
Большая разница в том, что первый пример фактически вызывает лямбду
f(x)
, а второй - нет.Ваш первый пример эквивалентен,
[(lambda x: x*x)(x) for x in range(10)]
тогда как ваш второй пример эквивалентен[f for x in range(10)]
.источник
Первый
работает
f()
для каждого значения в диапазоне, так чтоf(x)
для каждого значениявторой
запускает лямбду для каждого значения в списке, поэтому он генерирует все эти функции.
источник
Люди дали хорошие ответы , но забыл упомянуть самую важную роль , на мой взгляд: Во втором примере
X
в списке понимание не то же самое , какX
вlambda
функции, они совершенно не связаны. Итак, второй пример на самом деле такой же, как:Внутренние итерации на
range(10)
отвечают только за создание 10 похожих лямбда-функций в списке (10 отдельных функций, но абсолютно одинаковых - возвращая степень 2 каждого входа).С другой стороны, первый пример работает совершенно иначе, потому что X итераций DO взаимодействует с результатами, для каждой итерации значение
X*X
так, что результат будет[0,1,4,9,16,25, 36, 49, 64 ,81]
источник
Другие ответы верны, но если вы пытаетесь составить список функций, каждая из которых имеет свой параметр, который может быть выполнен позже , следующий код сделает это:
Хотя пример придуман, я нашел его полезным, когда мне нужен список функций, каждая из которых печатает что-то свое, т.е.
источник