Python input() not being called during function call [duplicate] - python

This question already has answers here:
Why does "a == x or y or z" always evaluate to True? How can I compare "a" to all of those?
(8 answers)
Closed 6 months ago.
This is a code snippet from a simple text based game I'm writing to improve my Python skills.
I plan on using input_check() to simplify a lot of code that I'll write later on in the project, but I can't get it to work at the moment. I'm running this on the latest master of VS Code with the Pylance extension, which doesn't flag any errors in my code. I've run multiple tests to make sure input_check() is the issue, and removing it and simply running the code multiple times works just fine.
import time
def rules():
print("The rules of this game are:")
time.sleep(0.5)
print("rules")
time.sleep(0.5)
print("rules")
time.sleep(0.5)
print("rules")
time.sleep(0.5)
print("rules")
time.sleep(0.5)
print("rules")
time.sleep(0.5)
input_check("Do you understand?\n", rules(), "Ok. Starting game...")
def input_check(question: str, function, confirmation: str):
yes_no = input(question)
if yes_no.lower() == "n" or "no":
function
elif yes_no.lower() == "y" or "yes":
print(confirmation)
time.sleep(1)
else:
print("Invalid input.")
input_check(question, function, confirmation)
input_check("Do you know the rules?\n", rules(), "Ok. Starting game...")
I'm almost a complete newbie to Python so I have no idea if taking the function argument and then running it as a function later in input_check() would work or not, but that's not the issue.
There should be a prompt run to define yes_no with input() but it never reaches this. Instead, it seems like it skips ahead to running rules() (which should only happen if the user inputs 'no' or 'n'), and rules() runs continuously until stopped, completely skipping input_check() .
My questions are:
Why is input_check() being completely ignored?
Can you run code taken as a parameter as-is (the function parameter) or is there an extra step I need to make it run?
Is there a better/more efficient way to do this? (e.g. a package that parses input that avoids having to make your own function)

Look at this statement:
input_check("Do you know the rules?\n", rules(), "Ok. Starting game...")
When you do that, Python is going to CALL the rules function immediately, so it can pass it's result to input_check. Your rules function prints out a bunch of stuff, then has the exact same line, which is going to call rules() again, and again, and again, and again... It never gets a chance to call input_check. It's still processing the parameters.
If you want to PASS the function object but not call it, don't use the parens:
input_check("Do you know the rules?\n", rules, "Ok. Starting game...")
Note that the input_check function will keep calling the passed in function. You DON'T need to call it again inside rules.
Followup
This does not do what you think:
if yes_no.lower() == "n" or "no":
That's parsed as:
if (yes_no.lower() == "n") or "no":
and since "no" is true, that if will always be taken. You should use one of these:
if yes_no.lower() in ("n" or "no"):
if yes_no.lower()[0] == "n":
Next, you have this:
if yes_no.lower() == "n" or "no":
function
Here, you DO want to call the function, so you need to add the parens:
if yes_no.lower()[0] == "n":
function()

inputCheck("Do you know the rules?\n", rules(), "Ok. Starting game...")
You don't need any parantheses() after rules, instead of passing function as an argument you're running it. Write it like this:-
inputCheck("Do you know the rules?\n", rules, "Ok. Starting game...")
Also here:-
if yes_no.lower() == "n" or "no":
function
You need to add () after function, write:-
if yes_no.lower() == "n" or "no":
function()
Let me know if it does solve problem

The problem is you used rules() like a parameter to pass a function. You need to change to: inputCheck("Do you know the rules?\n", rules, "Ok. Starting game...").
rules(): will calling function rules()
rules: functions can be passed as a parameter to another function.
You can come here to get more information:
What is the difference between calling function with parentheses and without in python?.
Note: I saw your sample code has many errors (when using def rules() like an object or function). You should to learn how to debug, it will help you fix errors effective

along with the other answers, I found another semantic error: your first if statement will always evaluate to true, as it will be evaluating the boolean value of 'no' as follows
if yes_no.lower() == 'n' or 'no' == True:
since a non empty string evaluates to true, this statement will always execute. instead of what you have, you can add
yes_no.lower() == 'no'
giving you
if yes_no.lower() == "n" or yes_no.lower() == "no":
making it so that statement evaluates as true only if yes_no.lower is 'n' or 'no'
for further clarification, see
Why is my python if statement not working?

