Lambdas из понимания списка возвращает лямбду при вызове

Я пытаюсь перебрать lambda func над списком, как в test.py , и я хочу получить результат вызова лямбда, а не сам объект функции. Однако следующий результат действительно смутил меня.

 ------test.py--------- #!/bin/env python #coding: utf-8 a = [lambda: i for i in range(5)] for i in a: print i() --------output--------- <function <lambda> at 0x7f489e542e60> <function <lambda> at 0x7f489e542ed8> <function <lambda> at 0x7f489e542f50> <function <lambda> at 0x7f489e54a050> <function <lambda> at 0x7f489e54a0c8> 

Я изменил имя переменной, когда печатаю результат вызова в t следующим образом, и все идет хорошо. Мне интересно, что это значит? ?

 --------test.py(update)-------- a = [lambda: i for i in range(5)] for t in a: print t() -----------output------------- 4 4 4 4 4 

3 Solutions collect form web for “Lambdas из понимания списка возвращает лямбду при вызове”

В Python 2 понимается «утечка» переменных для внешней области:

 >>> [i for i in xrange(3)] [0, 1, 2] >>> i 2 

Обратите внимание, что поведение на Python 3 отличается:

 >>> [i for i in range(3)] [0, 1, 2] >>> i Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'i' is not defined 

Когда вы определяете лямбда, она привязана к переменной i , а не ее текущему значению, как показывает ваш второй пример. Теперь, когда вы назначаете новое значение i lambda вернет все текущее значение:

 >>> a = [lambda: i for i in range(5)] >>> a[0]() 4 >>> i = 'foobar' >>> a[0]() 'foobar' 

Поскольку значение i в цикле является самой лямбдой, вы получите его как возвращаемое значение:

 >>> i = a[0] >>> i() <function <lambda> at 0x01D689F0> >>> i()()()() <function <lambda> at 0x01D689F0> 

UPDATE : пример для Python 2.7:

 Python 2.7.6 (default, Jun 22 2015, 17:58:13) [GCC 4.8.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> a = [lambda: i for i in range(5)] >>> for i in a: ... print i() ... <function <lambda> at 0x7f1eae7f15f0> <function <lambda> at 0x7f1eae7f1668> <function <lambda> at 0x7f1eae7f16e0> <function <lambda> at 0x7f1eae7f1758> <function <lambda> at 0x7f1eae7f17d0> 

То же самое на Python 3.4:

 Python 3.4.3 (default, Oct 14 2015, 20:28:29) [GCC 4.8.4] on linux Type "help", "copyright", "credits" or "license" for more information. >>> a = [lambda: i for i in range(5)] >>> for i in a: ... print(i()) ... 4 4 4 4 4 

Подробные сведения об изменениях в области переменных с пониманием списка см. В блоге Guido с 2010 года .

Мы также сделали еще одно изменение в Python 3, чтобы улучшить эквивалентность между выражениями списков и выражениями генератора. В Python 2, понимание списка «утечки» переменной управления циклом в окружающую область:

 x = 'before' a = [x for x in 1, 2, 3] print x # this prints '3', not 'before' 

Тем не менее, в Python 3 мы решили исправить «грязный маленький секрет» понимания списков, используя ту же стратегию реализации, что и для выражений генератора. Таким образом, в Python 3 приведенный выше пример (после модификации использования print (x) 🙂 будет печатать «before», доказывая, что «x» в понимании списка временно затеняет, но не переопределяет «x» в окружающем объем.

Закрытие в Python является поздним связыванием , что означает, что каждая функция лямбда в списке будет оценивать только переменную i при вызове, а не когда она определена. Вот почему все функции возвращают одно и то же значение, т. ì Последнее значение ì (которое равно 4).

Чтобы этого избежать, одним из способов является привязка значения i к локальному именованному параметру:

 >>> a = [lambda i=i: i for i in range(5)] >>> for t in a: ... print t() ... 0 1 2 3 4 

Другим вариантом является создание частичной функции и привязка текущего значения i качестве его параметра:

 >>> from functools import partial >>> a = [partial(lambda x: x, i) for i in range(5)] >>> for t in a: ... print t() ... 0 1 2 3 4 

Изменить: Извините, неправильно изначально возник вопрос, так как такие вопросы так часто связаны с поздним связыванием (спасибо @soon за комментарий).

Вторая причина для поведения – это утечка списка в Python2, как уже объяснили другие. При использовании i в качестве переменной итерации в цикле for каждая функция печатает текущее значение i (по причинам, указанным выше), что является просто самой функцией. При использовании другого имени (например, t ) функции печатают последнее значение i как это было в цикле понимания списка, который равен 4.

lambda: i – анонимная функция без аргументов, возвращающих i. Таким образом, вы создаете список анонимных функций, которые вы можете позже (во втором примере) привязать к имени t и вызвать с помощью () . Обратите внимание, что вы можете сделать то же самое с не анонимными функциями:

 >>> def f(): ... return 42 ... >>> name = f >>> name <function f at 0x7fed4d70fb90> >>> name() 42 

@plamut только что ответил на подразумеваемую другую часть вопроса, поэтому я не буду.

  • Проблемы с лямбдой Python
  • Повышение эффективности функции ранжирования путем замены лямбда x на векторизация
  • Как сортировать с лямбдой в Python
  • E731 не назначают лямбда-выражение, используйте def
  • Использовать значение переменной в выражении лямбда
  • аргументы с распаковкой лямбда
  • В чем преимущество использования функции лямбда: None?
  • Что означает «лямбда» в Python и какой самый простой способ использовать его?
  •  
    Interesting Posts for Van-Lav

    как вы фильтруете кадры данных pandas несколькими столбцами

    как очистить информацию о продукте на веб-странице amazon с помощью beautifulsoup

    Установка GOOGLE_APPLICATION_CREDENALAL для командной строки BigQuery Python

    Как разбить массив в соответствии с условием в numpy?

    Как фильтровать на рассчитанные значения модели, используя понимание списка

    Как добавить пространство между метками и осями в matplotlib?

    Наблюдатель Наблюдаемые классы в python

    Ошибка установки Pyodbc на Ubuntu 16.04 с установленным сервером Sql

    Необходимо избегать взаимоблокировки подпроцесса без связи

    Python-запросы не освобождают память при загрузке с сеансами

    Почему я не могу называть hash () по явно хешируемому методу нераскрывающегося экземпляра?

    как изменить значение поля по умолчанию из другой модели в odoo

    Django-rest-framework @detail_route для определенного URL-адреса

    Python – Разница между docopt и argparse

    Вызов C / C ++ из python?

    Python - лучший язык программирования в мире.