Понимание лямбда-функции переформатирования для закрытия - PullRequest
0 голосов
/ 19 июня 2019

Недавно у меня возникла проблема, когда я использовал лямбда-функцию в цикле for для pyqt с .connect. Это вызвало проблему с закрытием в лямбда-функции, я смог решить ее с помощью functools, но после немного большего исследования я обнаружил, что могу использовать немного другой фрагмент кода, который не требует импорта functools.

Пример кода с использованием формата:

for i in range(0,len(items)):
     items[i].connect( ( lambda i: lambda: func(i) )(i) )

def func(i):
    print('i value ' + str(i))

Я не уверен, почему это работает.

Я пытался сделать

for i in range(0,len(items)):
     items[i].connect( lambda i=i: func(i) )

def func(i):
    print('i value ' + str(i))

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

Любая помощь будет оценена, спасибо.

1 Ответ

0 голосов
/ 19 июня 2019

In Python Значения по умолчанию, такие как i=i в определении лямбды во втором примере, вычисляются только один раз, когда определяется определение функции (не каждый раз, когда оператор интерпретируется).Это означает, что i назначается на первой итерации, а затем никогда не изменяется.

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

for i in range(0, len(items)):
     items[i].connect( ( lambda x: lambda: func(x) )(i) )
...