如何使用与循环中创建的多个按钮的命令相同的功能?

时间:2015-12-01 20:28:29

标签: python

我正在创建一个按钮的tic-tac-toe板。单击时,每个按钮应交替切换到X或O.我已经在for循环中创建了按钮,并且如果可能的话,会避免单独初始化它们。 我已经尝试使用lambda将按钮传递给函数,并且我已经尝试通过调用self.bttn按钮来消除命令中的参数问题(因为这都发生在我修改的Frame类中)。但是,在这两种情况下,我遇到的问题是,无论我点击哪9个按钮,for循环创建的最终按钮都会响应。

def __build_board(self):
    """ Creates tic-tac-toe board of 9 blank buttons. """
    for row_num in range(3):
        for col_num in range(3):
            self.bttn = Button(self, text = "    ", command = self.__change_button)
            self.bttn.grid(row = row_num + 1, column = col_num, sticky = W)

这就是我用self.bttn尝试的方式。 self .__ change_button只是将self.bttn中的文本切换为X或O. 这就是我用lambda尝试它的方式......

def __build_board(self):
    """ Creates tic-tac-toe board of 9 blank buttons. """
    for row_num in range(3):
        for col_num in range(3):
            bttn = Button(self, text = "    ", command = lambda: self.__change_button(bttn))
            bttn.grid(row = row_num + 1, column = col_num, sticky = W)

我想我理解为什么这些方法不起作用。看起来,我已经命令所有的按钮来改变最后一个按钮的文本,但是我不知道如何让他们按照我想要的方式改变他们自己的文本。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

这是一个棘手的问题......

原因是lambda将绑定到bttn 变量,而不是其值,因此所有按钮都会作用于最后一个按钮(因为将是循环之后变量的值。

要考虑到这一点:

x = 1
y = lambda : x
print(y()) # will print 1
x = 2
print(y()) # will print 2; lambda captures variables, not values

可能的解决方法是:

def __build_board(self):
    """ Creates tic-tac-toe board of 9 blank buttons. """
    for row_num in range(3):
        for col_num in range(3):
            def mkbutton():
                b = Button(self, text = "    ",
                           command = lambda: self.__change_button(b))
                return b
            bttn = mkbutton()
            bttn.grid(row = row_num + 1, column = col_num, sticky = W)

这样每个lambda都会绑定到自己独立的变量b

通常情况下,使用频繁模式可以更轻松地解决这类问题:

x = lambda y=y: ...

其中值y被复制为lambda的可选参数的默认值。

但是,在您的情况下,这种方法是不可能的,因为在评估lambda时,Button实例尚未存在(因此您无法将其作为默认参数值存储在lambda本身。)