如何将特定于对象的值传递给循环中创建的对象的函数?

时间:2018-04-05 02:41:10

标签: python function for-loop tkinter

我已经深入搜索了这个问题的解决方案,但是,对于Python和tkinter来说,很难找到解决问题的方法,而这些问题主要是您不熟悉的语言。我希望这不是一个重复的问题。

假设我在tkinter中创建了一系列按钮,每个按钮将依次显示字母表中的字母,如下所示:

from string import ascii_uppercase as alphabet
from tkinter import Button
blockLetterButtons = []
for i in range(0,26):
    blockLetterButtons.append(Button(competitorSelectionFrame, 
    text=alphabet[i], command=some_function(alphabet[i])))

for循环中的某个位置下方的所有内容都是.grid(...)

command属性中引用的函数如下:

def some_function(letter):
    print(letter)

所以我认识到我的代码有两个问题:

  1. command属性中的函数在运行代码时立即执行,因为我指定的是函数调用而不是函数名。
  2. 即使这是使用参数调用函数的正确方法,使用alphabet[i]也不会起作用,因为它会在点击时传递i的任何值,而不是执行i循环时for无论如何。
  3. 所以我的问题如下:

    1. 如何在command属性中指定函数并使用参数传递给该函数?
    2. 如何在不为每个字母明确定义按钮的情况下,将该参数指定为该按钮特定字母的字母?
    3. 我相当肯定我可以使用列表解析来解决第二个问题,也许是一个字母,其键等于字母,值等于按钮,但是我仍然不知道如何获得来自按钮的键值。

2 个答案:

答案 0 :(得分:0)

Currying是将一些参数传递给函数以生成一个新函数的做法,该函数可以在以后调用,但是会记住"它早先的论点。您可以使用此技术来传递状态。

array

所以def some_function(letter): def f(): print(letter) return f ... command = some_function(alphabet[i]) 会调用该函数,但只使用一组括号只是为了以后存储该值。

答案 1 :(得分:0)

您应该使用更高阶函数(返回函数的函数)。为了演示,我不会使用tkinter,但原理是相同的:

In [25]: def some_func_maker(letter):
    ...:     def some_func():
    ...:         print(letter)
    ...:     return some_func
    ...:

In [26]: buttons = []

In [27]: from string import ascii_uppercase as alphabet

In [28]: for i in range(26):
    ...:     buttons.append(some_func_maker(alphabet[i]))
    ...:

In [29]: for b in buttons: b()
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z

注意,如果您不想使用lambda保持some_func_maker,则可以内联:

In [37]: buttons = []
    ...: for c in alphabet:
    ...:     buttons.append(
    ...:         (lambda x: lambda: some_function(x))(c)
    ...:     )
    ...:

In [38]: for b in buttons: b()
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z

一个常见的伎俩是,使用lambda的默认参数并不那么冗长,但是,我认为这更加晦涩,尽管在Python中很常见:

In [43]: buttons = []
    ...: for c in alphabet:
    ...:     buttons.append(
    ...:         lambda x=c: some_function(x)
    ...:     )
    ...:

In [44]: buttons[0]()
A

In [45]: buttons[1]()
B

In [46]: buttons[-1]()
Z

另请注意,当您可以简单地迭代迭代时,可以考虑使用for i in range(n): some_iterable[i]的反模式。通常,您只需要实际值,因此您只需for x in some_iterable