Reputation: 208
I want the f2
to end not itself, but rather completely the parent function f1
while being executed, with a command. I know that return
is used to end a function, but it doesn't work here at a sub-level.
So my question is what are these commands (or sets of lines) and how can I implement them in my code? Example snippet here:
def f1:
do something
def f2:
do something
# need a command here
f2()
do something
f1()
It is noteworthy that the code shall be running a while True:
loop at the time of discontinuing function.
I used tkinter library button to execute a sub function (which means that the sub-function cannot return a value to a variable), but am unable to end the main function from within that set of code.
here is the tkinter code:
tk.Button(root, text='Click me', command=f2)
Here command = f2
executes f2() when tk.Button is pressed, but the value is not returned anywhere. Probably a local or global variable flag can be used inside f2...
Way to quit the most outer function from an inner function? -- This doesn't solve my problem since I must not define a class or error in my code. Is there another method to do so?
EDIT: I think I am unable to convey the problem I am facing properly.
At this point it is just a mess 😓
import tkinter as tk
from tkinter import messagebox as msgbox
from PIL import ImageTk
lst = []
cnt = 0
black = '#%02x%02x%02x' % (50, 50, 50)
white = '#%02x%02x%02x' % (240, 240, 240)
red = '#%02x%02x%02x' % (255, 80, 80)
yellow = '#%02x%02x%02x' % (255, 220, 80)
green = '#%02x%02x%02x' % (120, 255, 150)
blue = '#%02x%02x%02x' % (0, 220, 240)
purple = '#%02x%02x%02x' % (120, 80, 255)
window_icon = 'icon.jpg'
######## Non-iterables ########
def set_root():
global root
root = tk.Tk() # create only one instance for Tk()
root.withdraw()
def root_attributes():
root.iconphoto(True, ImageTk.PhotoImage(file=window_icon))
root.attributes("-topmost", True)
#################################
def root_win():
global cnt
cnt += 1
set_root()
if cnt == 1:
root_attributes()
global lst
root.deiconify()
w_root = 500
h_root = 320
pos_right = round(root.winfo_screenwidth() / 2 - w_root / 2)
pos_down = round(root.winfo_screenheight() / 2 - h_root / 2)
root.title('Enter the values')
root.resizable(width=False, height=False)
root.geometry('{}x{}+{}+{}'.format(w_root, h_root, pos_right, pos_down))
root.configure(bg=white)
tk.Label(root, text='Enter the values', font=('bold', 30), bg=white, fg=black).place(x=70, y=20)
tk.Label(root, text='Enter width here:', font=('bold', 15), bg=white, fg=black).place(x=50, y=100)
tk.Label(root, text='Enter height here:', font=('bold', 15), bg=white, fg=black).place(x=50, y=140)
val1 = tk.Entry(root, bd=0, font=('bold', 15))
val1.place(x=280, y=102, width=170)
val2 = tk.Entry(root, bd=0, font=('bold', 15))
val2.place(x=280, y=142, width=170)
lbl = tk.Label(root, text='Min: 5, Max: 100', font=('bold', 15), bg=white, fg=purple)
lbl.place(x=170, y=260)
def enter():
global lst
if val1.get() == '' and val2.get() == '':
lbl.config(text='Please enter width and height!')
lbl.place(x=80, y=260)
elif val1.get() == '':
lbl.config(text='Please enter a width!')
lbl.place(x=145, y=260)
elif val2.get() == '':
lbl.config(text='Please enter a height!')
lbl.place(x=140, y=260)
else:
wid, hit = 0, 0
try:
wid = round(float(val1.get()))
hit = round(float(val2.get()))
except:
lbl.config(text='Please enter value from 5 to 100!')
lbl.place(x=70, y=260)
if not 5 <= wid <= 100 or not 5 <= hit <= 100:
lbl.config(text='Please enter value from 5 to 100!')
lbl.place(x=70, y=260)
else:
lbl.config(text='INPUT ACCEPTED !!!!')
lbl.place(x=130, y=260)
lst = [wid, hit]
root.deiconify()
def clr():
val1.delete(0, 'end')
val2.delete(0, 'end')
lbl.config(text='Min: 5, Max: 100')
lbl.place(x=170, y=260)
enter = tk.Button(root, text='Enter', font=('bold', 15), bd=0, fg=black, bg=green, activebackground=blue,
command=enter)
enter.place(x=300, y=200)
enter.configure(width=8)
clear = tk.Button(root, text='Clear', font=('bold', 15), bd=0, fg=black, bg=red, activebackground=yellow,
command=clr)
clear.place(x=100, y=200)
clear.configure(width=8)
root.mainloop()
# set_root()
root_win()
if not lst:
action = msgbox.askyesno(title='Exit prompt', message='Are you sure you want to exit?\nYes: Exit\nNo: Restart\n',
icon='warning', default='no')
if not action: # Returns True or False
root_win()
else:
quit()
print(lst)
I expect the code to form a GUI for input of 2 values, and if the values do not meet requirements, it should continue GUI interface untill requirements are met. Also, if user closes the GUI in between, there should be a confirm dialogue box to exit or restart "global function". Thing is, root.destroy()
help exit global function but some lines are not iterable, like iconphoto. It gives an error.
Upvotes: 2
Views: 293
Reputation: 208
Never mind folks, I found the solution I needed:
import tkinter as tk
from tkinter import messagebox as msgbox
from PIL import ImageTk
lst = []
black = '#%02x%02x%02x' % (50, 50, 50)
white = '#%02x%02x%02x' % (240, 240, 240)
red = '#%02x%02x%02x' % (255, 80, 80)
yellow = '#%02x%02x%02x' % (255, 220, 80)
green = '#%02x%02x%02x' % (120, 255, 150)
blue = '#%02x%02x%02x' % (0, 220, 240)
purple = '#%02x%02x%02x' % (120, 80, 255)
window_icon = 'icon.jpg'
def root_win():
global lst
root = tk.Tk() # create only one instance for Tk()
w_root = 500
h_root = 320
pos_right = round(root.winfo_screenwidth() / 2 - w_root / 2)
pos_down = round(root.winfo_screenheight() / 2 - h_root / 2)
root.iconphoto(True, ImageTk.PhotoImage(file=window_icon))
root.attributes("-topmost", True)
root.title('Enter the values')
root.resizable(width=False, height=False)
root.geometry('{}x{}+{}+{}'.format(w_root, h_root, pos_right, pos_down))
root.configure(bg=white)
tk.Label(root, text='Enter the values', font=('bold', 30), bg=white, fg=black).place(x=70, y=20)
tk.Label(root, text='Enter width here:', font=('bold', 15), bg=white, fg=black).place(x=50, y=100)
tk.Label(root, text='Enter height here:', font=('bold', 15), bg=white, fg=black).place(x=50, y=140)
val1 = tk.Entry(root, bd=0, font=('bold', 15))
val1.place(x=280, y=102, width=170)
val2 = tk.Entry(root, bd=0, font=('bold', 15))
val2.place(x=280, y=142, width=170)
lbl = tk.Label(root, text='Min: 5, Max: 100', font=('bold', 15), bg=white, fg=purple)
lbl.place(x=170, y=260)
def enter():
global lst
if val1.get() == '' and val2.get() == '':
lbl.config(text='Please enter width and height!')
lbl.place(x=80, y=260)
elif val1.get() == '':
lbl.config(text='Please enter a width!')
lbl.place(x=145, y=260)
elif val2.get() == '':
lbl.config(text='Please enter a height!')
lbl.place(x=140, y=260)
else:
wid, hit = 0, 0
try:
wid = round(float(val1.get()))
hit = round(float(val2.get()))
except:
pass
if not 5 <= wid <= 100 or not 5 <= hit <= 100:
lbl.config(text='Please enter value from 5 to 100!')
lbl.place(x=70, y=260)
else:
# lbl.config(text='INPUT ACCEPTED !!!!')
# lbl.place(x=130, y=260)
lst = [wid, hit]
root.destroy()
def clr():
val1.delete(0, 'end')
val2.delete(0, 'end')
lbl.config(text='Min: 5, Max: 100')
lbl.place(x=170, y=260)
def closing():
if msgbox.askyesno(title='Exit prompt', message='Are you sure you want to exit?',
icon='warning', default='no'):
root.destroy()
print('Have a nice day!')
quit()
ext = tk.Button(root, text='Cancel', font=('bold', 15), bd=0, fg=black, bg=red, activebackground=yellow,
command=closing)
ext.place(x=60, y=200)
ext.configure(width=7)
clear = tk.Button(root, text='Clear', font=('bold', 15), bd=0, fg=black, bg=yellow, activebackground=red,
command=clr)
clear.place(x=200, y=200)
clear.configure(width=7)
enter = tk.Button(root, text='Enter', font=('bold', 15), bd=0, fg=black, bg=green, activebackground=blue,
command=enter)
enter.place(x=340, y=200)
enter.configure(width=7)
root.protocol("WM_DELETE_WINDOW", closing)
root.mainloop()
root_win()
print(lst)
The key was this line set:
def closing():
if msgbox.askyesno(title='Exit prompt', message='Are you sure you want to exit?',
icon='warning', default='no'):
root.destroy()
print('Have a nice day!')
quit()
Upvotes: 1
Reputation: 69
There are a couple of ways I would tackle this - and it depends on the complexity of the problem.
Simple calculations can be achieved like so:
def foo(*args,**kwargs):
bar = lambda ... : ...
do something
final = bar(x)
return final
foo()
If the function has added complexity, it makes sense to use a class (or classes depending on the complexity) like so:
class thing_youre_classifying(object):
def __init__(self):
...
def __any_other_boilerplate_methods_needed__(self):
...
def foo(self):
do something
def bar(self):
do something
x = f1()
thing = thing_youre_classifying()
thing.bar()
This is mostly for readability (and probably other important things).
Or, if foo
and bar
are wildly different (say in foo
you're parsing a database and bar
you're doing statistical analysis), you'll want to check out class inheritance.
class foo(object):
def __init__(self, *args, **kwargs)
initialize each instance of foo with args and kwargs
class bar(foo):
def __init__(self):
foo.__init__(self, *args, **kwargs)
instance = bar()
instance.foo()
I want to point out that I did not include *args
or **kwargs
in bar
's boilerplate init function. That could also underline the difference between foo
and bar
.
The last thing that comes to mind is using decorators.
"One of the main uses of decorators is that they allow us to add functionality to existing functions, without modifying the original function. This capability extends to class methods as well." -anonymous professor
def foo():
def modifier():
return foo.method_you_want()
return modifier
@foo
def bar():
do something
My gut tells me decorators are going to be the cleanest way to do this.
Upvotes: 0
Reputation: 11611
One way can be to raise an exception from f2
, then catch that exception in f1
and then return early:
def f1():
# do something
def f2():
print('Hello')
# need a command here
raise StopIteration()
print('World!')
try:
f2()
except StopIteration:
return
print('World')
# do something
f1()
Outputs:
Hello
I'm not exactly sure where you're defining the while
loop mentioned. If it's outside of f1
entirely, I'd delegate handling of the error within such a loop itself - or you could even wrap the while
loop with a try-except if absolutely needed. If you go with latter approach, I'd suggest creating a custom exception class and then catching that specific error; this way you can be sure you're handling only the error that you've raised from within f2
for example.
Upvotes: 2