在这段基本的Python Tkinter代码中,我试图将某些函数绑定到按下UI按钮或按下键盘键时触发.

import tkinter as tk
from tkinter import ttk

main_window = tk.Tk()
main_window.title('Test UI')

# Change text with "Enter" then flush
def changeTextEnter():
    text_label.configure(text=entry_bar.get())
    entry_bar.delete(0, tk.END)

# Close program key function
def quitApp():
    main_window.destroy()

# Enter Button
enter_button = ttk.Button(text='Enter', command=changeTextEnter)
enter_button.grid(row=0, column=0)

# Entry bar
entry_bar = ttk.Entry(width=30)
entry_bar.grid(row=0, column=1)

# Quit Button
quit_button = ttk.Button(text='Quit', command=main_window.destroy)
quit_button.grid(row=0, column=2)

# Text label
text_label = ttk.Label(text='TEST TEXT GOES HERE')
text_label.grid(row=1, column=0, columnspan=2)

# Bind enter key
main_window.bind('<Return>', changeTextEnter)
# Bind quit key
main_window.bind('<Escape>', quitApp)

main_window.mainloop()

经过一段时间的反复试验,如果我添加一个

*randomVariable

在下列国家的声明中:

def changeTextEnter(*randomVariable):

以及:

def quitApp(*randomVariable):

我知道,一个星号允许函数接受未知数量的参数,而双星号则充当具有键值的字典.

我的问题是:

  1. 为什么我在这些函数中需要一个参数呢?
  2. 既然我实际上没有在函数中的任何地方使用/赋值任何东西,那么如何使用变量"*随机变量"呢?
  3. 为什么在变量前没有星号的情况下,函数不能正常工作?

推荐答案

感谢您的提问并提供了可运行的代码片段!

结论(TL;DR)

  • 您正在使用相同的函数来处理两种不同类型的事件(按钮按下、击键).
  • 因此,您的函数必须处理不同数量的参数
  • 使用*为您的函数提供了这种灵活性

About the * (asterisk)

您正确地提到,可以在函数的参数列表中使用*来接受任意数量的位置参数.您可能见过这样的一些函数:

def my_func(*args, **kwargs):
    ...

所以现在的问题是"*argsargs有什么区别?"我们可以在Python Language Reference条中找到答案:

星号*表示可迭代解包.其操作数必须是可迭代的.可迭代项被展开为一系列项,这些项在解包位置被包括在新的元组、列表或集合中.

这里最重要的词是unpacking.请考虑以下示例:

>>> my_list = [1, 2, 3]
>>> print(my_list)
[1, 2, 3]
>>> print(*my_list)
1 2 3
  • print(my_list)只是打印列表,这里没有什么特别的
  • print(*my_list)实际上做了两件事:
    1. Unpack the list
    2. 逐个打印列表中的elements

换句话说:

  • print(my_list)相当于print([1, 2, 3])
  • print(*my_list)相当于print(1, 2, 3) <-- no square brackets

Finding out why you need the * in your code

在这里,我将讨论函数changeTextEnter(),但同样适用于quitApp().

基本上,你用changeTextEnter()做了两件不同的事情:

  • 对于按钮命令:ttk.Button(..., command=changeTextEnter)
  • 对于密钥绑定:main_window.bind(..., changeTextEnter)

按"Enter"键和按<Return>键都是changeTextEnter(),但in a different way(参数不同).

您可以使用调试器来观察:

def changeTextEnter(*args):
    text_label.configure(text=entry_bar.get())  # <-- breakpoint here
    entry_bar.delete(0, tk.END)

另一种方法是打印args的值:

def changeTextEnter(*args):

    # DEBUG
    print(args)

    text_label.configure(text=entry_bar.get())
    entry_bar.delete(0, tk.END)
Action Value of args
Pushing the "Enter" button () (empty tuple)
Hitting the <Return> key (<KeyPress event ...>,)

原始代码无法处理第二种情况,因为该函数不需要位置参数:

TypeError: changeTextEnter() takes 0 positional arguments but 1 was given

附注

  • 如果您对<KeyPress event>对象不感兴趣,可以将函数定义更改为:def changeTextEnter(*_).这只会"吞下"任何立场上的争论._这个名字是"我不在乎这个"的习惯用法
  • 使用*最突出的功能之一是内置的print()功能.你有没有想过这些电话是如何工作的?
    • print()
    • print("Hello")
    • print("Cool number:", 42)
    • print("bla", "bla", end="")

看一下函数定义,它使用*:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

Python相关问答推荐

如何在具有重复数据的pandas中对groupby进行总和,同时保留其他列

删除任何仅包含字符(或不包含其他数字值的邮政编码)的观察

"使用odbc_connect(raw)连接字符串登录失败;可用于pyodbc"

对所有子图应用相同的轴格式

OR—Tools CP SAT条件约束

如何创建一个缓冲区周围的一行与manim?

在pandas中使用group_by,但有条件

如果满足某些条件,则用另一个数据帧列中的值填充空数据帧或数组

使用groupby方法移除公共子字符串

如何找出Pandas 图中的连续空值(NaN)?

基于Scipy插值法的三次样条系数

循环浏览每个客户记录,以获取他们来自的第一个/最后一个渠道

关于两个表达式的区别

如何按row_id/row_number过滤数据帧

将链中的矩阵乘法应用于多组值

如何获得满足掩码条件的第一行的索引?

极柱内丢失类型信息""

Polars时间戳同步延迟计算

函数()参数';代码';必须是代码而不是字符串

将Pandas DataFrame中的列名的长文本打断/换行为_STRING输出?