Python 如何从循环中创建的对象向函数传递特定于对象的值?

Python 如何从循环中创建的对象向函数传递特定于对象的值?,python,function,for-loop,tkinter,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): b

我已经深入地寻找了这个问题的解决方案,但是,由于对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
循环的
下面的某个地方有一个
网格(…)

命令
属性中引用的函数如下所示:

def some_function(letter):
    print(letter)
因此,我认识到我的代码存在两个问题:

  • 命令
    属性中的函数在运行代码时立即执行,因为我指定的是函数调用而不是函数名
  • 即使这是使用参数调用函数的正确方法,使用
    字母[i]
    也不会起作用,因为它会在单击时传递
    i
    的值,而不是执行
    for
    循环时传递的
    i
  • 因此,我的问题如下:

    def some_function(letter):
        print(letter)
    
  • 如何在
    命令
    属性中指定函数,并将参数传递给该函数
  • 如何将该参数指定为特定于该按钮的字母表中的字母,而不为每个字母明确定义按钮
  • 我很确定我可以用列表理解来解决第二个问题,也许是一本键等于字母,值等于按钮的字典,但是,我仍然不知道如何从按钮本身获取键值。

    是一种将一些参数传递给函数以生成新函数的实践,该函数可以在以后调用,但“记住”其早期参数。您可以使用此技术来传递状态

    def some_function(letter):
        def f():
            print(letter)
        return f
    
    ...
    
    command = some_function(alphabet[i])
    

    因此,一些函数(字母表[i])()
    会调用该函数,但仅使用一组括号就可以存储值供以后使用。

    您应该使用高阶函数(返回函数的函数)。为了演示,我将不使用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在周围保留
    某个函数生成器
    ,则可以将其内联:

    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
    

    注意,在“范围”(n)中,使用“<代码>”为“反模式”:当您可以简单地迭代迭代时,可以使用一些可迭代的[i] < /代码>。通常,您只需要实际值,因此您只需在某个_iterable

    command=lambda i=i:some_函数(字母表[i])中对x执行
    是惯用的解决方案。lambda生成一个函数,以后可以调用该函数,而不需要任何参数;带有默认值的参数
    i
    在定义lambda时捕获外部
    i
    的值,因此每个按钮都有其独特的值。这当然是惯用的方法,比我的答案更简洁。我可以建议你自己把这个作为答案吗?@jasonharper这个解决方案非常有效,谢谢。因此lambda为每个按钮生成一个函数,并为循环中的当前实例i生成一个函数。我到底做什么?这是lambda创建的函数的参数吗
    command=partial(print,alphabet[i])
    在不定义新的currying实用程序函数的情况下可以工作。严格来说,这不是currying,而是部分应用程序,但我经常混淆这两个功能。。。