Отложенная оценка с лямбдой в Python

В цикле я пытаюсь отложить сравнение двух значений () двух узлов на более позднее время.

class Node():
    def __init__(self, v):
        self.v = v
    def value(self):
        return self.v

nodes = [Node(0), Node(1), Node(2), Node(3), Node(4), Node(2)]
results = []
for i in [0, 1, 2]:
    j = i + 3
    results.append(lambda: nodes[i].value() == nodes[j].value())

for result in results:
    print result

Все результаты равны True (поскольку i,j==2,5 для всех лямбда-выражений). Как я могу отложить выполнение лямбды до ее фактического вызова, но с правильными привязками переменных? И выражения в лямбда-выражениях не обязательно равны... есть куча других более сложных выражений.

Спасибо за любую помощь!


person Albeit    schedule 18.06.2012    source источник
comment
Я не совсем уверен, что вы пытаетесь сделать. Лямбда-выражение кажется мне здесь излишним. Почему ты не можешь просто сделать results.append(nodes[i].value() == nodes[j].value())?   -  person JAB    schedule 18.06.2012


Ответы (3)


Чтобы привязать текущие значения i и j к функции вместо того, чтобы смотреть во внешнюю область, вы можете использовать либо замыкание, либо значения аргумента по умолчанию. Самый простой способ сделать это — использовать значения аргументов по умолчанию в вашей лямбде:

for i in [0, 1, 2]:
    j = i + 3
    results.append(lambda i=i, j=j: nodes[i].value() == nodes[j].value())

Вот как это будет выглядеть в закрытом виде:

def make_comp_func(i, j):
    return lambda: nodes[i].value() == nodes[j].value()

for i in [0, 1, 2]:
    j = i + 3
    results.append(make_comp_func(i, j))
person Andrew Clark    schedule 18.06.2012

Оберните его другой лямбдой:

results.append((lambda x, y: lambda: nodes[x].value() == nodes[y].value()) (i, j))

или в более приятном смысле, с partial:

from functools import partial

results.append(partial(lambda x, y: nodes[x].value() == nodes[y].value(), i, j))

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

person georg    schedule 18.06.2012

Идиоматический способ - использовать аргумент по умолчанию:

[f() for f in [lambda: i for i in range(3)]]
[2, 2, 2]

Измените это на:

[f() for f in [lambda i=i: i for i in range(3)]]
[0, 1, 2]
person ecatmur    schedule 18.06.2012