Python - No valuerror on int with isalpha - python

Why is no ValueError raised on this try / except when isalpha should fail.
I know that isalpha returns false if given a number
In [9]: ans = input("Enter a Letter")
Enter a Letter4
In [10]: ans.isalpha()
Out[10]: False
How do I get the value error if they supply a number instead of a y or n? Because if the try is false shouldn't it stop being true and not print my trajectory?
import sys
v0 = float(input("What velocity would you like? "))
g = float(input("What gravity would you like? "))
t = float(input("What time decimal would you like? "))
print("""
We have the following inputs.
v0 is %d
g is %d
t is %d
Is this correct? [Y/n]
""" % (v0, g, t))
while True:
try:
answer = input("\t >> ").isalpha()
print(v0 * t - 0.5 * g * t ** 2)
except ValueError as err:
print("Not a valid entry", err.answer)
sys.exit()
finally:
print("would you like another?")
break
For example if the user types 5 not a y or n still gets an answer
$ python3 ball.py
What velocity would you like? 2
What gravity would you like? 3
What time decimal would you like? 4
We have the following inputs.
v0 is 2
g is 3
t is 4
Is this correct? [Y/n]
>> 5
-16.0
would you like another?

except ValueError as err: only happens when there is a ValueError thrown. The value of answer is False, but that is just an arbitrary boolean value, not an error.
See ValueError documentation for examples of things that are errors.
In your case, simply test:
answer = input("\t >> ")
if answer.isalpha():
print(v0 * t - 0.5 * g * t ** 2)
break

In general you should prefer to use normal control flow logic to handle a range of user input rather than raising/catching exceptions.

You need to raise the error yourself. There is no exception raised by typing in something that you don't prefer:
try:
answer = input("\t >> ").isalpha()
if not answer:
raise ValueError
print(v0 * t - 0.5 * g * t ** 2)
except ValueError as err:
print("Not a valid entry", err.answer)
sys.exit()

Posting an answer for clarity trying to provide a way to be more consistent and explicit with the treatment of strings and int's. By using isinstance I declare to a person reading my code explicitly what my values are to be hopefully improving readability.
answer = input("\t >> ")
if isinstance(int(answer), int) is True:
raise ValueError("Ints aren't valid input")
sys.exit()
elif isinstance(answer, str) is True:
print(v0 * t - 0.5 * g * t ** 2)
else:
print("Ok please ammend your entries")
Should I have differing requirements later this could easily be abstracted into a function, which because isinstance allows checking against multiple types increases flexibility.
Reference How to properly use python's isinstance() to check if a variable is a number?
def testSomething(arg1, **types):
if isintance(arg1, [types]):
do_something

Related

This Python code for quadratic equation isn't working

I'm trying to get the userinput for a,b,c using a function and it doesn't seems to work
import math
def equationroots():
try:
a = int(input("Enter the coefficients of a: "))
b = int(input("Enter the coefficients of b: "))
c = int(input("Enter the coefficients of c: "))
except ValueError:
print("Not a number!")
my = b * b - 4 * a * c
sqrt_val = math.sqrt(abs(my))
quadratic = (-b + sqrt_val)/(2 * a)
return quadratic
print("The equation root of the numbers is" quadratic)
equationroots()
You have not used the proper intents, This is what your code supposed to be.
import math
def equationroots():
try:
a = int(input("Enter the coefficients of a: "))
b = int(input("Enter the coefficients of b: "))
c = int(input("Enter the coefficients of c: "))
except ValueError:
print("Not a number!")
my = b * b - 4 * a * c
sqrt_val = math.sqrt(abs(my))
quadratic = (-b + sqrt_val)/(2 * a)
return quadratic
quadratic = equationroots()
print("The equation root of the numbers is", quadratic)
Indentation is very important in Python to separate block statements. It appears your indentation is off, leading to some lines not being executed when you intend.
For example, the variables my, sqrt_val, and quadratic are only calculated if the except label is reached. This means they are only attempted to be calculated if there is an input error, which wouldn't work anyways.
It's possible you also pasted in your code and the formatting was adjusted, and that isn't the issue. If that is the case, please edit the question to reflect the formatting and indentation you are using.
You need to fix your indentations from the except portion. Indentations are very important in python
fix this portion:
except ValueError:
print("Not a number!")
my = (b*b)-(4*a*c)
sqrt_val = math.sqrt(abs(my))
quadratic = ((-b)+sqrt_val)/(2*a)
return quadratic
then call your function first then use that to print your statement. Like,
quadratic = equationroots()
print(f"The equation root of the numbers is {quadratic}")

