【问题标题】:Call different methods in a for loop in python?在python的for循环中调用不同的方法?
【发布时间】:2020-07-27 21:07:45
【问题描述】:

我正在创建一个骰子生成器来学习 tkinter。这是我的第一次,所以请多多包涵。我也试图在一个类中制作所有东西,虽然我没有展示所有的代码,因为有很多。 最终目标是能够输入 'x' 数量的 'y' 类型骰子(4、6、8 面骰子等,并计算总数。 而不是单独为每种类型的骰子,我都在尝试使用 for 循环来简化它。

class DiceRoller:
    def __init__(self,root):

一开始的代码很多,但以下都在上面的方法中。

self.diceNames = ['D4','D6','D8','D10','D12','D20','D100']

    for x in range(len(self.diceNames)):

        #DEFINE TEXT FOR ENTRY BOX
        self.entryText = 'Roll '+self.diceNames[x]
        #CREATE ENTRY BOX
        self.entryBox = ttk.Entry(self.rollButtonFrame, 
                            width=self.entryWidth,
                            textvariable = self.textvariable).grid(row=self.rollRowStart+x,column=self.entryCol)
        
        #CREATE BUTTONS
        ttk.Button(self.rollButtonFrame, text = self.entryText,
                                         command = self.rollDice).grid(row=self.rollRowStart+x,column=self.rollCol)
        #CREATE LABELS FOR ANSWERS
        ttk.Label(self.rollButtonFrame, text = 'Total: 0').grid(row=self.rollRowStart+x,column=self.answerCol)
        #CREATE LABELS FOR DESCRIPTIONS
        descText = 'Number of '+self.diceNames[x]+' dice: '
        ttk.Label(self.rollButtonFrame, text = descText).grid(row=self.rollRowStart+x,column=self.descCol)
                                         command = self.rollDice).grid(row=self.rollRowStart+x,column=self.rollCol)

这会正确创建按钮、标签和输入框,(see here) 但是我不知道如何为每个骰子调用不同的方法。我也不知道这是否是最好的方法。 如何根据输入使每个按钮的行为有所不同,同时在 for 循环中创建按钮,如图所示?

我想如果我可以列出一个方法列表它会起作用,但我不知道它是否可能。

有没有更好的方法来做到这一点?提前致谢!

【问题讨论】:

  • 你有两个for x in range(len(self.diceNames)): 循环,这是故意的吗?
  • 我建议你改掉像for x in range(len(list))这样循环的习惯。相反,使用for item in list:
  • @Barmar 删除了多余的 for 循环,这是无意的。我通常用于列表中的项目,但由于某种原因我没有在这里。在这种特定情况下有很大的优势吗?
  • 它只是让代码更容易编写和理解,没有针对这种情况。
  • for x, item in enumerate(self.diceNames) 更好,因为您需要grid(...) 中的x。此外,您对所有条目的textvariable 选项使用相同的self.textvariable。如果其中一个条目被更新,它将使所有条目具有相同的内容。为每个条目使用单独的变量。

标签: python python-3.x object tkinter methods


【解决方案1】:

我会为此使用functools.partial

# This assumes self.rollDice takes the name of the target die as the first argument
(ttk.Button(self.rollButtonFrame, text=self.entryText, command=partial(self.rollDice, self.diceNames[x]))
    .grid(row=self.rollRowStart + x, column=self.rollCol))

partial 通过提前绑定一些参数来创建一个new 函数。再举一个例子说明这是如何工作的:

roll_d20 = partial(self.rollDice('D20'))
roll_d100 = partial(self.rollDice('D100'))
d20_result = roll_d20()  # This is the same as `d20_result = self.rollDice('D20')`
d100_result = roll_d100()  # This is the same as `d100_result = self.rollDice('D100')`

您可以使用 lambda 来完成同样的事情:

(ttk.Button(self.rollButtonFrame, text=self.entryText, command=lambda name=self.diceNames[x]: self.rollDice(name))
    .grid(row=self.rollRowStart + x, column=self.rollCol))

然而这个方法有一个共同的gotcha 与Python 的词法作用域规则相关,因此需要默认参数name=self.diceNames[x]。我个人更喜欢partial,因为我总是最终忘记了 lambdas 的这种行为。

【讨论】:

  • 貌似还有partialmethod方法。在这种情况下会更好吗?由于我不熟悉偏函数,我在哪里定义偏函数?我想我理解你的代码。例如,我实际上应该把 roll_d20=partial(...) 放在哪里?
  • partialmethod 也用于部分绑定函数参数,但不同之处在于它为self 参数留出了空间,因此生成的函数可以用作类方法。因此,例如,如果您希望像 self.roll_d20()myDiceRoller.roll_d20() 那样调用绑定函数,则可以使用它。在这种情况下,您似乎不需要该表单,因为您只关心设置按钮回调。
  • 要回答您的第二个问题,您可以将部分函数分配给一个变量,您可以将它们全部拉入listdict,或者您可以像在我的第一个例子。在您给出的示例中,除了个人喜好之外,这并不重要。但是,如果您想在其他地方重用这些绑定函数,那可能会影响您的决定。
猜你喜欢
  • 2019-02-07
  • 1970-01-01
  • 1970-01-01
  • 2020-10-14
  • 1970-01-01
  • 1970-01-01
  • 2019-06-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多