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
  difference between forms of input a list to function akbarza 6 1,022 Feb-21-2024, 08:02 PM
Last Post: bterwijn
  The function of double underscore back and front in a class function name? Pedroski55 9 645 Feb-19-2024, 03:51 PM
Last Post: deanhystad
  nested function return MHGhonaim 2 608 Oct-02-2023, 09:21 AM
Last Post: deanhystad
  WHILE LOOP NOT RETURNING USER INPUT AFTER ZerroDivisionError! HELP! ayodele_martins1 7 1,053 Oct-01-2023, 07:36 PM
Last Post: ayodele_martins1
  restrict user input to numerical values MCL169 2 907 Apr-08-2023, 05:40 PM
Last Post: MCL169
  function return boolean based on GPIO pin reading caslor 2 1,171 Feb-04-2023, 12:30 PM
Last Post: caslor
  user input values into list of lists tauros73 3 1,064 Dec-29-2022, 05:54 PM
Last Post: deanhystad
Information How to take url in telegram bot user input and put it as an argument in a function? askfriends 0 1,076 Dec-25-2022, 03:00 PM
Last Post: askfriends
Question Take user input and split files using 7z in python askfriends 2 1,084 Dec-11-2022, 07:39 PM
Last Post: snippsat
  python difference between sys.exit and exit() mg24 1 1,823 Nov-12-2022, 01:37 PM
Last Post: deanhystad

Forum Jump:

User Panel Messages

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