1

我正在尝试使用 Python 对象作为 Tk 画布项目的包装器。例如:

class PlayingCard:
    def __init__(self, item):
        self.item = item

aceOfSpades = PlayingCard(canvas.create_image((coordinates), image = PhotoImage(aceofspades.gif)))
print aceOfSpades.item
>>> <canvas item id>

这样,如果我需要操作一个画布项,我可以通过一个对象来引用它:

aceOfSpades.item.move(dx, dy)

所以,问题是我有很多对象(实际上是 52 个),每个对象都有自己的 self.item 引用画布图像项,我想遍历对象并为其画布项创建事件绑定如果对象满足一定条件。这是我的解决方案(伪 pycode):

def event_handler(card):
    card.attribute = updated_value

for card in [list of card objects]:
    if card.attribute == test_condition:
        canvas.tag_bind(
            card.item, #this is the item id stored in the PlayingCard.item variable
            <Event Sequence>,
            lambda x: event_handler(card)
            )

问题是,在迭代完成后,所有事件绑定都将相同的参数传递给事件处理程序。

换句话说,我想将卡片对象作为参数传递给事件处理程序,这样当卡片的 object.item 画布项对应的事件发生时,事件处理程序就可以访问卡片对象。但是,此代码所做的是将相同的参数(即卡片对象)传递给事件处理程序,而不管画布项如何。在代码中,这意味着如果事件序列是单击,则单击任何卡片画布项都会调用该函数event_handler(<last card object in iteration>),而我希望单击画布项来调用event_handler(<corresponding card object>).

我说得有道理吗?我不明白为什么这种方法不能产生我想要的结果。

4

1 回答 1

2

在函数中使用具有默认值的可选关键字参数lambda。默认值在定义 lambda 时绑定到 lambda,因此在lambda,card中是一个局部变量,每个 lambda 将具有不同的默认值card

如果没有默认值,则在lambda调用函数时,将card使用LEGB 规则查找 的值——在本地范围内查找,然后是扩展范围,然后是全局范围,然后是内置范围。由于它没有在本地范围内定义,它会在扩展范围(包含 的范围for card in [list of cards])中找到它。在那里,card引用最后一张卡片list of cards。这就是为什么所有点击事件都会影响相同的card.

for card in [list of card objects]:
    if card.attribute == test_condition:
        canvas.tag_bind(
            card.item, #this is the item id stored in the PlayingCard.item variable
            <Event Sequence>,
            lambda x, card = card: event_handler(card)
            )
于 2012-11-28T18:07:49.733 回答