局部变量的第一个 lambda 捕获始终为 False

First lambda capture of local variable always False

将lambda函数连接到Qt小部件,lambda需要捕获两个局部变量并将它们传递给外部函数。我遇到了一个困扰我的问题,因为它绝对是位置问题:

pushbutton.clicked.connect(lambda ca=current_answer, a=correct_answer:
            self.ap.parse_answer(ca, a))

通过(False, "desired correct_answer string"),同时切换局部变量捕获的顺序:

pushbutton.clicked.connect(lambda a=correct_answer,ca=current_answer:
            self.ap.parse_answer(ca, a))

通过 ("desired current_answer string", False)

我首先捕获的任何一个变量始终设置为 False,而第二个变量捕获始终是预期的。

这表明我的代码中没有其他东西将 False 分配给 current_answercorrect_answer,并且在调用 lambda 函数之前立即插入的 print() 语句确认了两者变量设置为所需的字符串。也许我只是没有正确捕获变量,但在阅读了一些内容之后,我找不到我的语法有任何问题。我的变量捕获看起来与我发现的许多示例相同。

我很确定它只是以下内容:

当我们在函数定义中定义默认参数时 f(keyword=default...) 但在调用中我们没有明确声明 keyword=value 然后它关心参数的顺序,即使它们看起来与关键字匹配.所以我相信你的 lambda 函数关心它接收的顺序,而不是你分配的默认值。在您的第一个示例中, ca 获取第一个参数发送给 lambda 的任何内容, a 获取第二个参数的任何内容。在您的第二个示例中, a 获取第一个参数, ca 获取第二个参数。您为它们定义了默认值这一事实并没有做任何事情,除非调用 lambda 的任何东西都没有向它发送任何内容。

如果我定义一个函数

def f(a=1,b=2):
    return (a,b)

然后称其为

a=True
b=False
(x,y) = f(a,b)

我会找到x=Trueb=False

但如果相反,我将其称为

a=True
b=False
(x,y) = f(b,a)

我会找到 x=Falseb=True,因为当我这样调用它时,它会理解调用的第一个参数是 a,第二个参数是 b.

如果我使用第三个选项(这是我认为你所期待的)

(x,y) = f(b=False, a=True)

然后我得到 x=Truey=False。我认为这就是您认为会得到的行为。

根据 BrenBarn 和 Lambda Fairy 的评论,我决定假设 Qt 正在将第一个参数的值重置为 False。

作为变通方法,我向 ap.parse_answer 添加了第三个位置参数,并让 lambda 表达式在捕获两个重要变量之前捕获一个微不足道的局部变量:

pushbutton.clicked.connect(lambda sacrificial="",a=answer,ca=current_answer: 
                                      self.ap.parse_answer(sacrificial, ca, a))

Qt 覆盖的变量只是被调用的函数忽略,并且代码有效。

如果我向 ap.parse_answer() 添加一个 print(sacrificial_variable) 调用,毫不奇怪它的值为 False。

您总是看到 False 作为传递给回调 lambda 的第一个参数,因为 Qt 定义信号 QAbstractButton::clicked 以采用默认值为 False 的单个参数。由于您的 lambda 正在处理该信号,因此会使用 False.

调用它

为了其他人的利益:因为 lambda 只用一个参数调用,所以第二个和第三个参数获得它们的默认值,OP 现在将其定义为范围内变量的值 answercurrent_answer.