Multiple User Input with Try Except Python

I have been tasked with creating a python program that will ask for user inputs and calculate monthly loan repayments, this is the formula I have to work off: Formula. Doing this was not too difficult, however the tutor asked as a bonus to try to make the user inputs 'unbreakable', meaning if any value other than the expected were input it wouldn't break the program. I thought this can easily be done with Try Except, and that's what I did, however I believe my code can be written in a much more concise manner, instead of a Try Except for every input as below:
err = "Please enter a number only!!"
while True:
try:
A = int(input("How much were you loaned? "))
except ValueError:
print(err)
continue
else:
break
while True:
try:
R = float(input("At what monthly rate interest? ")) / 100
except ValueError:
print(err)
continue
else:
break
while True:
try:
N = int(input("And how many years is the loan for? "))
except ValueError:
print(err)
continue
else:
break
RA = R * A
RN = 1 - (1 + R) ** -N
P = RA / RN
print("You will pay £", P, "yearly", "or, £", P / 12, "monthly")
I feel as if perhaps the user inputs could be put into a For Loop, or perhaps all of this into one Try Except block? After thinking about it, I put all the inputs into one Try Except block, however as soon as you fail to correctly input the expected data for the user input, it goes right back to the beginning, not to the question you were on. This is not what I want. Have a look:
err = "Please enter a number only!!"
while True:
try:
A = int(input("How much were you loaned? "))
R = float(input("At what monthly rate interest? ")) / 100
N = int(input("And how many years is the loan for? "))
except ValueError:
print(err)
continue
else:
break
RA = R * A
RN = 1 - (1 + R) ** -N
P = RA / RN
print("You will pay £", P, "yearly", "or, £", P / 12, "monthly")
How do you think I can modify this code to make it more concise, shorter, and efficient without having a Try Except for every user input?
Modularise it, and use a generic function that handles input and loops until the user enters what is asked.
def get_num(prompt="Enter number: "):
"""
(str) -> num
Outputs a prompt and loops until a valid number is
entered by the user, at which point that value is
returned and the function terminates
"""
while True:
num = input(prompt)
try:
num = float(num)
return num
except:
print("Must enter a valid number")
def do_calc():
"""(None) -> None
Get user input, perform calculations and output results
"""
A = int(get_num("How much were you loaned? "))
R = get_num("At what monthly rate interest? ") / 100
N = int(get_num("And how many years is the loan for? "))
RA = R * A
RN = 1 - (1 + R) ** -N
P = RA / RN
print(f"You will pay £{round(P, 2)} yearly or £{P/12:.2f} monthly")
do_calc()
Using the f-string from Python 3 is really nice and elegant- just plug in the values or calculations inside the curly braces. As per suggestion in comment, you may wish to show to two decimal places using either the round function or the formatting option as shown.
A more pythonic way to name your variables would be
amount rather than A
rate rather than R
num_years rather than N
and so on.
Extract the repeated procedure in a function, with all the relevant inputs.
I have added some formatting to the final output to avoid too many decimals
def get_value(message, func, denominator = 1):
try_again = True
v = None
while try_again:
try:
v = func(input(message))/denominator
except ValueError:
print("Please enter a number only!!")
else:
try_again= False
return v
A = get_value("How much were you loaned? ", int)
R = get_value("At what monthly rate interest? ", float, denominator=100.0)
N = get_value("And how many years is the loan for? ", int)
RA = R * A
RN = 1 - (1 + R) ** -N
P = RA / RN
print("You will pay £ {:.2f} yearly or £ {:.2f} monthly".format(P, P / 12))

Using If Statements To Check If Something Raises An Error

