stop recursion from 'deepest' reccursion in python 3 - function

I am trying to stop errors happening in my code when an invalid input is entered by the user. Here is a simplified example that demonstrates my problem.
def foo():
try:
a = int(input('1,2,3 or 4'))
except (ValueError, UnboundLocalError):
print ('invalid input')
print ('')
print ('Try 1,2,3 or 4')
foo()
if a == 3:
print ('done')
When I input an intiger the function runs perfectly. When I input a string into the a = int(input()) part it runs foo() again. However, when I then input 3 it prints done' but goes on to give as many ValueError's as times I made an incorrect inputs followed by an UnboundLocalError.I think this is because im running the function over and over inside itself so it then has to 'come out' of this. Is there a better way to re run the function without using recursion? I am new to programming.

Put the last two lines inside the try..except block.
def foo():
try:
a = int(input('1,2,3 or 4'))
if a == 3:
print ('done')
except (ValueError, UnboundLocalError):
print ('invalid input')
print ('')
print ('Try 1,2,3 or 4')
foo()
And you'd better use while loop to avoid increasing the recursion depth:
def foo():
while True:
try:
a = int(input('1,2,3 or 4'))
if a == 3:
print ('done')
break
except (ValueError, UnboundLocalError):
print ('invalid input')
print ('')
print ('Try 1,2,3 or 4')

