Python Forum
Exit function from nested function based on user input
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Exit function from nested function based on user input
#1
Hello,

Currently making a chat bot that helps with adding some items to a database. I want a user to be able to start adding something to a database but be able to cancel at anytime.

Here's my current code:
def foo():
    def check(m):
        if m == "stop":
            return

    msg = input("Type a msg: ")
    check(msg)

    msg2 = input("Type another message: ")
    check(msg2)

    msg3 = input("Type a third message: ")

foo()
My thought process was to take the message and run it through a check that would exit out of the process however my check only exists out of the check() function and not the parent foo() function.

I found this thread which is a similar question to mine however I'm not sure exactly how to go about implementing that if it's the same solution.
Reply
#2
def foo():
    def check(m):
        if m == "stop":
            return 'exit'
 
    msg = input("Type a msg: ")
    if check(msg) == 'exit': 
        return
 
    msg2 = input("Type another message: ")
    if check(msg2) == 'exit' :
        return
 
    msg3 = input("Type a third message: ")
 
foo()
Reply
#3
It is difficult to answer your question because it is incomplete. Why do you need three strings? Why is the prompt different for each string? What happens if the user types "stop" for the first message? Based on "I want three strings that aren't used for anything" you could do something like this:
def foo():
    conversation = ("Type a msg: ", "Type another message: ", "Type a third message: ")

    def input_messages(prompts):
        for prompt in prompts:
            message = input(prompt)
            if message == 'stop':
                break
            yield message

    return [message for message in input_messages(conversation)]

print(foo())
If foo() needs to get three pieces of information to perform some kind of transaction I would be inclined to raise an exception if all three pieces are not provided.
class QueryException(Exception):
    '''Special exception type for my query'''
    def __init__(self, msg):
        super().__init__(f'"stop" entered when requesting "{msg}"')

def foo():
    conversation = ("Type a msg: ", "Type another message: ", "Type a third message: ")

    def input_message(prompt):
        message = input(prompt)
        if message == 'stop':
            raise QueryException(prompt)
        return message

    msg1 = input_message("Type a msg: ")
    msg2 = input_message("Type another message: ")
    msg3 = input_message("Type a third message: ")

    return msg1, msg2, msg3

print(foo())
How the situation should handled depends on what you aren't telling ups more than what you have told us.
Reply
#4
(Oct-05-2021, 08:12 PM)jefsummers Wrote:
def foo():
    def check(m):
        if m == "stop":
            return 'exit'
 
    msg = input("Type a msg: ")
    if check(msg) == 'exit': 
        return
 
    msg2 = input("Type another message: ")
    if check(msg2) == 'exit' :
        return
 
    msg3 = input("Type a third message: ")
 
foo()

Thanks for this, jefsummers. I did have this thought at one point but wasn't sure if it would be the smartest way to call the function after each message. I'll give this an attempt and see how it works.

(Oct-05-2021, 08:53 PM)deanhystad Wrote: It is difficult to answer your question because it is incomplete. Why do you need three strings? Why is the prompt different for each string? What happens if the user types "stop" for the first message? Based on "I want three strings that aren't used for anything" you could do something like this:

<snip>

How the situation should handled depends on what you aren't telling ups more than what you have told us.

Thanks for the reply, deanhystad. Admittedly, I did leave some information out and these are valid questions so I appreciate you asking them. A little more background for the project is it's a Discord bot using Discordpy so most of the interaction will take place through message strings. The bot will send the user a private message asking for some information about their entry. In this case, the bot will be creating a SQL database entry for a meeting. The different strings represent different items that pertain to the meeting information such as name, location, time, etc. To make things simpler, I'm asking for each item in a different message string to avoid having the user remember and follow a strict input format. Once I have all the strings in variables, I then add those variables to the correct fields in the database record.

Regarding the "stop" escape, my thought is to be able to have the user have a way to stop the process in case they decide they don't want to add the meeting halfway through the steps. So all previously entered information is just dumped and no record is created.

Hopefully this sheds a little more light on the project!
Reply
#5
It seem nobody wants to mention the elephant in the room - there is absolutely no need of nested function.. Remember Zen of Python - Flat is better than nested. And actually there is no need of "check" function at all. However you need to refactor your code structure.

def get_meeting_info():
    prompts = ('name', 'location', 'time')
    meeting = {}
    for prompt in prompts:
        user_input = input(f'Please, enter {prompt}:')
        if user_input == 'exit':
            return
        else:
            meeting[prompt] = user_input
    return meeting

meeting = get_meeting_info()
print(meeting)
or I would go with namedtuple

from collections import namedtuple

Meeting = namedtuple('Meeting', 'name location time')

def get_meeting_info():
    meeting = {}
    for prompt in Meeting._fields:
        user_input = input(f'Please, enter {prompt}:')
        if user_input == 'exit':
            return
        else:
            meeting[prompt] = user_input
    return Meeting(**meeting)

meeting = get_meeting_info()
print(meeting)
Of course this can be done slightly differently, e.g. raise error instead or return None, use class/OOP, etc., but you get the idea.
Turtle likes this post
If you can't explain it to a six year old, you don't understand it yourself, Albert Einstein
How to Ask Questions The Smart Way: link and another link
Create MCV example
Debug small programs

Reply
#6
Thanks, buran. This was a helpful response and a great way to accomplish my goal. I've incorporated your first example for now and will see how it works with my Discordpy bot.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Problem with input after function luilong 10 602 Dec-04-2021, 12:16 AM
Last Post: luilong
  Matplotlib - close multple plots with user input Positron79 0 77 Dec-01-2021, 05:26 PM
Last Post: Positron79
Star I'm getting syntax error while using input function in def. yecktmpmbyrv 1 354 Oct-06-2021, 09:39 AM
Last Post: menator01
  Unable to access the user input value given to daterangepicker klllmmm 1 832 May-26-2021, 09:16 PM
Last Post: nilamo
  Input function cutting off commands at spaces. throwaway34 3 740 May-12-2021, 06:40 AM
Last Post: throwaway34
Question Stopping a parent function from a nested function? wallgraffiti 1 906 May-02-2021, 12:21 PM
Last Post: Gribouillis
  Problem restricting user input in my rock paper scissors game ashergreen 6 1,450 Mar-25-2021, 03:54 AM
Last Post: deanhystad
  LinkedList by User Input SantiagoPB 5 1,522 Mar-03-2021, 09:54 PM
Last Post: deanhystad
Question exiting the outer function from the inner function banidjamali 3 1,089 Feb-27-2021, 09:47 AM
Last Post: banidjamali
  User input/picking from a list AnunnakiKungFu 2 904 Feb-27-2021, 12:10 AM
Last Post: BashBedlam

Forum Jump:

User Panel Messages

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