Issue with my 'very simple' Python Calculator - python

I have written another simple program that I call my basic 'Python Calculator.' So far, I have found a problem with some of the code that I have written in Python 3.3.2. Here is the code below so you can read it before I state my problem...
def startup_screen():
user_input_1 = int(input("Please enter your first number.\n"))
user_input_2 = int(input("Now please enter your second number.\n"))
command_list()
def command_list():
user_command = input("Now what would you like to do with these two numbers?\n").lower()
if user_command == "add":
calc_add()
elif user_command == "subtract":
calc_subtract()
elif user_command == "multiply":
calc_multiply()
elif user_command == "divide":
calc_divide
else:
print("Please try again.")
user_command
def calc_add():
add_result = (user_input_1+user_input_2)
print(add_result)
command_list()
def calc_subtract():
subtract_result = (user_input_1-user_input_2)
print(subtract_result)
command_list()
def calc_multiply():
multiply_result = (user_input_1*user_input_2)
print(multiply_result)
command_list()
def calc_divide():
divide_result = (user_input_1/user_input_2)
print(divide_result)
command_list()
startup_screen()
Here, you can see that I have defined the startup_screen, which collects user input as an integer and then stores it respectively in user_1 and user_2. Then, the user is taken to the command home screen where they can choose to either add, subtract, multiply or divide both numbers. The command is then determined from the user input, so if the user wants to add two numbers, they type in 'add' and they are taken to the add function - as defined above.
However, in the add function, the user_1 and user_2 inputs are not recognized, as well as in the other programs... so it causes an error in the in the program. I have no idea what to do. Could you please help me?
Thank you very much...

Lets look at you program from the point of view of the def calc_add(): function.
In the first line,
add_result = (user_input_1 + user_input_2)
you say, take the value of user_input_1 add it to user_input_2 and make that into the variable add_result. Okay that makes sense.
Now lets get the first value user_input_1... lets see, first place to check is the 'local scope'. That is the function i am currently in.
def calc_add():
add_result = (user_input_1 + user_input_2)
print(add_result)
Okay nope, nothing there... okay maybe it was one of the input parameters ?
def calc_add():
Nope no input parameters were passed to this function. Okay it must be global ... but wait crap... no global parameters are ever decalred! especially not user_input_1. Well dang it, im supposed to add two parameters but one of the parameters doesnt exist! Thats not possible I better throw an error!
Maybe if the programmer had passed me the information i needed it would work better,
Maybe something like this :
def load_screen():
user_1 = int(input("Please enter your first number.\n"))
user_2 = int(input("Now please enter your second number.\n"))
command_home( user_1, user_2) # Okay command_home I took 2 inputs!
# Here they are work your magic!
def command_home(in1, in2): # Hey I need 2 varaibles to work, Ill call them in1 and in2.
# so based on the way command_home( user_1, user_2) is called
# in1 = user_1, in2 = user_2
command = input("Now what would you like to do with these two numbers?\n").lower()
if command == "add":
calc_add(in1, in2) #Okay, now i need to add my two inputs,
# but calc_add is another function it wont be able to see MY
# in1, in2 ... i better pass them over as parameters.
elif command == "subtract":
calc_subtract()
elif command == "multiply":
calc_multiply()
elif command == "divide":
calc_divide()
def calc_add(user_input_1,user_input_2 ): # Okay now i know where to look for user_input_1
# and user_input_2, they will be passed to me
# when someone calls me! Now i can find my varables
# and i wont throw an error!
add_result = (user_input_1 + user_input_2)
print(add_result)

Give the inputs as arguments to the functions that follow, the values are not global variables (not immediately accessible by any function) if they are defined within a function.
def loadscreen():
...
command_home(user_input_1,user_input_2)
def command_home(user_input_1,user_input_2):
...
calc_add(user_input_1,user_input_2)
def calc_add(user_input_1,user_input_2)
add_result = (user_input_1 + user_input_2)
print(add_result)

You are not passing the user's input into the later functions which rely on it, such as calc_add().
The way to fix this problems would be to modify your code like so:
def startup_screen():
user_1 = int(input("Please enter your first number.\n"))
user_2 = int(input("Now please enter your second number.\n"))
command_home(user_1,user_2)
def command_home(u1,u2):
command = input("Now what would you like to do with these two numbers?\n").lower()
if command == "add":
calc_add(u1,u2)
elif command == "subtract":
calc_subtract(u1,u2)
elif command == "multiply":
calc_multiply(u1,u2)
elif command == "divide":
calc_divide(u1,u2)
def calc_add(user_input_1,user_input_2):
add_result = (user_input_1 + user_input_2)
print(add_result)
"""the rest of the functions go here, must be defined to take the inputs passed"""
startup_screen()
We have redefined command_home to take two objects as inputs (which should be the user_1 and user_2 from load_screen). You could call them anything but I called them u1 and u2 so I wouldn't have to type so much. Now, command_home has these values and can, in turn, pass them into the functions which it calls that need them. We have also changed all of the function calls inside the if/elif block so that u1 and u2 are passed into those functions.
Then, we have redifined calc_add to take two inputs, and I called them the same as you did already inside the function, so I would have one less line to change - user_input_1 and user_input_2.
Now when you ask for them to be added together into add_result, they exist and have the expected values, so everything now works.

