Что происходит с лямбда-выражением в этой функции python? - PullRequest
5 голосов
/ 09 мая 2009

Почему эта попытка создать список каррированных функций не работает?

def p(x, num):
    print x, num

def test():
    a = []
    for i in range(10):
        a.append(lambda x: p (i, x))
    return a

>>> myList = test()
>>> test[0]('test')
9 test
>>> test[5]('test')
9 test
>>> test[9]('test')
9 test

Что здесь происходит?

Функция, которая на самом деле выполняет то, что, как я ожидаю, выполняет вышеуказанная функция:

import functools
def test2():
    a = []
    for i in range (10):
        a.append(functools.partial(p, i))
    return a


>>> a[0]('test')
0 test
>>> a[5]('test')
5 test
>>> a[9]('test')
9 test

Ответы [ 4 ]

12 голосов
/ 09 мая 2009

В Python переменные, созданные в циклах и ветвях, не ограничены. Все функции, которые вы создаете с помощью lambda, имеют ссылку на одну и ту же переменную i, которая установлена ​​на 9 на последней итерации цикла.

Решение состоит в том, чтобы создать функцию, которая возвращает функцию, тем самым определяя область видимости переменной итератора. Вот почему functools.partial() подход работает. Например:

def test():
    def makefunc(i):
        return lambda x: p(i, x)
    a = []
    for i in range(10):
        a.append(makefunc(i))
    return a
1 голос
/ 05 апреля 2013

Меня всегда смущало, почему это не работает. Спасибо за объяснение, ' платный ботаник '. Я лично предпочитаю это решение:

for i in range(10):
    a.append(lambda num, val_i=i: p (val_i, num))

Обратите внимание на val_i=i аргумент по умолчанию lambda, который позволяет захватывать мгновенное значение i во время цикла, в то же время фактически делая lambda функцией 1 переменной. (Кстати: вы изменили x на num в соответствии с определением p.) Мне это нравится больше, потому что:

  1. она очень близка к исходной идее и не требует определения новой именованной функции, именно цели лямбды ...
  2. избегает импорта functools
  3. и избегает нелепых лямбд ...

Только что выполнил поиск и нашел там более подробные объяснения той же проблемы: Область применения лямбда-функций Python и их параметров

1 голос
/ 09 мая 2009

Ну, вы также можете привязать i к внешней лямбде для ленивых.

def p(x, num):
    print x, num

def test():
    a = []
    for i in range(10):
        a.append((lambda i :lambda x: p (i, x))(i))
    return a
0 голосов
/ 09 мая 2009

Я задал похожий вопрос и получил два ответа. Один в основном такой же, как принятый здесь ответ, а другой менее понятный, но немного более лаконичный.

Динамическое создание меню в Tkinter. (лямбда-выражения?)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...