Как я создаю список лямбд Python (в цикле понимания/для списка)?

34
задан Community 23 May 2017 в 11:46
поделиться

5 ответов

Я предполагаю, что лямбда, которую Вы создаете в понимании списка, связывается с переменной i, который в конечном счете заканчивается в 5. Таким образом, когда Вы оцениваете лямбды после факта, они все связываются с 5 и заканчивают тем, что вычислили 25. То же самое происходит с цифрой в Вашем втором примере. То, когда Вы оцениваете лямбду в цикле, это - цифра, не изменилось так, Вы получаете правильное значение. После цикла цифра равняется 5...

я не совсем уверен, для чего Вы идете, таким образом, я не уверен, как предложить решение. Как насчет этого?

def square(x): return lambda : x*x
listOfLambdas = [square(i) for i in [1,2,3,4,5]]
for f in listOfLambdas: print f()

Это дает мне ожидаемый вывод:

1
4
9
16
25

Другой способ думать это - то, что лямбда "получает" свою лексическую среду в точке, где это создается. Так, при предоставлении его цифра , это на самом деле не разрешает что значение до его вызванного. Это и сбивает с толку и мощно.

22
ответ дан 27 November 2019 в 16:53
поделиться

Вы имеете:

listOfLambdas = [lambda: i*i for i in range(6)]

for f in listOfLambdas:
    print f()

Вывод:

25
25
25
25
25
25

Вам нужно приправление карри! Кроме того, чтобы быть восхитительным, используйте это значение по умолчанию "взлом".

listOfLambdas = [lambda i=i: i*i for i in range(6)]

for f in listOfLambdas:
    print f()

Вывод:

0
1
4
9
16
25

Примечание i=i. Это - то, где волшебство происходит.

26
ответ дан 27 November 2019 в 16:53
поделиться
listOfLambdas = [lambda i=i: square(i) for i in listOfNumbers]

Или

listOfLambdas = map(lambda i: lambda: square(i), listOfNumbers)
2
ответ дан 27 November 2019 в 16:53
поделиться

Я иногда нахожу, что определение фактических классов для функциональных объектов помогает понять то, что продолжается:

>>> class square(object):
...   def __init__(self, val):
...     self.val = val
...   def __call__(self):
...     return self.val * self.val
...
>>> l = [1,2,3,4,5]
>>> funcs = [square(i) for i in l]
>>> for f in funcs:
...   print f()
...
1
4
9
16
25
>>>

Предоставленный, это является более подробным, чем использование лямбд или закрытий, но я нахожу это легче понять, когда я пытаюсь сделать неочевидные вещи с функциями.

1
ответ дан 27 November 2019 в 16:53
поделиться

Когда функциональные операторы выполняются, они связываются со своим (лексически) включающим объемом.

В Вашем отрывке, лямбды связываются с глобальной областью видимости, потому что for комплекты не выполняются как независимо ограниченная по объему единица в Python. В конце for цикл, эти num связывается в объеме включения. Демонстрация:

for num in range(1, 6):
    pass
assert num == 5 # num is now bound in the enclosing scope

Поэтому при привязке идентификаторов в for цикл, Вы на самом деле управляете объемом включения.

for num in range(1, 6):
    spam = 12
assert num == 5 # num is now bound in the enclosing scope
assert spam == 12 # spam is also bound in the enclosing scope

То же соглашение для пониманий списка:

[num for num in range(1, 6)]
assert num == 5

Сногсшибательный, я знаю. Anywho, с нашим новооткрытым знанием, мы можем решить, что лямбды, которые Вы создаете, обращаются к (синглу) num идентификатор, связанный в объеме включения. Это должно заставить это иметь больше смысла:

functions = []
for number in range(1, 6):
    def fun():
        return number
    functions.append(fun)
assert all(fun() == 5 for fun in functions)
assert all(fun() is number for fun in functions)

И вот самая прохладная часть, которая демонстрирует это еще больше:

# Same as above -- commented out for emphasis.
#functions = []
#for number in range(1, 6):
#    def fun():
#        return number
#    functions.append(fun)
#assert all(fun() == 5 for fun in functions)
#assert all(fun() is number for fun in functions)
number = 6 # Rebind 6 in the scope and see how it affects the results.
assert all(fun() == 6 for fun in functions) 

, Таким образом, решение этого, конечно, состоит в том, чтобы сделать новый объем включения для каждого number, Вы хотите связать. В Python можно создать новые объемы включения с модулями, классами и функциями. Распространено использовать функцию только для создания нового объема включения для другой функции.

В Python, закрытие является функцией что возвраты другая функция . Отчасти как функциональный конструктор. Выезд get_fun в следующем примере:

def get_fun(value):
    """:return: A function that returns :param:`value`."""
    def fun(): # Bound to get_fun's scope
        return value
    return fun

functions = []
for number in range(1, 6):
    functions.append(get_fun(number))
assert [fun() for fun in functions] == range(1, 6)

С тех пор get_fun функция, это добирается, чтобы иметь ее собственный внутренний объем. Каждый раз, когда Вы звоните get_fun со значением, немного таблицы составлено для отслеживания привязку в нем; т.е. это говорит, "В этом объеме, value идентификатор указывает на вещь, которая была передана". Тот объем уходит в конце функционального выполнения, если нет причина его для брожения вокруг.

, Если Вы возвращаете функцию из объема, это - серьезное основание для частей "таблицы объема" для брожения вокруг - которые функционируют, Вы возвращаетесь, мог сослаться на вещи от той таблицы объема, когда Вы называете его позже. По этой причине, когда fun создается в [1 118], Python говорит fun приблизительно [1 120] таблица объема, которая fun сохраняет удобной для того, когда это необходимо.

можно читать больше о деталях и технической терминологии (который я смягчил немного) в документы Python о модели выполнения . Можно также посмотреть на части объема включения, к которому относится функция с [1 122]. В вышеупомянутом мы видим ссылку на эти value, который, оказывается, интервал:

# Same as before, commented out for emphasis.
#functions = []
#for number in range(1, 6):
#    functions.append(get_fun(number))
#assert [fun() for fun in functions] == range(1, 6)
print functions[0].__closure__
# Produces: (<cell at 0x8dc30: int object at 0x1004188>,)
4
ответ дан 27 November 2019 в 16:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: