Question: What would be the issue if python continues to ask for the same input over and over again, and won't advance to the end of the program?
Where do you want to go? X
And how many days will you be staying in X? 1
And how many days will you be staying in X? 2
And how many days will you be staying in X? 164
And how many days will you be staying in X? 59
...
Here's the relevant part of the code:
# Import modules
import destinations
import currency
save_itinerary = True
main_function = True
while (main_function):
# Determine length of stay
while True:
try:
length_of_stay = int(input("And how many days will you be staying in " + destinations.destination[0] + "? "))
# Check for non-positive input
if (length_of_stay <= 0):
print("Please enter a positive number of days.")
continue
except ValueError:
print("The value you entered is invalid. Only numerical values are valid.")
break
else:
break
The reason your code is looping forever is that you have two nested while loops, and you never break out of the outer one. You do use break statements to exit the inner loop, but the condition for the outer loop is never changed, and you never execute a break at the right level to exit it.
Here's what I think a better version of your code would be:
# get rid of the outer while loop, which was never ending
while True:
try:
length_of_stay = int(input("And how many days will you be staying in " + destinations.destination[0] + "? "))
if (length_of_stay <= 0):
print("Please enter a positive number of days.")
continue
except ValueError:
print("The value you entered is invalid. Only numerical values are valid.")
# don't break here, you want to stay in the loop!
else:
break
I've used comments to indicate my changes.
You could also move the else: break block up and indent it so that it is attached to the if statement, rather than the try/except statements (and then get rid of the unnecessary continue statement). That's makes the flow a bit more obvious, though there's not really anything wrong with how it is now.
Related
I'm "newish" to python programming. I'm trying my best to make my code look nice and function well. I'm using Pycharm as my IDE. I'm doing something for myself. I play tabletop RPG's and I'm attempting to create a character creator for a game I play. I have everything working well, but Pycharm is telling me that "Expression can be simplified" and "PEP 8: E712 comparison to True should be 'if cond is not True:' or 'if not cond:'"
Here is the code in question:
fname = False
while fname != True:
new_character.firstName = input('What would you like your first name to be?\n').capitalize()
if 1 >= len(new_character.firstName) or len(new_character.firstName) > 20:
print('Name does not meet length requirements. Please try again.')
if new_character.firstName.isalpha() != True:
print('Please do not use numbers or special characters in your name. Please try again.')
if (1 < len(new_character.firstName) < 20) and (new_character.firstName.isalpha() == True):
fname = True
Pycharm is telling me that my "while fname != True:" is the part that can be simplified as well as the "if new_character.firstName.isalpha() != True:".
I've tried googling a solution for what I'm doing, but most of them are for something kinda like what I'm asking, but never with the != True portion. I've even reached out to one of my friends that's a python programmer, but I haven't heard back yet.
Again, I want to state that as it is now, the code works correctly the way it is written, I'm just wanting to understand if there is a way to make the code look cleaner/neater or do the same function and be simplified somehow.
Any pointers on how to potentially simplify those lines of code and maintain the functionality would be greatly appreciated.
Here's one way you could rewrite this code to make it easier to read, and more efficient:
# Loop until the user provides a good input
while True:
# Set a temp variable, don't constantly reassign to the new_character.firstName attribute
name = input('What would you like your first name to be?\n').capitalize()
# If the name isn't between 2 and 20 characters, start the loop over at the beginning
if not (1 < len(name) <= 20):
print('Name does not meet length requirements. Please try again.')
continue
# If the name contains anything other than letters, start the loop over at the beginning
if not name.isalpha():
print('Please do not use numbers or special characters in your name. Please try again.')
continue
# You can only reach this break if the name "passed" the two checks above
break
# Finally, assign the character name
new_character.firstName = name
One thing you could do to simplify further is to check both conditions at the same time, and print a more helpful error message that re-states the requirements explicitly:
NAME_ERROR_MESSAGE = """
Invalid name '{name}'. Your character's name
must be between 2 and 20 characters long, and
contain only letters. Please try again.
"""
while True:
name = input('What would you like your first name to be?\n').capitalize()
if (1 < len(name) <= 20) and name.isalpha():
new_character.firstName = name
break
print(NAME_ERROR_MESSAGE.format(name=name)
I can't seem to be able to get the correct total number of attempts to be displayed.
def checkAge():
Age=int(input("EnterAge:"))
attempts=0
if Age>=100:
attempts=attempts+1;
return checkAge()
elif Age<=1:
attempts=attempts+1;
return checkAge()
else:
attempts=attempts+1;
print("Your age is",Age,".")
print("Number of attempts: ",attempts,"")
Typing in 234 then 432 then 52, I expect the result for the attempts to be:
"Number of attempts:3"
but it shows me:
"Number of attempts:1"
attempts is being reset to 0 on each function call. You should create a parameter that you pass to checkAge and remove the variable instantiation attempts=0.
An updated function might look like
def checkAge(attempts):
Age=int(input("EnterAge:"))
if Age>=100:
attempts=attempts+1;
return checkAge(attempts)
elif Age<=1:
attempts=attempts+1;
return checkAge(attempts)
else:
attempts=attempts+1;
print("Your age is",Age,".")
print("Number of attempts: ",attempts,"")
Your problem arises mainly because you try to call your function recursively when it fails, which is a bad idea, because:
there is a limit to the number of recursive calls you can make (by default, 1000 with the common implementation of Python)
as you would have to do here, you have to pass variables between calls of the function.
the order of execution can become complicated to follow because of the imbricated calls / returns
The right way to do what you want here it is to use a loop:
def checkAge():
attempts = 0
while True:
attempts += 1
try:
age = int(input("Enter Age: "))
except ValueError:
# what we entered couldn't be converted to an integer
continue
if 1 < age <100:
return age, attempts
age, attempts = checkAge()
print("Your age is {}.".format(age))
print("Number of attempts: ", attempts, "")
Sample run:
# Enter Age: abc
# Enter Age: 122
# Enter Age: 0
# Enter Age: 33
# Your age is 33.
# Number of attempts: 4
I added a try/except block around the call to int(input(...)), as this would raise an exception and crash your program otherwise if the user didn't enter a valid number.
Also, it is better for functions to return data rather than print it directly, that makes them more versatile - you can decide what you do with the returned data.
Using format gives you more control on the printed output (here, it allows you to have the final dot just after the number, instead of separated by an extra space).
Every time you run your method checkAge() attempts is assigned the value of 0 so no matter how often you run it, it will always do: attempts = 0 then attempts = 0 + 1
You need to initialize your variable outside of your method, check if it already exists (only assign 0 if attempts is null) or implement it in a different way so it won't reset to 0 every time.
I want to write a python program, first it asks you to enter two numbers, and then output all daffodil numbers between the two numbers, and it will continue run, until I enter a "q". I write a program, but it is wrong:
#coding=utf-8
while 1:
try:
x1=int(raw_input("please enter a number x1="))
x2=int(raw_input("please enter a number x2="))
except:
print("please enter only numbers")
continue
if x1>x2:
x1,x2=x2,x1
pass
for n in xrange(x1,x2):
i=n/100
j=n/10%10
k=n%10
if i*100+j*10+k==i+j**2+k**3:
print ("%-5d")%n
pass
Can somebody help? I think it should be simple, but I am not able to write it correctly.
I believe you've misunderstood the problem statement. Try this instead:
if i*100+j*10+k==i**3+j**3+k**3:
ref: http://en.wikipedia.org/wiki/Narcissistic_number
for n in xrange(x1,x2):
digits = map(int,str(n))
num_digits = len(digits)
if sum(map(lambda x:x**num_digits,digits)) == n:
print "%d is a magic number"%n
you will still have the issue of not being able to enter "q" since you force the input to be integers
I would like to address the quit event.
while True:
x1 = raw_input("please enter a number x1=")
x2 = raw_input("please enter a number x2=")
quit = ('q','Q')
if x1 in quit or x2 in quit:
break
else:
try:
x1, x2 = int(x1), int(x2)
except:
print("please enter only numbers")
continue
# The mathematical part... (for completeness) (not my code)
if x1>x2:
x1,x2=x2,x1
for n in xrange(x1,x2):
i=n/100
j=n/10%10
k=n%10
if i*100+j*10+k==i+j**2+k**3:
print "%-5d"%n
The pass statement is used only when you don't have anything to be executed in certain block of code. It does nothing more, so don't use it if not needed. It is there for the sake of the code looking clean & with correct indentation.
if some_thing: # don't do anything
else:
some_thing = some_thing_else
Note how the above if statement is syntactically incorrect. This is where pass comes handy. Say, you decide to write the if part later, till then you must provide pass.
if some_thing: # don't do anything
pass
else:
some_thing = some_thing_else
It's a bit tricky to know what's going on without more hints, but some issues I see right off:
You need to be consistent with indentation in Python. Your last if statement is less indented than statements above it (like the previous if and the for loop). This will cause an error. You're also using different amounts of indentation in other places, but since it's not inconsistent that's allowed (if a bad idea). Its usually best to pick one indentation standard (like four spaces) and stick with it. Often you can set your text editor to help you with this (turn on "Expand tabs to spaces" or something in the settings).
You've got two pass statements where they're unneeded or harmful. The first, after the line that has if x1>x2: x1,x2=x2,x1 is going to cause an error. You can't have an indented "suite" of code if you've put a series of simple statements on the end of your compound statement like an if. Either put the assignment on its own line, indented, or get rid of the pass. The last pass at the end of the code is not an error, just unnecessary.
You're missing a colon at the end of your try statement. Every statement in Python that introduces an indented suite ends with a colon, so it should be easy to learn where they're needed.
while True:
x1 = raw_input("please enter a number x1=")
x2 = raw_input("please enter a number x2=")
quit = ('q','Q')
if x1 in quit or x2 in quit:
break
else:
try:
x1, x2 = int(x1), int(x2)
except:
print("please enter only numbers")
continue
if x1>x2:
x1,x2=x2,x1
pass
for n in xrange(x1,x2):
i=n/100
j=n/10%10
k=n%10
if i*100+j*10+k==i+j**2+k**3:
print ("%-5d")%n
pass
i have it! thx to Ashish! it is exactly what i want! and i will quit wenn i enter q! thx a lot!
I start my python script asking the user what they want to do?
def askUser():
choice = input("Do you want to: \n(1) Go to stack overflow \n(2) Import from phone \n(3) Import from camcorder \n(4) Import from camcorder?");
print ("You entered: %s " % choice);
I would then like to:
Confirm the user has entered something valid - single digit from 1 - 4.
Jump to corresponding function based on import. Something like a switch case statement.
Any tips on how to do this in a pythonic way?
Firstly, semi-colons are not needed in python :) (yay).
Use a dictionary. Also, to get an input that will almost certainly be between 1-4, use a while loop to keep on asking for input until 1-4 is given:
def askUser():
while True:
try:
choice = int(input("Do you want to: \n(1) Go to stack overflow \n(2) Import from phone \n(3) Import from camcorder \n(4) Import from camcorder?"))
except ValueError:
print("Please input a number")
continue
if 0 < choice < 5:
break
else:
print("That is not between 1 and 4! Try again:")
print ("You entered: {} ".format(choice)) # Good to use format instead of string formatting with %
mydict = {1:go_to_stackoverflow, 2:import_from_phone, 3:import_from_camcorder, 4:import_from_camcorder}
mydict[choice]()
We use the try/except statements here to show if the input was not a number. If it wasn't, we use continue to start the while-loop from the beginning.
.get() gets the value from mydict with the input you give. As it returns a function, we put () afterwards to call the function.
I am trying to analyse user input and only allow integers to be inputted. I have succesfully managed to only allow denominations of 100s between a certain range, but I cannot work out how to prompt the user to re-enter data if they enter a random string.
Trying to use the "try" command just results in the program getting stuck:
while True:
try:
bet=int(raw_input('Place your bets please:'))
except ValueError:
print 'l2type'
#The following receives a betting amount from the user, and then assesses whether it is a legal bet or not. If not, the user is prompted to enter a legal bet.
while True:
if bet%100==0 and 100<=bet<=20000:
print bet,"Your bet has been accepted, can you make a million?"
break
else:
print bet,"Please enter a legal bet. The table minimum is 100, with a maximum of 20000 in increments of 100."
bet = input('Place your bets please:')
You have the right approach for rejecting non-integer input, but you need to break out of the loop if your user enters valid input. Use the break statement:
while True:
try:
bet=int(raw_input('Place your bets please:'))
break # we only get here if the input was parsed successfully
except ValueError:
print 'l2type'
You will probably also want to move the range checks within the loop. If input that's out of range doesn't naturally lead to an exception, use if statements to make sure "break" is only executed if the input is completely valid.
I rather prefer my recursive version:
def ask_bet(prompt):
bet = raw_input(prompt)
# Validation. If the input is invalid, call itself recursively.
try:
bet = int(bet)
except ValueError:
return ask_bet('Huh? ')
if bet % 100 != 0:
return ask_bet('Huh? ')
if not 100 <= bet <= 20000:
return ask_bet('Huh? ')
# The input is fine so return it.
return bet
ask_bet("Place your bets please: ")
In my opinion, that is much cleaner and easier to read than while loops. You don't have to bother what are attribute values after the first iteration? Adding new validation rules is also really simple.
Generally, I try to avoid while loop in favour of recursive version. Of course, not all the time, since it's slower and the stack is not infinite.