Закрытие Python и ячейки (закрытые значения) - PullRequest
4 голосов
/ 08 февраля 2012

Что такое механизм Python, который делает так, чтобы

[lambda: x for x in range(5)][2]()

равнялось 4?

Каков обычный прием для привязки копии x к каждомуВыражение lamba, так что приведенное выше выражение будет равно 2?


Мое окончательное решение:

for template, model in zip(model_templates, model_classes):
    def create_known_parameters(known_parms):
        return lambda self: [getattr(self, p.name)
                             for p in known_parms]
    model.known_parameters = create_known_parameters(template.known_parms)

Ответы [ 3 ]

5 голосов
/ 08 февраля 2012
>>> [lambda x=x: x for x in range(5)][2]()
2
4 голосов
/ 08 февраля 2012

Я обычно использую functools.partial :

[ partial(lambda x: x, x) for x in range(5) ]

Или, конечно, вы можете сделать это сами:

[ (lambda x: (lambda: x))(x) for x in range(5) ]
3 голосов
/ 09 февраля 2012

Поскольку никто не ответил на часть «что такое механизм», и это удивило меня, когда я впервые прочитал его, вот что:

Это:

ls = [lambda: x for x in range(5)]

Это немного похоже на:

ls = []
x = 0
ls.append(lambda: x)
x = 1
ls.append(lambda: x)
x = 2
ls.append(lambda: x)
x = 3
ls.append(lambda: x)
x = 4
ls.append(lambda: x)

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

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

Конечно, вы могли бы дополнительно изменить то, что возвращают эти лямбды, связав x, или заставить их выдать ошибку, открепив ее. В версии для понимания списка, x ограничен только частной областью внутри понимания списка, поэтому вы не можете связываться с ним (так легко).

Решение, конечно, состоит в том, чтобы расположить вещи так, чтобы каждая лямбда имела x в своей локальной области видимости (или, по крайней мере, некоторую внешнюю область, которая не является общей для лямбд), чтобы они могли ссылаться на разные объекты. Способы сделать это были показаны в других ответах.

...