I'm trying to write a program that will solve questions about parametric equations for me. I'm trying to do the following:
I'm trying to find 2 answers to a parametric equation. The first answer will be the positive square root. The second answer will be the negative square root. If the first square root raises a math domain error, don't find the second answer. This is what I have so far:
def hitsGround(vertical_velocity, y_coordinate):
h = vertical_velocity/-16/-2
k = -16*(h)**2 + vertical_velocity*(h) + y_coordinate
time = float(input("At what height do you want me to solve for time?: "))
try:
hits_height1 = math.sqrt((time - k)/-16) + h
except ValueError:
print("It won't reach this height.")
else:
print(f"It will take {hits_height1} seconds to hit said height.")
try:
hits_height2 = -math.sqrt((time - k)/16) + h
except ValueError:
print("There is no second time it will reach this height.")
else:
print(f"It will take {hits_height2} seconds to hit said height.")
Is there any way to use an if statement to check if the first equation raises a math domain error so I can make it so it doesn't find the second answer? Thanks!
You cannot test for a run-time exception with if; that's exactly what try-except does. However, when the illegal operation is so directly defined, you can test for that condition before you try the sqrt opertaion:
if (time - k)/-16 < 0:
# no roots
else:
# proceed to find roots.
In general, the way to make exception handling easier to is to do everything you need to do to handle the exception within the except. For example, if you don't want to find the second answer after you hit the first exception, just return:
try:
hits_height1 = math.sqrt((time - k)/-16) + h
except ValueError:
print("It won't reach this height.")
return
print(f"It will take {hits_height1} seconds to hit said height.")
If you want to make life even easier, just allow the exception to raise (without catching it at all), and catch it in the calling function!
def hitsGround(vertical_velocity, y_coordinate):
h = vertical_velocity/-16/-2
k = -16*(h)**2 + vertical_velocity*(h) + y_coordinate
time = float(input("At what height do you want me to solve for time?: "))
hits_height1 = math.sqrt((time - k)/-16) + h
print(f"It will take {hits_height1} seconds to hit said height.")
hits_height2 = -math.sqrt((time - k)/16) + h
print(f"It will take {hits_height2} seconds to hit said height.")
try:
hitGround(1.0, 10.0)
except ValueError:
print("It won't reach that height again.")
Wherever the exception is raised in hitsGround, it will immediately stop whatever that function is doing, and it will hit the except in the calling scope. That way you only need a single try/except to cover both cases.

How can can I get the entered value that matches blockRegexes in PyInputPlus.inputStr() function

