Python Forum
Whys is asterisk and random variable necessary in these functions?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Whys is asterisk and random variable necessary in these functions?
#1
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.

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()
After a while of trial and error, it seems to work the way I want if I add an *randomVariable in the declarations of def changeTextEnter(*randomVariable): and def quitApp(*randomVariable):
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?
Reply
#2
When you bind the callback to a key, it receives a KeyPress event parameter every time the key is pressed. On the other hand, a function bound to a Button does not receive a parameter when the button is pressed. So if you want to bind the callbacks both to a key and to a Button, you need to give them a variable number of arguments. Try adding a print() in the functions to see what it does
# Change text with "Enter" then flush
def changeTextEnter(*args):
    print('changeTextEnter:', args)
    text_label.configure(text=entry_bar.get())
    entry_bar.delete(0, tk.END)
 
# Close program key function
def quitApp(*args):
    print('quit:', args)
    main_window.destroy()
Output:
changeTextEnter: (<KeyPress event keysym=Return keycode=36 char='\r' x=89 y=14>,) changeTextEnter: () quit: (<KeyPress event keysym=Escape keycode=9 char='\x1b' x=181 y=14>,)
rrowhe4d likes this post
Reply
#3
The function signature is misleading. Don't use the asterisk, if you expect a static number of arguments. The callback sends one argument, which is the event itself. You should change the callbacks (example taken form Gribouillis).

# Change text with "Enter" then flush
def changeTextEnter(event):
    print('changeTextEnter:', event)
    text_label.configure(text=entry_bar.get())
    entry_bar.delete(0, tk.END)
  
# Close program key function
def quitApp(event):
    print('quit:', event)
    main_window.destroy()
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#4
You should read the documentation. This describes what arguments are passed to the bound event callback.

https://docs.python.org/3/library/tkinte...d-events-1

In your example you are binding a key code (<Return>, <Escape>), so the argument passed to your functions is an event that contains the key that was pressed.

This is a little program that displays the event in an Entry widget. You can select the entry and type and it works like normal, but it you press <Return> or <Escape> an text is replaced by the event info.
import tkinter as tk

class MainWindow(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.title("Test UI")
        self.bind("<Return>", self.keypress)
        self.bind("<Escape>", self.keypress)
        self.text = tk.StringVar(self, "")
        tk.Entry(self, textvariable=self.text, width=80).pack(padx=20, pady=20)

    def keypress(self, event):
        self.text.set(str(event))


MainWindow().mainloop()
If you don't use the event you can ignore it. The linter in my IDE does not like functions arguments that aren't used in the function, so I use a place holder instead of an argument.
   def keypress(self, _):
        self.text.set("something happened")
The "_" in the function declaration tells the reader that one argument is passed, but not used by the function. Unfortunately you can only use one "_". If there are multiple arguments to ignore I might do this:
def keypress(self, *_):
But I cannot do this:
def keypress(self, *_, **_):
I can also use a lambda expressing to remove or replace the event argument.
self.bind("<Return>", lambda event:self.keypress("Return was pressed")
self.bind("<Escape>", lambda event:self.keypress("Escape was pressed")

    def keypress(self, msg):
        self.text.set(msg)
Here the lambda expression consumes the "event" argument and passes along a different argument.
Reply
#5
(Aug-04-2022, 07:10 PM)deanhystad Wrote: But I cannot do this:

1 def keypress(self, *_, **_):

You should read the error messages:
Error:
SyntaxError: duplicate argument '_' in function definition
Fix:

class Test:
    def keypress(self, *args, **kwargs):
        ...
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#6
You could also do
def changeTextEnter(event=None):
    ...
This allows zero or one argument.
buran likes this post
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Calling functions by making part of their name with variable crouzilles 4 849 Nov-02-2023, 12:25 PM
Last Post: noisefloor
  trying to input a variable using random.choice python63 9 3,653 Aug-13-2020, 05:37 PM
Last Post: python63
  Help removing asterisk item in a nested list. bmcguire 3 2,611 Apr-06-2020, 02:35 PM
Last Post: snippsat
  append one random intergar variable Coastal 5 2,704 Dec-18-2019, 09:18 PM
Last Post: ichabod801
  random variable function? Novice_fanatic 4 2,780 Oct-08-2019, 01:22 PM
Last Post: jefsummers
  Guidance in Creating random output for a variable. Livne_ye 1 2,520 May-04-2019, 01:18 PM
Last Post: Yoriz
  How do you make functions that take a variable that is not defined? magic 6 4,437 Sep-24-2018, 01:30 PM
Last Post: gruntfutuk
  multiprocess passing multiple arguments double asterisk pic8690 1 5,291 Oct-23-2016, 08:51 AM
Last Post: Skaperen

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020