变量如何在lambda函数中工作?

2024-10-01 19:15:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我尝试使用lambda函数和python3.6中的一些pyqt5qpushbutton将9个不同的按钮连接到一个处理程序。如果我用整数单独分配它们,一切都很好。不过,如果他们被分配了一个10的循环和一个数字,他们尝试使用10。我不明白为什么,因为我会认为我的赋值是给整数值的,而我的变量超出了范围。很明显,这里有些事情我不明白。有人能解释这个代码的行为吗?在

    self.buttonList = [ self.sq1Button,
                        self.sq2Button,
                        self.sq3Button,
                        self.sq4Button,
                        self.sq5Button,
                        self.sq6Button,
                        self.sq7Button,
                        self.sq8Button,
                        self.sq9Button]
    buttonNumber = 1
    for button in self.buttonList:
        button.clicked.connect(lambda: self.squareButtonHandler(buttonNumber))
        buttonNumber += 1

Tags: lambda函数代码self处理程序button数字整数
2条回答

我曾经遇到过同样的问题,this帮助了我。您基本上需要做的是将click处理程序移动到一个单独的函数中,并在循环中使用buttonNumber调用该函数。这可能是由于闭包的工作方式和/或是因为每次循环运行时它都需要一个新的buttonNumber。我仍然不明白确切的原因,所以如果有人知道,请评论/编辑。在

当python执行一个函数时,它会创建一个命名空间来保存局部变量。lambda在里面

button.clicked.connect(lambda: self.squareButtonHandler(buttonNumber))

是一个内部函数,它在外部作用域中包含对buttonNumber的引用。当您将lambda传递给button.clicked.connect时,python必须以某种方式记住该引用。它通过将外部作用域的上下文添加到它创建并传递给connect的函数对象来实现这一点。您连接的所有按钮的函数对象引用相同的外部上下文,这意味着当函数退出时,它们都将看到buttonNumber中的内容。在

下面是一个正在运行的示例,它显示了您的问题

^{pr2}$

它产生了

test 1
button 4
button 4
button 4
button 4
button 4

是的,这就是问题所在。让我们看看通过查看函数对象的闭包创建的函数对象

print("test 2")
for handler in try_lambda():
    handler()
    print(handler, handler.__closure__)

它显示了

test 2
button 4
<function try_lambda.<locals>.<lambda> at 0x7f66e34a9d08> (<cell at 0x7f66e49fb3a8: int object at 0xa68aa0>,)
button 4
<function try_lambda.<locals>.<lambda> at 0x7f66e34a9d90> (<cell at 0x7f66e49fb3a8: int object at 0xa68aa0>,)
button 4
<function try_lambda.<locals>.<lambda> at 0x7f66e34a9e18> (<cell at 0x7f66e49fb3a8: int object at 0xa68aa0>,)
button 4
<function try_lambda.<locals>.<lambda> at 0x7f66e34a9ea0> (<cell at 0x7f66e49fb3a8: int object at 0xa68aa0>,)
button 4
<function try_lambda.<locals>.<lambda> at 0x7f66e349a048> (<cell at 0x7f66e49fb3a8: int object at 0xa68aa0>,)

有趣。我们有4个不同的函数对象(0x7f66e34a9d08,等等),但是只有一个单元格保存我们想要的变量0x7f66e49fb3a8。这就是为什么它们都看到相同的数字-它们都使用外部函数的局部变量中保存的相同单元格。在

{cd5>在这种情况下,{cd5}是更好的选择。它使用一个变量的当前值创建一个函数,并按照您想要的方式工作。在

import functools

def try_partial():
    handlers = []
    for num in range(5):
        handlers.append(functools.partial(buttonHandler, num))
    return handlers

print("test 3")
for handler in try_partial():
    handler()

它产生了

test 3
button 0
button 1
button 2
button 3
button 4

相关问题 更多 >

    热门问题