Skip to content
Advertisement

Why do I need an asterisk and some random variable in these Python Tkinter functions for them to work properly?

In this basic Python Tkinter code, I’m trying to bind certain functions to trigger upon either a UI button press or a keyboard key press.

JavaScript

After a while of trial and error, it seems to work the way I want if I add an

JavaScript

in the declarations of:

JavaScript

and:

JavaScript

I get that one asterisk lets the function take an unknown number of arguments, and a double asterisk acts as a dictionary with key values.

My questions are:

  1. Why do I need a parameter in those functions at all?
  2. How does the variable “*randomVariable” get used, since it seems like I’m not actually using/ assigning anything to “randomVariable” anywhere within the function.
  3. Why does the function not work as intended without the asterisk before the variable?

Advertisement

Answer

Thanks for your question and for providing a runnable code snippet!

Conclusion (TL;DR)

  • You’re using the same function to handle two different kinds of events (button push, keystroke).
  • Because of this, your function has to handle different numbers of arguments
  • Using * gives your function this kind of flexibility

About the * (asterisk)

You correctly mentioned that you can use * in a function’s parameter list to accept any number of positional arguments. You probably have seen some function like this:

JavaScript

So now the question is “what is the difference between *args and args?” We can find the answer in the Python Language Reference:

An asterisk * denotes iterable unpacking. Its operand must be an iterable. The iterable is expanded into a sequence of items, which are included in the new tuple, list, or set, at the site of the unpacking.

The important word here is unpacking. Consider this example:

JavaScript
  • print(my_list) just prints the list, nothing special here
  • print(*my_list) actually does two things:
    1. Unpack the list
    2. Print the elements of the list one-by-one

In other words:

  • print(my_list) is equivalent to print([1, 2, 3])
  • print(*my_list) is equivalent to print(1, 2, 3) <– no square brackets

Finding out why you need the * in your code

Here, I’ll talk about the function changeTextEnter(), but the same applies to quitApp().

Basically, you’re using changeTextEnter() for two different things:

  • For a Button command: ttk.Button(..., command=changeTextEnter)
  • For a key binding: main_window.bind(..., changeTextEnter)

Pressing the “Enter” button and hitting the <Return> key both call changeTextEnter(), but in a different way (with different arguments).

You can use a debugger to observe this:

JavaScript

Another way is to print the value of args:

JavaScript
Action Value of args
Pushing the “Enter” button () (empty tuple)
Hitting the <Return> key (<KeyPress event ...>,)

You original code can’t handle the second case because the function doesn’t expect a positional argument:

JavaScript

Side notes

  • If you aren’t interested in the <KeyPress event> object, you can change your function definition to this: def changeTextEnter(*_). This will just “swallow” any positional arguments. The _ name is a convention for “I don’t care about this”
  • One of the most prominent functions using * is the built-in print() function. Did you ever wonder how these calls work?:
    • print()
    • print("Hello")
    • print("Cool number:", 42)
    • print("bla", "bla", end="")

Have a look at the function definition, it uses *:

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

Advertisement