First if statement being ignored by python but not elif's - python

Beginner in python here. I'm trying to create a program that takes the takes the total price of many things and rounds them up or down depending on their last digit. My issue is that my first "if" statement always gets ignored but all my other "elif" statements work just fine
Code:
if str(finalTotalPrice).endswith("1" or "2") :
roundedDown = round(finalTotalPrice, 1)
print("Final Total = $" + str(roundedDown) + str(0))
print()
cashPayment = float( input("How much cash will you pay with? $"))
change = (cashPayment - roundedDown)
change = round(change, 3)
print("Your change is $" + str(change))
elif str(finalTotalPrice).endswith("8" or "9") :
roundedUp = round(finalTotalPrice, 1)
print("Final Total = $" + str(roundedUp) + str(0))
print()
cashPayment = float( input("How much cash will you pay with? $"))
change = (cashPayment - roundedUp)
change = round(change, 3)
print("Your change is $" + str(change))
elif str(finalTotalPrice).endswith("5" or "0") :
print("Final Total = $" + str(finalTotalPrice))
print()
cashPayment = float( input("How much cash will you pay with? $"))
change = (cashPayment - finalTotalPrice)
change = round(change, 3)
print("Your change is $" + str(change))

Python is not natural language. and and or do not behave the way you are used to. Let's look at the documentation:
>>> help(str.endswith)
Help on method_descriptor:
endswith(...)
S.endswith(suffix[, start[, end]]) -> bool
Return True if S ends with the specified suffix, False otherwise.
With optional start, test S beginning at that position.
With optional end, stop comparing S at that position.
suffix can also be a tuple of strings to try.
Your if statements should look like this:
if str(finalTotalPrice).endswith(("1", "2")):

As pointed out by tripleee, you're actually trying to do logically the wrong thing.
roundedDown = round(finalTotalPrice, 1)
This suggests that finalTotalPrice is a float. Never use floats for money. It'll mostly work for small values, but one day things will stop adding up. Instead, use an integer representing the amount of the smallest denomination you have – here, it looks like your dollar is divided into mils (you used round(..., 3)), so a dollar should be represented as 1000.
But can you still use the round function?
>>> help(round)
Help on built-in function round in module builtins:
round(number, ndigits=None)
Round a number to a given precision in decimal digits.
The return value is an integer if ndigits is omitted or None. Otherwise
the return value has the same type as the number. ndigits may be negative.
Yes, you can; just put in -1 to round to the nearest 10, -2 to round to the nearest 100, etc..
str(finalTotalPrice).endswith("1" or "2")
Ignoring the bug for a moment, this is a bad solution. If you're using floats, it will usually give a completely wrong answer, and if you're using ints it's inefficient. Once you're using ints, you can fix this; finalTotalPrice % 10 will get the last digit, finalTotalPrice % 100 will get the last two digits, etc.. Then you can do:
if finalTotalPrice % 10 in (1, 2):
if finalTotalPrice % 10 > 7:
if finalTotalPrice % 5 == 0:
as necessary.
Additionally, your cash payment code is identical in each if branch, so it should be written after them, not in each branch. And, while we're at it, let's make your variable names conform to PEP 8, the Python Style Guide, and improve input handling:
import re
MONEY_REGEX = re.compile(r"[$]?(\d*)(?:\.(\d+))?")
def input_dollars(prompt="", places=3):
"""Input a dollar amount, returned as an integer.
The prompt string, if given, is passed to the input function.
The places argument determines how many decimal places are allowed.
The return value is shifted by that many decimal places,
so that it is an integer.
>>> input_dollars("prompt? ", places=2)
prompt? a
invalid input
prompt?
empty input
prompt? 0.
invalid input
prompt? $32
3200
>>> input_dollars("prompt? ", places=2)
prompt? 32.450
too many decimal places
prompt? 32.4
3240
>>> input_dollars("prompt? ", places=2)
prompt? .6
60
>>> input_dollars("prompt? ", places=4)
prompt? $.472
4720
"""
fix = 10 ** places
while True:
text = input(prompt)
match = MONEY_REGEX.fullmatch(text)
if match is None:
print("invalid input")
continue
integer, fractional = match.groups()
if fractional is None:
if len(integer) == 0:
print("empty input")
continue
return int(integer) * fix
if len(fractional) > places:
print("too many decimal places")
continue
ipart = int(integer) if integer else 0
fpart = int(fractional.ljust(places, '0'))
return ipart * fix + fpart
def format_dollars(dollars, places=3):
fix = 10 ** places
return "${}.{:0>{}}".format(dollars // fix, dollars % fix, places)
def print_final_total(final_total, places=3):
print("Final Total =", format_dollars(final_total, places))
print()
final_total_price = input_dollars("What's the final total price? ")
if final_total_price % 10 in (1, 2, 8, 9):
print_final_total(round(final_total_price, -2))
elif final_total_price % 5 == 0:
print_final_total(final_total_price)
cash_payment = input_dollars("How much cash will you pay with? $")
change = cash_payment - final_total_price
print("Your change is", format_dollars(change))
This code probably doesn't do what you want it to. But, then, neither does your original.

Related

If statement requires float, terminal returns error if datatype is string

I am a beginner programmer, working on a project for an online course. I am trying to build a tip calculator. I want it to take input from the user for three values: Bill total, how many are splitting the bill, and the percent they would wish to tip. My conditional statement only has one if:
if meal_price >= 0.01:
example(example)
else:
example(example)
There are no elifs, only an else clause, stating to the user to enter only a numerical value. The program is designed to loop if the else clause runs, or continue if the 'if' condition is met. I would like this program to be completely user-friendly and run regardless of what is typed in. But instead of the else clause being ran when a user enters a string value, the terminal returns an error. How would I check the datatype the user enters, and run my conditional statement based off of that instead of the literal user response?
Note, I've tried:
if isinstance(meal_price, float):
Converting the user input into a string, but then the conditional statement becomes the problem
Thank you all for the help. I started my coding journey about 3 months ago and I am trying to learn as much as I can. Any feedback or criticism is GREATLY appreciated.
enter image description here
def calculation():
tip_percent = percentage / 100
tip_amount = meal_price * tip_percent
meal_and_tip = tip_amount + meal_price
total_to_return = meal_and_tip / to_split
return total_to_return
print("\nWelcome to the \"Bill Tip Calculator\"!")
print("All you need to do is enter the bill, the amount of people splitting it, and the percent you would like to tip.\n")
while True:
print("First, what was the total for the bill?")
meal_price = float(input("Bill (Numerical values only): "))
if meal_price >= 0.01:
meal_price2 = str(meal_price)
print("\nPerfect. The total is " + "$" + meal_price2 + ".")
while True:
print("\nHow many people are splitting the bill?")
to_split = int(input("People: "))
if to_split >= 1:
to_split2 = str(to_split)
print("\nAwesome, there is", "\"" + to_split2 + "\"", "person(s) paying.")
while True:
print("\nWhat percent would you like to tip?")
percentage = float(input("Percentage (Numerical values only, include decimals): "))
if percentage >= 0:
percentage2 = str(percentage)
print("\nGot it.", percentage2 + '%.')
calculation()
total = str(calculation())
#total2 = str(total)
print("\n\nEach person pays", "$" + total + ".")
exit()
else:
print("\nPlease enter only a numerical value. No decimals or special characters.")
else:
print("\nPlease respond with a numerical value greater than 0.\n")
else:
print("Please remember to enter only a numerical value.\n")
Included image snapshot in case copy & paste isn't accurate.
The user's input will be a string, so you need to check if the parse to the float was successful. You can do that with a try/except, and then loop back over asking for more input:
print("First, what was the total for the bill?")
meal_price = None
while meal_price == None:
try:
meal_price = float(input("Bill (Numerical values only):"))
except ValueError:
print("That didn't look like a number, please try again")
print(meal_price)
Adding on to #OliverRadini's answer, you use the same structure a lot for each of your inputs that could be generalized into a single function like so
def get_input(prompt, datatype):
value = input(prompt)
try:
a = datatype(value)
return a
except:
print("Input failed, please use {:s}".format(str(datatype)))
return get_input(prompt, datatype)
a = get_input("Bill total: ", float)
print(a)
Perhaps the main point of confusion is that input() will always return what the user enters as a string.
Therefore trying to check whether meal_price is something other than a string will always fail.
Only some strings can be converted into floats - if you try on an inappropriate string, an exception (specifically, a ValueError) will be raised.
So this is where you need to learn a bit about exception handling. Try opening with this block:
meal_price = None
while meal_price is None:
try:
meal_price = float(input("Bill (Numerical values only): "))
except ValueError:
print("Please remember to enter only a numerical value.\n")
This will try to execute your statement, but in the event it encounters a value error, you tell it not to raise the exception, but to instead print a message (and the loop restarts until they get it right, or a different kind of error that you haven't handled occurs).
Thank you all! After looking into your comments and making the amendments, my program works perfectly! You lot rock!!
def calculation():
tip_percent = tip / 100
tip_amount = bill * tip_percent
meal_and_tip = tip_amount + bill
total_to_return = meal_and_tip / to_split
return total_to_return
def user_input(prompt, datatype):
value = input(prompt)
try:
input_to_return = datatype(value)
return input_to_return
except ValueError:
print("Input failed, please use {:s}".format(str(datatype)))
return user_input(prompt, datatype)
print("\nWelcome to the \"Bill Tip Calculator\"!")
print("\nAll you need to do is:\n1.) Enter your bill\n2.) Enter the amount of
people (if bill is being split)\n3.) Enter the amount you would like to
tip.")
print("\n\n1.) What was the total for the bill?")
bill = user_input("Total Bill: ", float)
print("\nAwesome, the total for your meal was " + "$" + str(bill) + ".")
print("\n\n2.) How many people are splitting the bill?")
to_split = user_input("Number of People: ", int)
print("\nSo the bill is divided", str(to_split), "way(s).")
print("\n\n3.) What percent of the bill would you like to leave as a tip?
(Enter a numeral value only. No special characters.)")
tip = user_input("Tip: ", int)
print("\nYou would like to tip", str(tip) + "%! Nice!")
total = calculation()
print("\n\n\n\nYour total is " + "$" + str(total), "each! Thank you for using
the \"Bill Tip Calculator\"!")

Doubling amount per day, need to convert number of pennies to dollars + cents

This program starts with 1 cent and doubles each day. However, I'm stuck on trying to find a way to convert the number of pennies into a dollar and cent amount. For example, converting 1020 pennies to $10.20.
I'm also attempting to make it so if user input is not a positive number, the user will be continously prompted until they enter a positive number. This isn't working, however.
I also feel I've messed up by using range, as I want to enter a set number of days, say 16 days, and when I enter 16, I receive the days 1-17, as range should be doing, and I'm not sure how to go about fixing that.
b = int(input("Input number of days "))
if b > 0:
print(b)
else:
b = int(input("Days must be positive "))
print("Day 1:","1")
days = 1
aIncrement = 2
penny = 1
for i in range(b):
pAmount = int(penny*2)
addAmount = int(2**aIncrement -1)
aIncrement +=1
days +=1
penny *= 2
print("Day " + str(days) + ":",pAmount)
Your question has multiple parts, which is not ideal for stackoverflow, but I will try to hit them all.
Fixing the numeric values to show dollars and cents.
As noted in comments to other answers, division can often run into snags due to floating point notation. But in this case, since all we really care about is the number of times 100 will go into the penny count and the remainder, we can probably safely get away with using divmod() which is included with Python and calculates the number of times a number is divisible in another number and the remainder in whole numbers.
For clarity, divmod() returns a tuple and in the sample below, I unpack the two values stored in the tuple and assign each individual value to one of two variables: dollars and cents.
dollars, cents = divmod(pAmount, 100) # unpack values (ints)
# from divmod() function
output = '$' + str(dollars) + '.' + str(cents) # create a string from
# each int
Fixing the range issue
The range() function produces a number and you can set it to start and end where you want, keeping in mind that the ending number must be set at one value higher than you want to go to... i.e. to get the numbers from one to ten, you must use a range of 1 to 11. In your code, you use i as a placeholder and you separately use days to keep track of the value of the current day. Since your user will tell you that they want b days, you would need to increment that value immediately. I suggest combining these to simplify things and potentially using slightly more self-documenting variable names. An additional note since this starts off on day one, we can remove some of the setup code that we were using to manually process day one before the loop started (more on that in a later section).
days = int(input("Input number of days "))
for day in range(1, days + 1):
# anywhere in your code, you can now refer to day
# and it will be able to tell you the current day
Continuous input
If we ask the user for an initial input, they can put in:
a negative number
a zero
a positive number
So our while loop should check for any condition that is not positive (i.e. days <= 0). If the first request is a positive number, then the while loop is effectively skipped entirely and the script continues, otherwise it keeps asking for additional inputs. Notice... I edited the string in the second input() function to show the user both the problem and to tell them what to do next.
days = int(input("Input number of days "))
while days <= 0:
days = int(input("Days must be positive, input positive number of days: "))
Putting all this together, the code might look something like this:
I put the items above together AND cleaned up a few additional things.
days = int(input("Input number of days "))
while days <= 0:
days = int(input("Days must be positive, input number of days: "))
# aIncrement = 2 # this line not needed
penny = 1
for day in range(1, days + 1):
pAmount = int(penny) # this line was cleaned up
# because we don't need to manually
# handle day one
dollars, cents = divmod(pAmount, 100)
output = '$' + str(dollars) + '.' + str(cents)
# addAmount = int(2**aIncrement -1) # this line not needed
# aIncrement +=1 # this line not needed
penny *= 2
print("Day " + str(day) + ":", output)
For the continuous prompting, you can use a while loop.
while True:
user_input = int(input("Enter the number"))
if user_input > 0:
break
else:
continue
Or alternatively:
user_input = int(input("Enter the number"))
while user_input <= 0:
user_input = int(input("Enter the number"))
For the range issue, you can add -1 to the parameter you're passing range.
for i in range(b - 1):

how to check for float

I am trying to make a nested loop to check if a user's input should be an integer or a float.
In my calculator, rate per compounds is stored in an integer based on text input, however I want to add the functionality for the else statement to check if the input is a whole number or if its decimal. If its a whole number, I want the text to produce the number without a .0, but if its a float, such as 6.5, I want to keep that variable as a float.
rerun = True
while (rerun):
print ("Welcome to the interest calculator")
balance = input ("\nPlease enter your account balance: ")
interest = input ("\nWhat is the interest rate on the account? (decimal): ")
rate = input ("\nWhat is the rate that interest is applied? "
"\n(Monthly, Quarterly, Annually, Biannually): ")
balance = float(balance)
interest = float(interest)
#Convert text to rate variable
if (rate == "Monthly" or rate == "monthly"):
compounds = 12
elif (rate == "Quarterly" or rate == "quarterly"):
compounds = 4
elif (rate == "Annually" or rate == "annually"):
compounds = 1
elif (rate == "Biannually" or rate == "biannually"):
compounds = 2
This is where I think the check should be
else:
compounds = float(rate)
#Display Data
print ('interest = ', type(interest))
print ('balance = ', type(balance))
print ('compounds = ', type(compounds))
if (compounds == 1):
print ("\nYour account has a balance of $" + str(balance), "dollars with an interest rate \n"
"of ", str(interest) + "%", " being applied", str(compounds), "time per year")
else:
print ("\nYour account has a balance of $" + str(balance), "dollars with an interest rate \n"
"of ", str(interest) + "%", " being applied", str(compounds), "times per year")
total = interest * balance * compounds
if (total < 1):
print ("Calculated total = $" + "{:.2f}".format(total) + " cents")
else:
print ("Calculated total = $" + "{:.2f}".format(total) + " dollars")
#while loop to rerun program
answer = input ("\nType (y) to rerun the program: ")
if (answer == "y" or "Y"):
rerun = True
print ("\n")
else:
rerun = False
So if a user inputs 1 for rate, which would fall in the else statement as it is not one of my predefined words, the "Your account balance......" should display compounds as an int.
If a user inputs 1.5 for rate, which would fall in the else statement as it is not one of my predefined words, the "Your account balance......." should display compounds as a float.
Can anyone offer me some input on how I can approach this? I have tried writing it out using remainders, subtracting and adding numbers to check if compounds is > than a whole number, but I cant seem to get it to write correctly.
Just use float initially, then check if is_integer and handle accordingly:
>>> f = float(input())
3
>>> f
3.0
>>> f.is_integer()
True
Or even better, use the g format specifier:
>>> f = 1.000
>>> f
1.0
>>> print("{:g}".format(f))
1
>>> f = 3.14
>>> print("{:g}".format(f))
3.14
General format. For a given precision p >= 1, this rounds the number
to p significant digits and then formats the result in either
fixed-point format or in scientific notation, depending on its
magnitude.
The precise rules are as follows: suppose that the result formatted
with presentation type 'e' and precision p-1 would have exponent exp.
Then if -4 <= exp < p, the number is formatted with presentation type
'f' and precision p-1-exp. Otherwise, the number is formatted with
presentation type 'e' and precision p-1. In both cases insignificant
trailing zeros are removed from the significand, and the decimal point
is also removed if there are no remaining digits following it.

Rounding a float that is an str and used in int

I'm trying to replicated a program I made on a Scratch-like application. My problem here is I'm trying to display the user with different numerical data (subtotal, tax and total cost), but when it shows the total cost it gives repeating or terminating decimals. I'd like it to be rounded to two decimals. I've tried adding the round() command inside the program but it's difficult because I'm trying to round a variable rather than an actual number. This is my code so far (line 25 and 28 I believe is where I'm suppose to add a round() or on a new line). I'm very new to Python, I'm using version 3.5.0. I also have searched on here, but the answers were too complex for me. In addition, I got this error: typeerror type str doesn't define __round__ method when adding the round() function in places I assume won't work. Thanks. (ignore after the last else: statement)
#This program asks for the size of pizza and how many toppings the customer would like and calculates the subtotal, tax and total cost of the pizza.
largePizza = 'large'
extraLargePizza = 'extra large'
print ('Answer the follwing question in all lowercase letters.')
print ('Would you like a large or an extra large pizza?')
sizeOfPizza = input()
if sizeOfPizza == largePizza:
print('Large pizza. Good choice!')
else:
print('Extra large pizza. Good choice!')
costOfLargePizza = str(6)
costOfExtraLargePizza = str(10)
oneTopping = 'one'
twoToppings = 'two'
threeToppings = 'three'
fourToppings = 'four'
print ('Answer the following question using words. (one, two, three, four)')
print ('How many toppings would you like on your pizza?')
numberOfToppings = input()
tax = '13%'
if numberOfToppings == oneTopping:
print('One topping, okay.')
if sizeOfPizza == largePizza:
subtotalCostOfLargePizza = str(int(costOfLargePizza) + 1)
**totalCostOfLargePizza = str(int(subtotalCostOfLargePizza) * 1.13)**
print('Your subtotal cost is ' + str(subtotalCostOfLargePizza))
print('Your tax is ' + str(tax))
**print('Your total cost is ' + str(totalCostOfLargePizza))**
else:
print('One topping, okay.')
subtotalCostOfExtraLargePizza = str(int(costOfExtraLargePizza) + 1)
totalCostOfExtraLargePizza = str(int(subtotalCostOfExtraLargePizza) * 1.13)
print('Your subtotal cost is ' + str(subtotalCostOfExtraLargePizza))
print('Your tax is ' + str(tax))
print('Your total cost is ' + str(totalCostOfExtraLargePizza))

Exhaustive Enumeration python

I need to create a program that finds the base and exponent of a single number given that the exponent is less than 7 and greater than 1. I am using python 2.7.
My code is as follows:
def determineRootAndPower(inputInteger):
pwr = 1
num = inputInteger
while (num) > 0 and (0 < pwr < 7):
inputInteger = inputInteger - 1
pwr = pwr + 1
num = num - 1
if int(num)**int(pwr) == inputInteger:
print(str(num) + (" to the power of ") + str(pwr) + (" equals ") + str(inputInteger) + ("!"))
else:
print("No base and root combination fit the parameters of this test")
Can anyone give me any general advice on this issue? Right now I am always receiving the 'else' statement which is not correct.
First, the reason you're always hitting the else is that you're doing the if check after the loop is over. So, instead of checking each value, you're just checking the very last values.
You want to print the "Yes" answer if any value matches, and the "No" only if all values fail. For that, you need to put the if inside the loop, and break as soon as you find the first success (unless you want to print all matches, instead of just the first one), and then the else becomes something you do only if you didn't find any of them.
You can use an else: with a while:, which gets run only if you didn't break anywhere. But many people find that confusing, so it might be simpler to just return instead of break on success, and just always print the failure message if you finish the loop.
Meanwhile, I think what you're hoping to do is handle all num values from inputNumber to 0, and, for each one, all pwr values from 1 to 7. To do that, you need a nested loop.
While we're at it, using a for loop is a whole lot easier than using a while loop around a variable that you initialize and +1 or -1 each time through.
Putting all of that together:
def determineRootAndPower(inputInteger):
for num in range(inputInteger, 0, -1):
for pwr in range(1, 7):
if int(num)**int(pwr) == inputInteger:
print(str(num) + (" to the power of ") + str(pwr) + (" equals ") + str(inputInteger) + ("!"))
return
print("No base and root combination fit the parameters of this test")
You can simplify this further.
What you really want is all combinations of any num in range, and any pwr in range. You don't care about how the nesting works, you just want all the combinations. In mathematical terms, you want to loop over the cartesian product of the two ranges. The function itertools.product does exactly that. So:
def determineRootAndPower(inputInteger):
for num, pwr in itertools.product(range(inputInteger, 0, -1), range(1, 7)):
if int(num)**int(pwr) == inputInteger:
print(str(num) + (" to the power of ") + str(pwr) + (" equals ") + str(inputInteger) + ("!"))
return
print("No base and root combination fit the parameters of this test")
As a side note, there are two things that make this code harder to read for no good reason.
First, if you want to print out an expression, it's a lot easier to use format (or %) than to manually convert things to strings and concatenate them together. Formatting lets you see what the output will look like, instead of having to figure it out, and it takes care of the stringifying and related stuff automatically.
Second, adding parentheses where they're not needed makes the code harder to read. The parentheses around your print expression makes your code look like Python 3, but it's actually Python 2. And the parentheses around each string inside the expression are even worse—at first glance, it looks like those are supposed to be inside the quotes. Even the parentheses in your test expression, (num) > 0 and (0 < pwr < 7), force the reader to pause—normally, parentheses like that are used to override the normal way operators combine together, so you have to think through what would be wrong with the normal num > 0 and 0 < pwr < 7 and how the parentheses make it different, only to eventually figure out that it's actually exactly the same.
Anyway, compare these two and see which one is easier to follow:
print "{} to the power of {} equals {}!".format(num, pwr, inputInteger)
print(str(num) + (" to the power of ") + str(pwr) + (" equals ") + str(inputInteger) + ("!"))

Categories

Resources