The issue you're having is that you don't exit the function when you recurse in your exception handler. One solution would be to return foo() when you recurse, but this is still going to be awkward (Python doesn't do tail call optimization, so this will build up a big stack of calls waiting to be returned from, if you keep entering invalid values). A better solution is to use a loop:
a=None:
while a is None:
try:
a = int(input('1,2,3 or 4'))
except ValueError:
print ('invalid input')
print ('')
print ('Try 1,2,3 or 4')
# you could do more validation here, and set `a` back to `None` if it is invalid
if a == 3:
print("done")
The while loop will keep on asking for input until an acceptable value is provided by the user. No recursion is needed.

Pull the try and except block outside of your recursive function This way you don't enter multiple different trys. Then when your recursive function throws an error, it'll go all the way back up it that one any only try block that you have.

Related

How to create a function return nothing in Julia?

When I create a function in Julia, I print something in the function and don't return anything. But the result is the function print what I want and also return 'nothing'. What can I do to make the function just print what I want without return 'nothing'?
There is always a return value from a function. When there is no explicit return statement, the value of the last expression in the function is returned. This is probably what you're seeing here: if the print statement is the last line of your function, since print's return value is nothing, that becomes the return value of your function too.
If you just don't want the nothing shown at the end of the output,then please paste the code you're using that leads to this behaviour, and we can figure out how to suppress this output of nothing from appearing.
Some additional comment to the answer by #sundar.
In other words nothing is the value meaning that the function did not return anything. Consider this Julia session:
julia> function f()
end
f (generic function with 1 method)
julia> res = f()
julia> dump(res)
Nothing nothing
By default nothing is displayed as an empty output:
julia> res
This however changes when res ends up interpolated in another string:
julia> "$res"
"nothing"
For cases like above consider using something such as:
julia> "$(something(res,""))"
""

Python 3.9.x | Cannot 'return' variable with user entry validation

I'm having problems getting my code to 'return' one of the option strings correctly.
If the user inputs one of the string options correctly the first time through, then the 'return' value comes back perfectly fine when going through the 'while' to 'if/elif' statements. No problem.
However, if the user DOES NOT input the data correctly the first time through, I'm trying to catch that with my final 'else' statement and then begin the function again. However, the second/third/ect time through, even if the user inputs a valid selection, the 'return' type is None and the value returned is None.
So, my user validation is missing something. Any thoughts?
#Global variable initialization
mainSelection = str(None)
#Santa's Christmas Card List Main Menu function
def XmasMainMenu(mainSelection):
print('')
print('How may the elves be of service today?')
print('')
print('\"PRINT\" - Print out the Christmas card list from the database.')
print('\"ADD\" - Add nice recipients information to the Christmas card list.')
print('\"SEARCH\" - Search the database for information.')
print('\"DELETE\" - Remove naughty recipients from the Christmas card list. ')
print('\"EXIT\" - Exit the program without any printing or changes to the database.')
print('')
mainSelection = input('Please enter your selection: ')
mainSelection = mainSelection.lower()
print(type(mainSelection), mainSelection)
#Selection return value
while mainSelection != None:
if mainSelection == 'print':
print('|| Will print out the Xmas Card List ||')
return mainSelection
elif mainSelection == 'add':
print('|| Will prompt user to add information to the DB ||')
return mainSelection
elif mainSelection == 'search':
print('|| Will prompt user to search the information in the DB ||')
return mainSelection
elif mainSelection == 'delete':
print('|| Will prompt the user to delete recipients from the DB ||')
return mainSelection
elif mainSelection == 'exit':
print('|| Will exit the user from the program with no changes')
return mainSelection
elif mainSelection == 'drop table':
print('|| Will call the XmasTableDrop function ||')
return mainSelection
else:
print('')
print('Input Error: Please enter a valid selection above!')
print('Try again...')
print('')
print(type(mainSelection), mainSelection)
break
XmasMainMenu(mainSelection)
Program Launch
User input correct, 'return' value is correct
1st user input invalid. Error message is received, the function starts over again. 2nd user input valid --> however, the 'return' type is None and the value is None (this is what I need to fix, but cannot figure out).
This is a typical "new programmer" mistake. Do not call a function within the function itself unless you know what recursion is and how it works. When a called function returns it returns to the function that called it. What happens is:
XmasMainMenu is called from the top-level script.
...user enters an incorrect value...
XmasMainMenu calls XmasMainMenu again.
...user enters a correct value....
XmasMainMenu (2nd call) returns to XmasMainMenu (1st call)
The return value is not assigned to anything, so is lost.
Now at the end of the function with no return, so returns default None.
top-level script receives None.
Instead, wrap your code in a while True: and break when you get a correct value, then return that (pseudo-code):
def XmasMainMenu():
while True:
print menu # this could be outside while if you don't want to re-print menu.
selection = input()
if selection valid:
break # exit while loop
else:
prompt user to enter valid input.
return selection

Passing Arguments within If Statement

I'm trying to pass arguments between two files, and am encountering issues. I'm trying to parse a message for the word 'foo' in it, and create a function that will check if the message is only 'foo' or perhaps is a word like 'foot', which contains foo but isn't the word foo. Here's the two files
test2.py
import os, sys
from functiontest import function
message = 'foo'
check = 0
if 'foo' in message:
function(message,check)
print(check)
print('bar')
else:
check = 0
if check == 0:
print('foo not recognized')
and the function file
functiontest.py
import os, sys
def function(a,b):
print('checking message')
a = a.split()
print(a)
if a[0] == 'foo':
b = 1
print(b)
return b
else:
b = 0
return b
When run, it indicates that when b is set to 1 and passes it, it doesn't get passed correctly and remains 0. I want it to pass the argument check to be 1 if it is detected that the word isn't exactly 'foo' so that the message will appear saying that 'foo is not detected'. What am I doing wrong?
Follow up question: Once check is confirmed as 0 within the if statement, is there a way to break the statement and not execute the next lines that are within that if statement and rather skip to the else statement? I would prefer to include this somehow in the function to make the main code look cleaner, because I could include more embedded if statements but I want to avoid that if possible.
You're throwing away the return value of function, then printing check, which was never changed from the original value of 0. I believe your intent was to reassign check with the return value of the function:
check = function(message,check)
print(check)

How to call a function with less arguments that is set (Python 3)

I am making a terminal emulator in Python 3. The commands are being stored in functions, like:
def rd(os_vartmp, os_vartmp2):
if os_vartmp == None:
print('rd [path] [-S]')
print('Delete a folder')
else:
if os.path.isfile(os_vartmp) == True:
if os_vartmp2 == '-S': print('a')
else:
print(ERR5)
a = input('Command: ')
The terminal works like this:
Asks user for input
Splits the input
Uses the first part of input to search a function in locals
If there is one, uses the rest part of input as argument
Calls the function
The thing here is, when i call the function 'rd' with, for example, 'rd "boot.py" -S' it works just fine. But if i need to call it like this: rd "boot.py", it throws me a error about 1 argument given when 2 are required. Is there a fix for that?
You can make an argument optional by assigning a value in the method definition. For example:
def Add(x=0, y=0):
return x+y
If you input only one value, y will default to 0. If I wanted to give y a value but have x fall back on it's default value I could do Add(y=10). I hope this helped!
Have you tried this?
def rd(os_vartmp, os_vartmp2="-S"):
Instead of trying to get null value, which would require rd("boot.py",null), you can ser default value and then you can do rd("boot.py").
Hope it works.

About functions

In the code below I try to find prime numbers. My problem is that, I am not sure how to use print inside a function.
Is it correct? I get an answer but it both says 6 is not a prime number and it also gives "None". How can I get rid of this "None"? Also, is it okay to use return just like this?
#Prime number
def prime(num):
for i in range (2,num):
if num%i == 0:
print num, "is not a prime number."
return
else:
print num, "is a prime number."
return
print prime(6)
First of all you have print statements in your code already so just calling prime will result in stuff being printed to the screen. When you have a bare return your function will return None. That means that when you do:
print prime(6)
prime(6) will return None which makes this equivalent to:
print None
Then you have a major logic error in your code because you do not check every possible divisor due to returning too early. For example if you have the number be 9, this is not a prime number. However your function will print that it is a prime because on the first run through the for loop i will be 2 which means 9%2 is false so the else branch gets taken and it prints out that the number is prime. The function then returns at that point without checking the rest of the numbers. If you run this code you will see what happens: http://ideone.com/zxdez2
The design issue here is that you really should keep IO separate from the rest of the functionality. Say you wanted to reuse prime somewhere else later on you can't do this without also having that code print out to the screen. This might not be what you want at that later date but it's hard to do something with that. Instead it is much cleaner to return a boolean that represents if the number was prime or not then print out based on that returned value:
def prime(num):
for i in range (2,num):
if num%i == 0:
return False
return True
x = 6
if prime(x):
print x, "is not a prime number."
else:
print x, "is a prime number."