I have a simple multiplication quiz from the automate book and I want to expand on it.
My goal is to collect the incorrect answers and display them at the end of the game.
However, the way the code checks for the correct answer is by blocking everything except the correct answer using the blockRegexes parameter.
I've tried checking for the validation exception but that doesn't work.
Here is my code:
import pyinputplus as p
import random, time
numberOfQuestions = 10
correctAnswers = 0
incorrectAnswers = []
#def blockRegRaiseExcep(text):
# because in a regular inputStr it won't raise an exception if I match the blocked regex.
for questionNumber in range(numberOfQuestions):
# Pick two random numbers:
num1 = random.randint(0,9)
num2 = random.randint(0,9)
prompt = f'#{questionNumber}: {num1} x {num2} = '
try:
# Right answers are handled by allowRegexes.
# Wrong answers are handled by blockRegexes, with a custom message.
inp = p.inputStr(prompt,allowRegexes=[f'^{num1 * num2}$'], # allow only the right number! great.
blockRegexes=[('.*','Incorrect!')], # we are blocking everything, basically, love it!
timeout=8, limit=3)
except p.TimeoutException:
print(f'Out of time!\nCorrect answer is {num1 * num2}')
except p.RetryLimitException:
print(f'Out of tries!\nCorrect answer is {num1 * num2}')
else:
# This block runs if no exceptions were raised by the try block.
print('Correct!')
correctAnswers += 1
time.sleep(1) # Brief pause to let the user read the result.
print(f'Score: {correctAnswers} / {numberOfQuestions}')
There are actually different ways you can achieve what you want.
There is an optional parameter applyFunc which is common to all input*() functions, see documentation or call help(pyip.parameters):
applyFunc (Callable, None): An optional function that is passed the user's input, and returns the new value to use as the input.
You can use this function to save the input and pass it on unaltered to the validation. If you only want to store the input in case it is incorrect, you need to check the condition again within this function.
Example:
import pyinputplus as p
import re
# hardcoded values for example
incorrectAnswers = []
questionNumber = 1
num1 = 2
num2 = 3
prompt = f'#{questionNumber}: {num1} x {num2} = '
def checkAndSaveInput(n):
if not (re.match(f'^{num1 * num2}$',n)):
incorrectAnswers.append(n)
return(n)
inp = p.inputStr(prompt,
allowRegexes=[f'^{num1 * num2}$'],
blockRegexes=[('.*','Incorrect!')],
applyFunc=checkAndSaveInput)
print("Your wrong answers were:")
for a in incorrectAnswers:
print(f' {a}')
Execution:
#1: 2 x 3 = six
Incorrect!
#1: 2 x 3 = 4
Incorrect!
#1: 2 x 3 = 5
Incorrect!
#1: 2 x 3 = 6
Your wrong answers were:
six
4
5
Since with the approach above, you need to check the condition again anyway, you could also directly write a custom inputCustom() function. The following example uses the regexes in allowRegexes and blockRegexes only to validate that an int is entered and the actual result checking is not done with a regex but instead with simple math. The difference to the approach above is that the values are actually only handed to the checking function after it is made sure that they match the pattern in allowRegexes.
import pyinputplus as p
# hardcoded values for example
incorrectAnswers = []
questionNumber = 1
num1 = 2
num2 = 3
prompt = f'#{questionNumber}: {num1} x {num2} = '
def checkAndSaveInput(n):
if((num1 * num2) != int(n)):
incorrectAnswers.append(n)
raise Exception('Incorrect.')
else:
print('Correct!')
inp = p.inputCustom(checkAndSaveInput,
prompt=prompt,
allowRegexes=[r'^\d+$'],
blockRegexes=[('.*','Please enter a valid number!')])
print("Your wrong answers were:")
for a in incorrectAnswers:
print(f' {a}')
Execution:
#1: 2 x 3 = six
Please enter a valid number!
#1: 2 x 3 = 4
Incorrect.
#1: 2 x 3 = 5
Incorrect.
#1: 2 x 3 = 6
Correct!
Your wrong answers were:
4
5

How to use python to find an angle in a SSS triangle via the cosine rule?

I am creating a massive calculator in python, but I have come a across an issue. I am trying to use the law of cosines to find the angle in an SSS triangle and I cannot see where i am going wrong.
elif qchoice5 == 4:
while True:
try:
print("======================================================================")
a = float(input("what is side a?"))
break
except ValueError:
print("======================================================================")
print("please enter a valid option")
while True:
try:
print("======================================================================")
b = float(input("what is side b?"))
break
except ValueError:
print("======================================================================")
print("Please enter a valid option")
while True:
try:
print("======================================================================")
c = float(input("what is side c?"))
break
except ValueError:
print("======================================================================")
print("Please enter a valid option")
print(((b**2)+(c**2)-(a**2))/(2*a*b))
ans = math.acos((((b**2)+(c**2)-(a**2))/(2*a*b)))
print(ans)
Whenever run it it gives the error
ans = math.degrees(math.acos((((b*b)+(c*c)-(a*a))/(2*a*b))))
ValueError: math domain error
Can anyone give me any pointers on how to get this working?
Without a valid MCVE, I can only do this from a QA standpoint. I see some problems:
You never validate your input. A non-triangle, such as sides of 2, 3, 100, will leave you taking acos of a value out of range.
Your computation is incorrect: b^2 + c^2 - a^2 would need to be divided by 2bc, not 2ab.
FYI, if you're working with integers in Python 2, you'll run into a problem: the division is integer division, and pretty much everything will return acos(0), which is math.pi/2
Try this to correct the last two problems (#2 and the integer division):
ans = math.acos((((b**2)+(c**2)-(a**2))/(2.0*b*c)))

Categories

Resources