'Issues with recursive functions when function is called the second time around
I'm trying to create a function that is similar to a shopping list where the function asks the users for 2 inputs, the first one being of the item and the second one being the number of said item the user wants, the only caveat being that the total number of items needs to be exactly 10.
def manualInput():
items = []
noitems = []
x = 1
while sum(noitems) != 10 and sum(noitems) < 10:
try:
i = str(input(f'Item {x}: '))
noi = int(input(f'No. of {i}: '))
items.append(i)
noitems.append(noi)
x = x+1
except ValueError:
print('Check inputs and try again')
items.clear()
noitems.clear()
manualInput()
if sum(noitems) > 10:
print('Number of items need to be exactly 10. Try again')
items.clear()
noitems.clear()
manualInput()
return items, noitems
Now this function works perfectly fine if the user does it perfectly the first time around. However if a ValueError is thrown or the sum of the number of items is greater than 10, the lists always return as empty lists despite the function asking the users for their inputs again.
For example if the user wants to type in Oranges and Apples and wants 6 and 4 of each respectively and manages to input all the information correctly, the first time around, the function returns (['Oranges', 'Apples'], [6, 4]) which is what I want.
In the event of an error however, lets say the user accidently inputs Oranges Apples 6 5 , the function does print out Number of items need to be exactly 10. Try again but when the user inputs all the information again, correctly this time, the function does stop but returns ([], []).
I've tried taking out the item.clear() and noitems.clear() commands but this just results in the function returning (['Oranges', 'Apples'], [6, 5])
So to sum it up I don't know why my lists aren't being appended the second time around when I call the function again in the event of an error. It was my understanding that when u call a function within a function it sort of acts like a loop where the function is run again from the top.
Solution 1:[1]
It seems you have not understood recursion and the advantage of it.
Your function creates everytime it gets called a new empty items and noitems list. That's why it is impossible to "remember" the last state.
You have to pass them as function arguments - so that the different rounds of calls can share the state of these two lists.
Second, the while loop is an imperative programming construct - recursion replaces the loop - or should replace it. So you have to get rid of it.
Third, naming in programming is one of the most critical and hardest thing.
noitems tells a reader: "there are no items" - but what you mean are 'Number of items" - call it num_items avoid misinterpretable names.
Fourth, programming is communication. Communication requires that you follow conventions of the peer group with/to which you communicate. Writing Python code means you address your code - besides to the machines especially - to the community of people writing Python code (and who have to maintain the machines and your code). - Be it your successor at work, your colleagues, or your instructor in the course. This means: Always follow the Python code conventions and guidelines (style guide https://peps.python.org/pep-0008/ - in other languages - usually the google style guide for that language).
The style guide says: You don't name in python in camelCase, but in snake_case.https://peps.python.org/pep-0008/
So call it manual_input() - not manualInput() (camelCase is JavaScript and Java convention).
def manual_nput(items = [], num_items = []):
if sum(num_items) == 10: # this is the recursion exit condition
return items, num_items # culminating in returning the result
elif sum(num_items) < 10: # these are the different cases
item = str(input(f'Item {len(items)}: '))
num_item = int(input(f'No. of {item}: '))
return manual_input(items + [item], num_items + [num_item])
# they usually end in a recursive call of the function
# with updated arguments
else: # the number of items is > 10
# in this case remove the last item and call the manual_input again
print('Number of items need to be exactly 10. Try again')
return manual_input(items[:-1], num_items[:-1])
# this [:-1] removes the last input and puts the state of
# items and num_items back to the beginning of the previous call
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