You're getting a lot of explanation for the code's current behavior but not
much practical advice on how to do what I think you're trying to do. You don't
need to pass the rules function back and forth. You need the most important
tool for getting user input: a while-true loop.
def game():
if not yesno('Do you know the rules'):
rules()
print("Ok. Starting game ...")
def rules():
while True:
print("The rules of this game are ... BLAH BLAH")
if yesno('Do you understand'):
break
def yesno(question):
while True:
yn = input(f'{question}? [yes/no]: ').lower()
if yn in ('y', 'yes'):
return True
elif yn in ('n', 'no'):
return False
else:
print("Invalid input.")

Related

What command do I do to make someone loop back to a specific place in my code? [duplicate]

This question already has answers here:
Asking the user for input until they give a valid response
(22 answers)
Closed 1 year ago.
I am making a text based game. I am moving along, but I am stumped on how to make specific choices bring you back to where you need to make the choice. Currently, the current plan I am doing is to make the right answers bring you to the rest of the game, while the incorrect questions bring you nowhere, and you have to restart the program entirely, but it isn't very fun to have to slog through the parts I have already done every single time I get a wrong choice.
ruintalk = input ()
if ruintalk == '1':
print ('"Rude!" the old man shouts, "I knew you were just like the rest of them." The old man storms out as fast as his frail legs can take him. You never hear from him again and later die of lumbago and are buried in a paupers grave. Dont insult the old man or ask stupid questions. Hes kind of a dick so just roll with it and restart the game.')
What command should I put to bring me back to input()?
Loops are what can you help you with that. "while" loops particularly in this case. "while" loops keep iterating through a block of code till the condition is true.
Here is an example demonstrating their use -
while True:
ruintalk = input()
if ruintalk == correct_answer:
break # This will break the iteration
This block of code will keep iterating until break statement is called. Alternatively, what you can do is have a variable set as True and set it to false once the correct answer is entered. Here is an example showing this -
run = True
while run:
ruintalk = input()
if ruintalk == correct_answer:
run = False
If I understand what you're trying to build, you might want to make your input a function to be called. You can then build loops for different scenarios and your input will happen in a statement:
def userInput():
r = input()
r = r.lower() #I like doing this to simplify how I handle user input in the code
return(r)
while sceneComplete is False:
print("Something to setup the scene. What do you want to do, user??? (X/Y/Z)?")
action = userInput()
if action == "x":
do the x thing
elif action == "y":
do the y thing
elif action == "z":
sceneComplete = True
else:
print("You broke the rules and an ogre kills you ....")

Inputting a function into an imported module

