I'm trying to write a small Python program for use in secondary schools to teach about ciphers.
It's all part of an ongoing project they have to do.
However on my while loops I have an if condition inside them and if the condition isn't met the first time it just infinitely loops until I break.
while esc == False:
if guess != cipher:
print("ERROR: INCORRECT CIPHER:" + Decrypt(guess, enc))
pass
else:
esc = True
print("Correct Cipher! Decryption successful:" + Decrypt(guess, enc))
The cipher here is 12 and if that is input it carries on as normal, however any other input just gives the error message and loops out forever.
I'm from a C#/C++ background usually and I know Python needs to be in line with its tab characters and white space and I've checked that a few times but I'm at a loss now.
ADDITIONAL CODE:
This works fine and It's done the same way
while esc == False:
if CheckPassword(pw) == True:
print("Authorisation successful.")
esc = True
else:
pw = input("Password = : ")
ADDITIONAL PLACES WHERE SAME PROBLEM HAPPENS:
while esc == False:
if attempts < 1:
esc = True
GameOver()
elif x == "USERS":
print("USERS UNAVAILABLE.")
attempts = RemoveAttempt(attempts)
pass
I'm not sure what else you are expecting to happen. If the guess is incorrect once you get into the while loop, it is going to always be incorrect, because you never ask the user for another guess. Note that in the one that does work, the else clause has an input for a new password: you don't do that in either of your non-working examples.
(Also I think you might be confused about what pass does: it's simply a no-op, ie it does nothing at all, and is only useful where you syntactically need a statement but don't want to do anything. That's not the case in either of the places you use it, so you should remove it. Unless you perhaps meant break instead, to break out of the loop?)
Related
This question already has answers here:
Why does non-equality check of one variable against many values always return true?
(3 answers)
Closed 1 year ago.
Our teacher wants us to make a program that asks if you are ready and if YES or NO are typed then it should move on to the next question. For some reason he doesn't want us to use break and I can't find any command that really does anything similar to it other then continue, but continue only skips to the next line. Here is my code:
prompt = ""
while (prompt != "YES" or prompt != "NO"):
prompt = input ("Are you ready?(YES/NO): ")
if (prompt == "YES"):
print("Great!")
break
elif (prompt == "NO"):
print("How can I help?")
break
else:
print("Error, not a valid input")
while this would work in what I'm trying to achieve, I would get failed for having the break statement. Is there any alternative to this?
You might want to have a variable to that will check the condition such as valid_answer. Also, it is better practice to get rid of unnecessary parenthesis (if you expression is complex, they are fine, but in your case while loop condition is much simpler without them).
valid_answer = False
while not valid_answer:
prompt = input("Are you ready?(YES/NO): ")
if prompt == "YES":
print("Great!")
valid_answer = True
elif prompt == "NO":
print("How can I help?")
valid_answer = True
else:
print("Error, not a valid input")
You could just delete break from your code if you fixed your loop condition, changing:
while (prompt != "YES" or prompt != "NO"):
which is always true ("YES" is not equal to "NO", so the second test is true whenever the first one is false, so the loop condition is always true), with either:
while prompt != "YES" and prompt != "NO":
which is the minimal change to fix the logic (so it stops if it's equal to either value, rather than only when it's equal to both), or for a more English readability:
while prompt not in ("YES", "NO"):
which doesn't have the tricks of how != and and/or interact in boolean logic to worry about. Either way, after fixing the test, the code will work as written without the need for break at all.
To answer the broader question, the only alternatives to break are:
Careful use of tests to ensure the loop condition itself terminates when desired, and no code after the condition becomes true that should only execute when false is actually executed (this is what the minimal fix described above does)
Using return in a function (requires factoring the loop out of the function it is in)
Using an exception and try/except to jump out of the loop.
Not coincidentally, these are also your options when you need to break out of multiple levels of a nested loop (Python has no break that can break an arbitrary number of loops). #1 is frequently unpythonic (especially if it relies on flag variables; in your case, it's okay, just mildly redundant on the tests), as is #3, so if your code can't use break, and can't be restructured to avoid the need for it, #2 is usually the best solution, especially in complex cases.
Personally, I usually wouldn't put the handling of valid cases in the loop at all, leaving the loop to run and handle only invalid cases (which can occur 0-infinity times), with the valid cases handled after the loop is complete, exactly once.
A simple solution available on Python 3.8+ is to use the walrus operator (assignment expression for boring types) and just have the loop run until the result is valid, removing the handling for valid inputs from the loop entirely, putting them outside/after the loop entirely, so for your specific problem the end result would look like:
while (prompt := input("Are you ready?(YES/NO): ")) not in ("YES", "NO"):
print("Error, not a valid input")
if prompt == "YES":
print("Great!")
else: # No need for elif; only "YES" or "NO" would exit loop without throwing exception
print("How can I help?")
Pre-3.8, you could still do the same thing, the while is just a little uglier (more repeated code):
prompt = input("Are you ready?(YES/NO): ")
while prompt not in ("YES", "NO"):
print("Error, not a valid input")
prompt = input("Are you ready?(YES/NO): ")
Bonus, with no particular increase in code complexity, you drop from 9-11 lines of code in your current design (9 without break or explicit flag, 11 with) to 6-8 lines (6 with walrus, 8 without). With the walrus, it's strictly better; no code is repeated, no tests are repeated multiple times per loop, the loop is kept very simple.
I have two files in my text-based game. The variable that is being assigned will be keep_note.
If you enter "Take" the boolean value True is assigned to the have_note-001
but in the next file when if have_note_001 == True I get an error saying
have_note-001 is undefined
If keep_note is == "Take":
have_note_001 = True
Then in the next file I want that True value to travel over to the next file.
If have_note_001 == True: print("This Value Is True")
keep_paper = input("Do you want to Leave the piece of paper or Take it? > ")
if keep_paper == "Take":
have_note_01 = True
if have_note_01 == True:
print("You have chosen to keep the piece of paper")
print("You leave the house with the note(" + note_001 + ")")
This is my next file
from intros.intro_001 import have_note_001
if have_note_01 == True:
print("True")
elif have_note_01 == False:
print("False")
In the file, the import is working.
I am importing the have_note_001. It is just not transferring the value True over. It doesnt seem to remember when you give it that value you in the first file, to the second
How can I have the value assigned to a variable carry over to another file when imported?
I'm not sure what you are asking for is in your best interest. The values stored in variables are already carried over by default when you import the file they are from. However, this type of sporadic architecture is not really considered good practice. Let me give you some feedback on your program. First lets give it some input validation:
# start off setting keep_paper to nothing
keep_paper = ''
# As long as the player does not enter 'take' or 'leave' we are going to
# keep asking them to enter a proper response.
while keep_paper not in ['take', 'leave']:
# here we are going to "try" and ask the player for his choice
try:
# here we are getting input from the user with input(...)
# then converting it into a string with str(...)
# then converting it to lowercase with .lower()
# all together str(input(...)).lower()
keep_paper = str(input("Do you want to Leave the piece of paper or Take it? > ")).lower()
# if the player entered an invalid response such as "53" we will go back
# to the beginning and ask for another response.
except ValueError:
print("Sorry, I didn't understand that.")
# ask the user to provide valid input
continue
if have_note_01 == True:
print("True")
elif have_note_01 == False:
print("False")
Now let's address the main topic of your question. Having the value assigned to a variable carry over on imports. As I've already mentioned, this is generally not something that you want, which is why most Python programs have code including:
if __name__ == "__main__":
# do xyz....
This ensures that xyz is only run if the file is being ran, and will not run if the file is imported.
For good measure, I recommend you checkout: https://github.com/phillipjohnson/text-adventure-tut/tree/master/adventuretutorial, reading over the code in this project will give you a better idea at how you might want to tackle your own project. (The basics of functions, classes and inheritance)
I would like to have a function that works like input(), but that returns None (for example) when Esc key is pressed.
I tried doing the following:
def input(t):
print(t)
text = ""
while True:
char = msvcrt.getche();
if char == chr(27).encode():
return None
if char == b'\r':
return text
try:
text += char.decode()
except:
pass
This works for the most part, but the problem is that backspace won't work, and that I get strange characters when pressing non-character keys like the arrow keys, or the combination Ctrl+C. So getche might not be the answer to my problem.
I was under the impression that this would be a common problem, but I haven't been able to find a solution.
I was under the impression that this would be a common problem
No it is not. There are two common idioms when it comes to io. First is called line oriented. It can be used in batch mode programs where the standard input can be redirected to a file or a pipe. In this mode, the program itself should not even try to know whether it reads from a real keyboard or from a file (well more or less, password input being the exception). The low level driver, or the input library can add some goodies like in line edition (backspace processing), but this is not directly accessible to the programmer, and in any case is not intended to be portable.
Second mode is for GUI. Here, most of the things are under programmer control: the position of input fields on the screen, their size, and optionally the processing of special characters. More exactly, it is generally processed through a graphic library like tkinter (tk), pyqt or pyside (Qt), or ...
What you ask for is a medium way. It is common for beginners to try to explore it, but after some time, we all realize that for real world programs the two common idioms are enough.
You may find this answer more philosophical that technical, and in theory there would be nothing bad in improving line edition, but in real programs, I have never found any true reason to go beyond what is currently available.
I made a code using module keyboard. You an install it using pip install keyboard. It reads left,right,end,home,enter,escape,backspace and many other keys.
You can use function read_input. It has two options text and cancel. text is the text to print and cancel is the key which will cancel the input. If you press escape then it returns None, if enter then typed text.
Here is the code:
def read_input(text="",cancel="esc"):
import keyboard,string as t
print(text,end="")
output = []
output2 = []
allowed = t.ascii_letters+"1234567890!##$%^&*()-=_+{}[]|\:;',<>./?`~"+'"'
while True:
key = keyboard.read_event()
k = key.name
if key.event_type == "up":continue
if k == cancel:print("");return None
elif k == "enter":break
elif k == "end":output = output+output2;output2 = []
elif k == "home":output2 = output+output2;output = []
elif k == "left":
try:output2.insert(0,output.pop())
except:pass
elif k == "right":
try:output.append(output2.pop(0))
except:pass
elif k == "space":k = " ";output.append(k)
elif k == "backspace":output = output[:-1]
elif k in allowed:output.append(k)
foutput2 = ""
for put in output:
foutput2 += str(put)
for put in output2:
foutput2 += str(put)
for i in range(0,len(foutput2)+2):keyboard.press_and_release("backspace")
print(foutput2)
return foutput2
You can use it like normal input:
print(read_input("Enter your name: "))
It has some issues on the other side.
It read keys from the whole windows, not only python.
The keys typed in first second(when executed) may be ignored.
Here is an animation:
Ok so in this I have an issue where if the answer is "N" then it will still continue to the else statement. How do I fix this? (this is all in a function, edit: with other if statements that work fine)
if command == "Exit":
exit = 1
while exit == 1:
print("Quit? Y/N:", end="")
ex = input()
if ex == "Y":
quit()
elif ex == "N":
break
else:
print("Err")
The Code Seems To work Fine.
I assumed what you Want to do is : on Entering Exit ask user Y or N if user enters Y you quit the program if user enters N you want to break out of while loop. It works fine for both the cases can you add something else to the question to illustrate the problem.
I would also recommend you to try using return statnment while trying to break from multiple loop or if you are creating function for this purpose.
Make sure You are not entering small alphabets . You can use .upper() function to make sure you always use uppercase.
I have been trying to convert some code into a try statement but I can't seem to get anything working.
Here is my code in pseudo code:
start
run function
check for user input ('Would you like to test another variable? (y/n) ')
if: yes ('y') restart from top
elif: no ('n') exit program (loop is at end of program)
else: return an error saying that the input is invalid.
And here is my code (which works) in python 3.4
run = True
while run == True:
spuriousCorrelate(directory)
cont = True
while cont == True:
choice = input('Would you like to test another variable? (y/n) ')
if choice == 'y':
cont = False
elif choice == 'n':
run = False
cont = False
else:
print('This is not a valid answer please try again.')
run = True
cont = True
Now what is the proper way for me to convert this into a try statement or to neaten my code somewhat?
This isn't a copy of the mentioned referenced post as I am trying to manage two nested statements rather than only get the correct answer.
If you want to make your code neater, you should consider having
while run:
instead of
while run == True:
and also remove the last two lines, because setting run and cont to True again isn't necessary (their value didn't change).
Furthermore, I think that a try - except block would be useful in the case of an integer input, for example:
num = input("Please enter an integer: ")
try:
num = int(num)
except ValueError:
print("Error,", num, "is not a number.")
In your case though I think it's better to stick with if - elif - else blocks.
Ok so as a general case I will try to avoid try...except blocks
Don't do this. Use the right tool for the job.
Use raise to signal that your code can't (or shouldn't) deal with the scenario.
Use try-except to process that signal.
Now what is the proper way for me to convert this into a try statement?
Don't convert.
You don't have anything that raises in your code, so there is no point of try-except.
What is the proper way to neaten my code somewhat?
Get rid of your flag variables (run, cont). You have break, use it!
This is prefered way of imlementing do-while, as Python docs says; unfortunately, I cannot find it to link it right now.
If someone finds it, feel free to edit my answer to include it.
def main()
while True: # while user wants to test variables
spuriousCorrelate(directory) # or whatever your program is doing
while True: # while not received valid answer
choice = input('Would you like to test another variable? (y/n) ')
if choice == 'y':
break # let's test next variable
elif choice == 'n':
return # no more testing, exit whole program
else:
print('This is not a valid answer please try again.')