Related

How to return to the start of a function while in that function without recursion

class PlayerAttributes:
inventory = []
def __init__(self, name, inventory):
self.name = name
self.inventory = inventory # LIST
class Item:
def __init__(self, item_name, damage):
self.item_name = item_name
self.damage = damage
class Weapons(Item):
weapon_1 = Item("Me Sword", 100)
Player_1 = PlayerAttributes("Bob", [])
def get_name():
Player_1.name = input("Enter name here: ").capitalize()
commands()
def stats():
print("Name = " + str(Player_1.name), "\n",
"Inventory: ")
for x in Player_1.inventory:
print(str(x.item_name))
def commands():
prompt = None
prompt_choices = {"stats", "quit", "give"}
while prompt not in prompt_choices:
prompt = input("Enter Command: ").lower()
if prompt == "stats":
stats()
commands()
elif prompt == "quit":
quit()
elif prompt == "give":
Player_1.inventory.append(Weapons.weapon_1)
commands()
get_name()
PROBLEM
I'm currently getting back to the while loop for "prompt" by calling "commands()" in the if statements but was told that it's a recursion and that it's unnecessary as well as it has a side effect of growing the call stack...
QUESTION
What should I do differently??
Extra
How would it grow the call stack?
You can use an infinite loop. Instead of letting get_name and commands call commands, try putting the following at the end of the code:
get_name()
while True:
commands()
and remove all other calls commands() from your code.
Your while loop is configured for repeating the cycle until it finds a prompt. Then, the loop ends. You are restarting the cycle calling the function again but that leaves the first function running so every time this happens a new function will start and the old one will stay waiting. So as you said, the call stack is growing.
One way to solve this is to change your while loop.
Instead of:
while prompt not in prompt_choices:
You can use:
While True:
This makes the loop repeat over and over again without calling a new function.
Another solution will be to use two whiles:
condition = True
While condition:
while prompt not in prompt_choices:
This also makes the loop repeat over and over again. But if you want to finish the loop you can set condition = False within your code and that will make the current cycle the last cycle.
Hope this helps.
You can change your commands() func like below
def commands():
prompt = None
prompt_choices = {"stats", "quit", "give"}
while prompt not in prompt_choices:
prompt = input("Enter Command: ").lower()
if prompt == "stats":
stats()
elif prompt == "quit":
quit()
elif prompt == "give":
Player_1.inventory.append(Weapons.weapon_1)
prompt=None
get_name()

How do I get my code to run the if statement?

I'm a beginner in Python and I'm writing a code for a school project and ran into an early bug.
For some reason my if function won't run.
import time #imports computer time to program(buit in function)
count= 0
print(" Gymship") # center this
print("--------------------------------------") # this should go across the whole screen
print("Input a level to view the description or InputSign up to begin signing up for a card")
print("--------------------------------------------------------------------------")
print("Bronze")
time.sleep(1) # this wil pause the program for 1 second(for effect)
print("Silver")
time.sleep(1)
print("Gold")
time.sleep(1)
print("Platinum")
time.sleep(2)
print("-----------------------------------------------") # this should go across the whole screen
print("Sign up")
print(" ")
input()
if input == "Bronze":
print("Bronze")
print("--------------------------------------------")
print("You acquire a bronze card when you use two or less gym services")
print("2 Hours limit in the gym")
print("-------------------------------------")
print(input("Back to return to menu screen"))
count = count + 1
This is not correct:
input()
if input == "Bronze":
The way input() works is by returning a value. The name input refers to the function itself, so the function input will never equal the text "Bronze" unless you explicitly do something bad, like input = "Bronze" (it's bad because if you overwrite input, you'll no longer be able to access that function).
Instead, you should be using the returned value:
usr_input = input()
if usr_input == "Bronze":
Also, the line print(input("Back to return to menu screen")) is unnecessarily complicated; the print() will print whatever was returned by input(), but input() will display the "Back to return to menu screen" prompt without wrapping it in an if statement. So, input("Back to return to menu screen") is all you need. If you keep it the way you have it, if someone typed some text and then hit enter, the text would display again, because the print() is printing whatever that text was that the user typed.
You first need to assign a variable to the input and then check if the variable is equal to "Bronze"
Right now you are taking the input, but are not storing it anywhere. So the fixed code would be
user_input = input()
if user_input == "Bronze":