I am attempting to create a game menu that I can then use in games to skip having to make a new menu each time. However, currently it just preforms the gameMain() function instead of doing the gameMenu() first, and then trying to select the game with "g" or "G" does nothing but end the program.
What I'm asking is if it's possible to have a variable in a module that's a function in the code that's importing it.
Here is the code for the menu, which is called textbasedadventures.py:
def gameMenu(game,your_choice="Please Enter how you'd like the game described"):
menu_options = ""
while not(menu_options == "G" or menu_options == "g":
title()
print()
print("\t\t",your_choice,"\n\n")
print('G start game')
menu_options = input("\t\tChoice: ")
if menu_options == "G" or menu_options == "g":
game
input(pause)
and this is the code for the game:
import sys
sys.path.append("\MyOwnProjects")
import textbasedadventures as t
def veryStart():
answer = ""
while not(answer == "1" or answer == "2" or answer == "3"):
print("\tYou are awoken by the blaring of your alarm clock.How did you sleep last night?")
print("\n\t1 Very well\n\n\t2 Well\n\n\t3 Not good\n\n\t4 atrociously")
answer = input("You slept ")
if answer == "1":
print("one option")
elif answer == "2":
print("\t")
elif answer == "3":
pass
elif answer == "4":
print("another option")
else:
print("\t",answer,"is not a valid entry, please try again")
def gameMain():
veryStart()
t.gameMenu(gameMain(),"please work")
If anyone can tell me how to do this, or if this is even possible, I'd be very grateful.
Your remaining problem is getting used to when you're calling a function, and when you're referring to the function as an object.
Since you didn't get any errors when you imported your textbasedadventures (which I shortened to tba to avoid typos), I assume that you've handled that properly: the file is named textbasedadventures.py and is in the local directory.
I had to remove the input(pause) line, since you didn't define pause, and it's there for a different shell from the one I'm using. I also had to remove title(), since that's no longer in your code.
When you pass the main program's main-game function, you have to pass it as a function object. You did this:
t.gameMenu(gameMain(),"please work")
This calls gameMain (because of the parentheses), grabs the return value, and passes that to t.gameMenu. Since there isn't any such return value, your remote menu routien receives only the value None.
Simply remove the parentheses:
t.gameMenu(gameMain,"please work")
This takes the entire gameMain function (well, a reference to it) and passes that to your remote function, where ...
Instead of calling the passed-in game module, you simply listed its value. Python thinks, "okay, cool, I have to evaluate this expression. Gee, a reference to an object -- that's easy. The value is simply the reference itself. I'm not even supposed to do anything with it. Done."
Simply putting a value on a line is legal Python, but boring: the value is displayed if you're in an interactive shell, but is otherwise ignored. Therefore, you never got any response from that line.
Instead, now you call it: this is where you put the parentheses you took off the other end of the call:
game()
I made those changes, and here's the result:
enter G to start game
Choice: g
You are awoken by the blaring of your alarm clock.How did you sleep last night?
1 Very well
2 Well
3 Not good
4 atrociously
You slept

Python game; Why can't I re-call my input and if/else function?

I'm still kind of learning Python, but my friend who has programmed in Python before says this should work fine, but it wont?
All code before this was the beginning story for this basic "escape the room" game I'm making. The code up until here works, (basic print functions describing the game).
I give the player the scenario that they're in a room and they can do one of two things:
def intro_room_input():
intro_action = input("What would you like to do? (Please enter either: 1 or 2) ")
return intro_action;
These two functions are for when they choose 1 or 2, the next if/elif function runs these functions
If they choose 1:
def intro_room_result1():
print(
"""
(Story stuff for the result of option 1. Not important to the code)
""")
return;
This function will play out if they choose 2
def intro_room_result2():
print(
"""
(Story stuff for the result of option 2. Not important to the code)
""")
return;
This will be the function for taking the player's input and continuing the story from there.
def intro_action_if(string):
if string == "1":
intro_room_result1()
elif string == "2":
intro_room_result2()
else:
print("I'm sorry, that wasn't one of the options that was available..."+'\n'+
"For this action, the options must be either '1' or '2'"+'\n'+
"Let me ask again...")
intro_room_input()
intro_action_if(string)
return;
that last intro_room_input runs fine, it re-runs the previous input, but when you actually enter 1 or 2, it doesn't do anything with them. It doesn't want to re-run the if/elif/else function to give the results.
finally I have a main that runs everything:
def main():
string = intro_room_input()
intro_action_if(string)
return;
main()
Please help, I have no idea what's wrong with this code!?
The problem is in your intro_action_if(). When you are calling the function to get values again, you forgot to change the string value.
ie,
#intro_room_input() #wrong
string = intro_room_input() #right
intro_action_if(string)
As you can see, even though in your code you asked for the user input and returned it, you forgot to reassign string with the returned value. Hence it kept the same input you had given previously and passed that old value to intro_action_if().

Exit a program conditional on input (Python 2)

This is for a game. The game asks the user if s/he would like to play again. If not, the program should just exit. If yes, the entire game is repeated and asks to play again, and so on.
while True:
print "*game being played*"
# prompt to play again:
while True:
replay = raw_input("Play again? ")
print replay
if replay.lower == "yes" or "y":
break
elif replay.lower == "no" or "n":
sys.exit()
else:
print "Sorry, I didn't understand that."
However, when I actually execute this code it acts as if every answer input is a yes (even "aksj;fakdsf"), so it replays the game again.
.
When I changed the code to first consider no instead of yes:
if replay.lower == "no" or "n":
sys.exit()
I get the error
Traceback (most recent call last):
File "C:/Python27/Programs/replay game.py", line 18, in <module>
sys.exit()
NameError: name 'sys' is not defined
This might have something to do with the fact I don't actually know what sys.exit() does but just found it while googling "how to exit program python".
lower is a function in python.
Be sure to include the elipses (). It should look like string.lower()
Also, try putting it at the end of your input so you don't have to type it every time
replay = raw_input('Play again? ').lower()
As Jon Clements pointed out, something that I looked over and missed in your code, consider the following statement:
if replay.lower() == "yes" or "y":
#execute
To the human eye, this looks correct, but to the computer it sees:
if replay.lower() is equal to "yes" or if 'y' is True...execute
Your game will always replay because "y" is a string and always true. You must replace the code with something like this (my above advice included):
if replay == 'yes' or replay == 'y':
#execute
finally, import sys at the top of your program. This is where the error is occurring, because sys is a module that must be imported to the program.
Here is an article on operators that you might benefit reading from
You first need to import sys. Place this:
import sys
at the top of your code to import the sys module.
However, a much easier way to exit a script is to just do this:
raise SystemExit
The above code does the exact same thing as sys.exit.
Also, for your code to work properly, you will need to do two more things:
Reconstruct your if-statements to use the in keyword.
Invoke the .lower method by placing () after it.
Below is a fixed version of your script:
while True:
print "*game being played*"
# prompt to play again:
while True:
# I put .lower() up here so I didn't have to call it multiple times
replay = raw_input("Play again? ").lower()
print replay
if replay in ("yes", "y"):
break
elif replay in ("no", "n"):
raise SystemExit
else:
print "Sorry, I didn't understand that."
Now let me explain why you needed to remake your if-statements. As it currently stands, Python is reading your code like this:
if (replay.lower == "yes") or "y":
Furthermore, since "y" is a non-empty string (which always evaluate to True in Python), this if-statement, left as it is, will always pass as True. Using in however like I did above tests whether replay can be found in the tuple ("yes", "y").
At the beginning of the code you have to add:
import sys
then other code can follow
Firstly, sys is a standard lib package that needs to be imported to reference it. I recommend reading up a bit on importing in python.
put this at the top of your code:
import sys
That should take care of the sys namespace error
Secondly you need to understand how python evaluates if statements
if replay.lower == "no" or "n":
which can be broken up into two statements:
if ( (replay.lower == "no") or ("n") ):
the left side will evaluate to False, and the right side will evaluate to True. this is because "n" (or any non 0/non False object) evaluates to True.

How do I make a function to accept an argument that is another function?

My question might seem confusing but it is the only way I could think of wording it. I apologise for any confusion, I will try my best to explain.
Basically what I am trying to do is have a simple exit function within my game that asks "Do you want to exit?" If the user inputs no it returns them back to a function they were in.
Here is what I have tried to do however it seems to just be looping back to the 'bear_room()' function.
def bear_room():
print "You are greeted by a bear"
next = raw_input()
if next == 'fight':
print 'You tried to fight a bear. You died'
elif next == 'exit':
exit_game(bear_room())
else:
print 'I did not understand that!'
bear_room()
def exit_game(stage):
print '\033[31m Are you sure you want to exit? \033[0m'
con_ext = raw_input(">")
if con_ext == 'yes':
exit()
elif con_ext == 'no':
stage
else:
print 'Please type ''yes'' or ''no'
exit_game()
You almost got it; you just need to not call bear_room when you're passing it as an argument:
elif next == 'exit':
exit_game(bear_room)
Conversely, you need to call stage as a function:
elif con_ext == 'no':
stage()
You need to understand the difference between passing a function around and calling it.
Here you are copying a reference to the function raw_input into the variable next, without actually executing it. You probably want to add parentheses () to raw_input:
next = raw_input
Here you are calling bear_room() again, recursively, instead of passing a reference to it to the exit_game function. You probably want to remove the parentheses () to bear_room:
elif next == 'exit':
exit_game(bear_room())
Again, mentioning a function without parentheses does not execute it, so you want to add those here too:
elif con_ext == 'no':
stage

Categories