Найти - Пользователи
Полная версия: Генераторное выражение с lambda делает не то
Начало » Python для экспертов » Генераторное выражение с lambda делает не то
1 2
alien308
Создаю список функций вычисляющих многочлен Лежандра от нулевого до пятого порядка при заданном x.
 from scipy.special import eval_legendre
M0 = 6
f0_l = [lambda x:  eval_legendre(i, x)  for i in range(M0)]
На самом деле вызов
 f0_l[0](0.5)
вычисляет значение полинома Лежандра 5 порядка при аргументе 0.5.
При внимательном рассмотрение оказывается что при выполнении генераторного выражения в области видимости появляется переменная i значением 5. И все элементы списка видят эту переменную и определяют порядок полинома по ней.
Как поправить, чтобы в списке функции просто вычисляли полином с порядком
заданным в генераторном выражении.

Python 2.7.9
FishHook
alien308
 [lambda x:  eval_legendre(i, x)  for i in range(M0)]
Вот эта вот херня во втором питоне создает переменные в объемлющем неймспейсе, то есть i из списочного выражения переползает в область видимости функции. С этим сделать ничего нельзя, просто иметь в виду
Rodegast
От версии питона это не зависит. А происходит очень банальная вещь, lambda-функция получает ссылку на переменную, а не её значение. Как с этим бороться тоже вполне очевидно.
 >>> s = [ lambda x: x+y for y in range(10) ]
>>> [ x(i) for i, x in enumerate(s) ]
[9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
>>> s = [ lambda x, y=y: x+y for y in range(10) ]
>>> [ x(i) for i, x in enumerate(s) ]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
alien308
Спасибо, заработало!
FishHook
Rodegast
От версии питона это не зависит.
Еще как зависит, в третьем пофиксили

второй
 [x for x in range(10)]
print(x)
>>>9

третий
 [x for x in range(10)]
print(x)
Traceback (most recent call last):
  File "/Users/asmirnov/PycharmProjects/test/test.py", line 5, in <module>
    print(x)
NameError: name 'x' is not defined
Rodegast
> Еще как зависит, в третьем пофиксили

 rodegast@rodegast:~$ python3
Python 3.4.2 (default, Oct  8 2014, 10:45:20) 
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> s = [ lambda x: x+y for y in range(10) ]
>>> [ x(i) for i, x in enumerate(s) ]
[9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
Slow
Rodegast
some strange code

Так у вас замыкание некорректно описано. Естественно, что он замыкает у, но не значение, а ссылку на значение.
Значение по ссылке у вас заменяется в каждой итерации компрехеншна, порождающего s, что изменяет и ранее созданные замыкания (лол, насколько это корректно - это как раз большой вопрос к гвидо)
но после выхода из компрехеншна переменная y определена не будет. посмотрите сами.
Тут вы привели абсолютно некорректный пример.
Slow
То же самое и у топикстартера. Проблема вообще не в области видимости, а в том, как не надо делать замыкания в питоне.
Rodegast
> Так у вас замыкание некорректно описано.

Я то я этого не знаю.

> Тут вы привели абсолютно некорректный пример.

Это иллюстрация того что “от версии питона это не зависит”.
Slow
https://stackoverflow.com/questions/2295290/what-do-lambda-function-closures-capture

тут суть в том, что лямбда - ленивая.
то есть, значение замыкания берется на момент вызова лямбды, а не на момент создания.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB