I was hoping to get some kind of advice regarding the use of sys.exit(). I have used sys.exit() to stop a script from running any further:
My code:
if x != 20:
query = raw_input("X does not equal 20. Do you want to continue? (Y/N)")
if query in ['y', 'Y']:
pass
else:
sys.exit()
I have done some searching (and am still searching) but I was hoping to gain some clarity regarding the best practices use of sys.exit(). Is there something a little less extreme than killing the script? I'm considering the combination of extra loop and a more inquisitive question.
Since this is used at the beginning of your script (as mentioned by you). Use the coding pattern written below. And use return instead of sys.exit (actually since you are exiting from the script itself thereby terminating the process altogether sys.exit is not a bad practice).
Whether you use return or sys.exit return appropriate integer. its a good practice.
def do_something():
//process something
return 1
if __name__ == '__main__':
query = raw_input("Do you want to continue? (Y/N)")
if query.lower() == 'y':
//do something
do_something()
else:
print 'ERROR: Cant Understand Input. It has to be (Y/N). Exiting...'
return 0
Place your code in the main() function:
def main():
// your code
if __name__ == '__main__':
main()
Then you can exit from your script just by return
As other commenters have noted, a function provides you the option of using return to bail out from anywhere in the script and that's probably the best choice - I just thought I'd mention one piece of trivia:
Technically sys.exit raises a SystemExit exception. You can catch a SystemExit with an ordinary try-catch, effectively 'canceling' the exit if you want to. This might come in handy if you have more complex code in which a low level function might not have enough context to make a good decision but higher level code may want to step in and clean up.
People from C/C++ and lots of other languages get hives from this tactic but it's not uncommon in Pythonland. It's not a good idea to use exceptions for flow control in general but if you are using other people's functions, or combining smaller scripts into a larger application, it may be useful.
Don't forget, btw, that if control falls through to the bottom of your script it will just return 'None' anyway, so in your example:
if x != 20:
query = raw_input("X does not equal 20. Do you want to continue? (Y/N)")
if query in ['y', 'Y']:
// do something
is the same as
if x != 20:
query = raw_input("X does not equal 20. Do you want to continue? (Y/N)")
if query in ['y', 'Y']:
// do something
else:
sys.exit()
EXCEPT for the fact that you could try/catch around the second but not the first... though I assume your example is snipped from a larger sample where return is the better escape route
Related
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.")
I am doing a python course where they suggested a try and except block in a while loop in order to keep asking for input until the condition is satisfied. Intuitively I feel it is shorter to just call the function again in the "except" block like this:
def exceptiontest():
try:
print(int(input("number 1: "))+int(input("number 2:")))
except:
print("a mistake happened")
exceptiontest()
exceptiontest()
When asking on the forum on the course I got the reply that it is not the same. I am a bit confused now. Anyone that can clarify for me? Thanks in advance!
Calling the function in the except will eventually raise a RecursionError: maximum recursion depth exceeded error if you keep entering bad inputs. Generally must humans won't be entering that many bad data to hit the error before they give up, but you are unnecessarily putting function calls on a stack.
A while loop is better since it's one function call, waiting for a valid input. IT doesn't waste any more resources than it needs.
while loop, for two reasons
it's clearer to read: while not success, try again
recursion is not free. It leaves the previous function stack open. it could run out of memory (probably won't, in this case, but in principle, avoid it)
Another reason to use the while loop which has not yet been mentioned is that you could leverage the assignment expressions coming with Python 3.8.
The function add encapsulates getting two numbers and trying to add them.
def add():
'try to add two numbers from user input, return None on failure'
x = input('number 1: ')
y = input('number 2: ')
try:
return float(x) + float(y)
except TypeError, ValueError:
return None
The following while loop runs as long as there is no result.
while (result := add()) is None:
print('you made a mistake, make sure to input two numbers!')
# use result
I would like to use win32 in python to create 2 functions... 1. A function that checks if a certain application is running. 2. A function that checks if an application is installed...
I have tried the following to check if something is running;
def IsRunning(ProgramName):
if win32ui.FindWindow(None, ProgramName):
print("its running")
return True
else:
print("its not running!")
but the findwindow always throws an error if the program is not running before my program ever gets to the else statement and I do not know how to bypass that....
I needed to pass it like this;
def IsRunning(WindowName):
try:
if win32ui.FindWindow(None, WindowName):
print("its running")
return True
except win32ui.error:
print("its not running!")
return False
You need to put the window title exactly for it to pass the test and return True...
The next thing I want to write is a similar function that uses regular expressions to find any part of a title name...
Brilliant!!! Happy now :)
The only thing with this, is that if the Applications creator decides to change the title of the main window of the program you are trying to test for, it will no longer work... I was hoping for a much more robust way of doing it... i.e. through some kind of unique process code!
in any case this will do for the time being, but if anyone has a more definitive answer please let me know...
I'm going through "Learn Python the Hard Way" by Zed Shaw.
I'm currently on lesson 36: http://learnpythonthehardway.org/book/ex36.html
My issue:
I'm trying to create my own game based on what Zed did in lesson 35: http://learnpythonthehardway.org/book/ex35.html
In his game he creates the following function to terminate the game:
def dead(why):
print why, "Good job!"
exit(0)
That's used in if/else statements such as this:
choice = raw_input("> ")
if choice == "left":
bear_room()
elif choice == "right":
cthulhu_room()
else:
dead("You stumble around the room until you starve.")
When I run his program it exits when calling the dead function.
However, when I try and use this same construct in my own code I get the following error:
RunTime Error: Maximum Recursion Depth Exceeded
after lines of code spitting out the spot in my program where the exit(0) function is called.
Here's an example of how I have used it in my program:
def exit(message):
print message, "Your adventure is over."
exit(0)
With if/else statements like this:
answer = raw_input("> ")
if "stay" in answer:
exit("Adventure and excitement are only available to those who participate.")
elif "don't" in answer:
exit("Great things were never achieved by cowards. Please rethink your choice.")
elif "wait" in answer:
exit("Great things were never achieved by cowards. Please rethink your choice.")
elif "outside" in answer:
exit("Adventure and excitement are only available to those who participate.")
elif "enter" in answer:
lobby()
elif "go" in answer:
lobby()
elif "through" in answer:
lobby()
elif "inside" in answer:
lobby()
else:
exit("Well, you're no fun!")
It's not clear to me why it works in Zed's program but doesn't in my own. (And yes, I know that's probably an egregious use of elif's but my programming chops prohibit me from doing much else right now).
At first I thought it was due to how I was using while loops in my program but I've deleted all those and I'm having the same issues.
Thank you.
It's pretty simple. You named your function exit(), and your function tries to call a function named exit(). Thus your function calls itself, then calls itself again, and again, and again...
When a function calls itself, this is called a recursive call. If your function calls itself over and over too many times, eventually a limit is reached and Python stops your program. Python raises an exception, telling you that the "maximum recursion depth" was reached.
Here's a simple fix:
import sys
def dead(why):
print why, "Good job!"
sys.exit(0)
Now your program is explicitly asking for a particular exit() function, the one inside sys. Instead of calling itself recursively forever, it calls sys.exit() once and your program will stop.
Another solution is simply to rename your function to something other than exit(). Zed called his dead() which is why his example works.
I have done this in C/C++ before where I have a while loop that acts as a wait holding the program up until the condition is broken. In Python I am trying to do the same with while(GPIO.input(24) != 0): and its says that it is expecting an indent. Is there anyway to get the script to hang on this statement until the condition is broken?
Do note that an empty while loop will tend to hog resources, so if you don't mind decreasing the time resolution, you can include a sleep statement:
while (GPIO.input(24) != 0):
time.sleep(0.1)
That uses less CPU cycles, while still checking the condition with reasonable frequency.
In Python, you need to use the pass statement whenever you want an empty block.
while (GPIO.input(24) != 0):
pass
Add a pass, as such:
while(GPIO.input(24) != 0):
pass
You might also consider a different approach:
while True:
if GPIO.input(24) == 0: break
Whichever you think is more readable.
In python you can't leave the colon : hanging so you must use a pass to complete the empty block. Another way to use a while in this way
while True:
if GPIO.input(24) == 0:
break