python pass function with argument to another function

I'm trying to create a function that gets two functions as argument and I get an error .
What I have done is created a function named "parent" that takes 2 functions as argument (ux and ui). But ux has arguments too, and it gets them from the parent function:
import ID_Ui as Ui
ui = Ui.admin_panel()
# ui returns something like this :
'''Please choose one of the options below :
Please press 0 if you want to exit the program .
Please press 1 if you want to exit to main menu .
Please press 2 if you want exit to previous section .
Please press 3 if you want to create/modify user account .
Please press 4 if you want to create/modify company account .
Please press 5 if you want to create/modify document type .
Please press 6 if you want to create/modify document ID . '''
def child(*ui):
user_choice = ui
if user_choice == 3:
return 3
elif user_choice == 4:
return 4
elif user_choice == 5:
return 5
else:
return 'error'
def parent(ux, ui):
user_choice = ui
x = user_choice
if user_choice == 0:
return 0
elif user_choice == 1:
return 1
elif user_choice == 2:
return 2
else:
ux(x)
print(parent(child(), ui))
I expect that when I input a number other than [0:2] , it runs the ux function and passes it the x variable as its argument. But I get the following error regarding ux(x) line:
TypeError: 'int' object is not callable
First of all, I'll assume that the function menu_conditions you are invoking is in fact the parent function, but I believe you should fix that.
Second, when you run child() on the last line, it returns a number, or the string error. If you wanted to be able to run child inside the parent folder, simply pass it without parentheses, like that:
print(parent(child, ui))

Function called without being told to

Newish to python, working on a text adventure, testing out the use of functions.
def cell1():
loop = 1
while loop == 1:
print("ONE")
cave1 = input()
if cave1 == ("end?"):
print("\nthis should end program")
loop = 0
break
elif cave1 == ("TWO"):
global testvar
testvar = 1
option1()
else:
print("INVALID")
def option1():
print("TWO")
loop = 1
while loop == 1:
print("test1 definition")
print (testvar)
test1 = input()
if test1 == ("ONE"):
print("you pick up the cheese")
loop = 0
cell1()
elif test1 == ("THREE"):
option2()
else:
print("INVALID")
def option2():
print("THREE")
loop = 1
while loop == 1:
print("This is option 3")
test2 = input()
if test2 == ("ONE"):
print("testering2")
cell1()
elif test2 == ("TWO"):
global testvar
testvar = 2014
option1()
else:
print("INVALID")
run = True
while run == (True):
print ("testing 123")
cell1()
print("restart about to activate")
cont = input("Restart? ")
if (cont) != "yes":
break
This program should allow you to go between options (what would be rooms) and eventually in cell1, the program should be end-able.
if the program is run and "end?" is typed as the first input, the program goes into the continue bit at the bottom, however, if you go between the 'rooms' then back to cell1, typing "end?" will call option 2.
Ive had a look around and it is still baffling me, am i ding something wrong?
Any help is appreciated, thank you.
The reason "end?" only quits for the player when they are within the first cell is because you're only checking for that input therein. The execution contained within option1() and option2() doesn't affect the execution of cell1(). You're not returning anything from your option functions, nor are you changing a sentinel value.
So, there's two basic ways you could go about this.
First, you could return a value from your functions:
if option1() == "END":
break
Or, you could alter your while loop:
# is_running is defined globally
while is_running:
And then just set is_running to False in any of your methods whenever the user types "end?". That'd probably be the easiest way with the design you're using now.
I'm sure you can tell, though, that in general your program is going to get exponentially more complex as you add more rooms and your function calls get further nested.
I'm pretty sure that the issue you're having is because you don't always break out of the loop in one function when you call another function. For instance, if your entries were TWO, ONE then end?, you'd find yourself still in the cell1 loop. That's because when the inner call to cell1 returns, the control flow of the program goes back to where that function was called from, which is option1, since loop is now 0, the loop ends and option1 returns, to the outer call to cell1, where the loop is still running.
Unless you want the game you're designing to have a tree structure, where you can return to where you came from with different semantics than moving to some other place, I'd suggest using a different architecture. Rather than each of your functions calling the next function when appropriate, return that function instead. Then you'd write a single top level loop that calls the function. Here's an example where the function to be called by the top level loop is saved in a variable named state:
def cell1():
print("In cell1!")
while True:
choice = input("pick 'ONE' or 'TWO' (or type 'quit' to exit):")
if choice == "ONE":
return option1
elif choice == "TWO":
return option2
elif choice == "quit":
return None
else:
print("I'm sorry, I didn't understand that.")
def option1(): # these other two functions are very basic in my example
print("In option1!") # but you can make them as complex as you want
return option2
def option2():
print("in option2!")
return cell1
def control_loop(initial_state=cell1):
state = initial_state
while state is not None:
state = state() # the next state is the return value of the previous state
The problem is you are getting deeper and deeper within nested functions. For example, changing
if test1 == ("ONE"):
print("you pick up the cheese")
loop = 0
cell1()
to
if test1 == ("ONE"):
print("you pick up the cheese")
loop = 0
break
will allow you to run your program, enter room two, go back to room one, and "end?" will work properly. This won't fix your issues completely though because there is a similar problem where when you go from two to three where if you simply changed
if test2 == ("ONE"):
print("testering2")
cell1()
to
if test2 == ("ONE"):
print("testering2")
break
it would break the current function and go back into option1() (if you run your program, go to room two, then to room three, then back to one) where "end?" doesn't do anything. Hopefully this gets you on the right track.

