Python, конечно, использует ссылки, но это не имеет значения в этом контексте.
Когда вы определяете лямбду (или функцию, поскольку это точно такое же поведение), она не оценивает лямбда-выражение до времени выполнения:
# defining that function is perfectly fine
def broken():
print undefined_var
broken() # but calling it will raise a NameError
Еще более удивительно, чем ваш лямбда-пример:
i = 'bar'
def foo():
print i
foo() # bar
i = 'banana'
foo() # you would expect 'bar' here? well it prints 'banana'
Короче говоря, думайте динамически: перед интерпретацией ничего не оценивается, поэтому в вашем коде используется последнее значение m.
Когда он ищет m в лямбда-исполнении, m берется из самой верхней области, что означает, что, как указали другие; Вы можете обойти эту проблему, добавив еще одну область видимости:
def factory(x):
return lambda: callback(x)
for m in ('do', 're', 'mi'):
funcList.append(factory(m))
Здесь, когда вызывается лямбда, он смотрит в области определения лямбда для х. Этот x является локальной переменной, определенной в теле фабрики. Из-за этого значение, используемое при лямбда-выполнении, будет значением, переданным в качестве параметра во время вызова фабрики. И дореми!
Как примечание, я мог бы определить фабрику как фабрику (m) [заменить x на m], поведение такое же. Я использовал другое имя для ясности:)
Возможно, вы обнаружите, что Andrej Bauer столкнулся с похожими лямбда-проблемами. Что интересно в этом блоге, так это комментарии, где вы узнаете больше о закрытии Python:)