Python Amateur - 'Greeting program' - 'Referenced before assignment error'

Like I said in my previous question, I'm a python amateur. I've made a couple silly mistakes. I'm attempting to make a highly simple greeting program using Python 3.4 however I have encountered an error. The error I have is:
UnboundLocalError: local variable 'lastNameFunction' referenced before assignment
Here's my code (I know I probably don't need to post it all, but there isn't much of it):
def main():
import time
running = True
while (running):
firstNameInput = input("What is your first name?\n")
firstName = firstNameInput.title()
print ("You have entered '%s' as your first name. Is this correct?"%firstName)
time.sleep (1)
choice = input("Enter 'Y' for Yes or 'N' for No\n")
if(choice.upper() == "Y"):
lastNameFunction()
elif(choice.upper() == "N"):
main()
def lastNameFunction():
lastNameInput = input("Hi %s. Please enter your last name. \n"%firstName)
lastName = lastNameInput.title()
if __name__ == '__main__':
main()
I'd appreciate any help and advice! Please take into consideration I am really new to this stuff. I'm also not quite sure on having a function inside of a function, but I thought it would be a fix so that the 'firstName' was available when entering the 'lastName'.
Thanks in advance! :)
You need to move the lastNameFunction declaration somewhere before you call it using lastNameFunction(), e.g.:
def main():
import time
running = True
while (running):
firstNameInput = input("What is your first name?\n")
firstName = firstNameInput.title()
print ("You have entered '%s' as your first name. Is this correct?" % firstName)
time.sleep (1)
choice = input("Enter 'Y' for Yes or 'N' for No\n")
def lastNameFunction():
lastNameInput = input("Hi %s. Please enter your last name. \n" % firstName)
lastName = lastNameInput.title()
if(choice.upper() == "Y"):
lastNameFunction()
elif(choice.upper() == "N"):
main()
if __name__ == '__main__':
main()
You can also move it outside the main function, but you will then need to pass the firstName in using the function arguments:
def lastNameFunction(firstName):
lastNameInput = input("Hi %s. Please enter your last name. \n" % firstName)
lastName = lastNameInput.title()
def main():
...
lastNameFunction(firstName)
...
Move your lastNameFunction to somewhere before the call. Ideally, you would place this above the main function.
def lastNameFunction():
lastNameInput = input("Hi %s. Please enter your last name. \n"%firstName)
lastName = lastNameInput.title()
def main():
...
The problem is you called lastNameFunction() before you defined it in the while loop. Try defining the function outside the while loop.
The organisation of the whole program seems a little bit off.
Imports usually go at the top of the module.
Functions defined in functions are usually just for closures, which you a) don't need here and b) might be a bit advanced for your current experience level.
Recursive calls like your calling main() from within main() are wrong. When you adopt that style of control flow instead of a loop, you will eventually run into limitations of recursive calls (→ RuntimeError). You already have the necessary loop, so simply leaving out the elif branch already asks the user again for the first name.
running isn't used anywhere, so you can remove it and just use while True:.
I would move asking the user for ”anything” + the question if the input was correct into its own function:
def ask_string(prompt):
while True:
result = input(prompt).title()
print("You have entered '{0}'. Is this correct?".format(result))
choice = input("Enter 'Y' for Yes or 'N' for No\n")
if choice.upper() == 'Y':
return result
def main():
first_name = ask_string('What is your first name?\n')
last_name = ask_string(
'Hi {0}. Please enter your last name.\n'.format(first_name)
)
print(first_name, last_name)
if __name__ == '__main__':
main()

Categories