writing a function that catches multiple exceptions in python - python

I am required to write a function that takes a simple mathematical formula as a string as an argument. The function should then return the result of that formula. For example, for the input "2 + 3" the function should return 5.
A string is considered a valid formula if it has the format . Note that operator and integer are separated by whitespace.
A valid operator is either +, -, * or /
If a string doesn't consist of three parts (integer operator integer), the function should raise a ValueError with the message "Formula must be of the following format: ."
If the first part or the last part of the input string can't be converted to integers, the function should raise a ValueError with the message "Expected two integers."
If the second part of the string is not one of the valid operators, the function should raise a ValueError with the message "Invalid operator ''. Expected one of these operators: +, -, *, /."
If the second integer is zero and the operator is /, the function should raise a ZeroDivisionError with the message "Division by zero not possible."
So far I've managed to split the string by whitespace and convert the [0] and [2] indexes to integers to be used in solving the respective mathematical equations, and I've also written a try: except: block that successfully catches invalid operators and returns the desired error message. My problem is going on to accommodate the other exceptions as outlined in the conditions, although I've written code that attempts to catch the exceptions and print the relevant error messages, it isn't working and I'm still getting the default internal python error messages. I'm assuming something in my approach is off, maybe the order that the try: except blocks are written in? something with the indenting? I'm new to this so any pointers or advice would be much appreciated.
def formula_from_string(formula):
valid_operators = '+-*/'
chopped=formula.split()
equa=int(chopped[0]),chopped[1],int(chopped[2])
subtraction=equa[0]-equa[2]
addition=equa[0]+equa[2]
division=equa[0]/equa[2]
multiplication=equa[0]*equa[2]
if chopped[1]=='+':
return(addition)
elif chopped[1]=='-':
return(subtraction)
elif chopped[1]=='*':
return(multiplication)
elif chopped[1]=='/':
return(division)
try:
if chopped[1] not in valid_operators:
invalid=chopped[1]
raise ValueError
except ValueError:
print('Value Error:')
return("Invalid operator '"+invalid+"'. Expected one of these operators: +, -, *, /.")
try:
if chopped[0] or chopped[2] != int:
raise ValueError
except ValueError:
print('Value Error:')
return('Expected two integers.')
try:
if equa[1]=='/' and equa[2]==0:
raise ZeroDivisionError
except ZeroDivisionError:
print('ZeroDivisionError:')
return('Division by zero not possible.')
try:
if chopped <=1 or chopped >=2:
raise ValueError
except ValueError:
print('ValueError:')
return('Formula must be of the following format: <integer> <operator> <integer>.')

This code should helps you.
learn about Regex (Regular Expressions)
See Regular expression operations
import re
def formula_from_string(formula):
valid_operators = '+-*/'
pattern = re.compile(r'^(\d+)(?:\s+)?([*/+\-^])(?:\s+)?(\d+)$')
try:
if match := pattern.search(formula):
operator = match.group(2)
if operator not in valid_operators:
raise ValueError(f"Invalid operator {repr(operator)}. Expected one of these operators: +, -, *, /.")
else:
raise ValueError('Formula must be of the following format: <integer> <operator> <integer>.')
return eval(formula) # Safe call
except (ValueError, ZeroDivisionError) as e:
print(e)
# Uncomment to see output
# formula_from_string('3 / 2') # 1.5
# formula_from_string('3 ^ 2') # ValueError Invalid operator
# formula_from_string('a / 2') # ValueError Formula must be...
# formula_from_string('3 / 0') # ZeroDivisionError

Related

Unable to Catch Exception and Raise Error in Python

Suppose that I have a variable initial_cash = 'a'. I want to check if this is convertible to float else I want to raise error for that I've written code below:
initial_cash = 'a'
try:
initial_cash = float(initial_cash)
except TypeError:
raise TypeError("Initial cash amount should be float or int")
I am unable to raise exception instead I get ValueError: could not convert string to float: 'a'. What am I doing wrong due to which the expectation is not caught?
Your answer is in the error message - ValueError. you should expect ValueError instead of TypeError.

Why am I getting an error when trying to compare to dictionary values?

I'm supposed to:
Write a function, precipiation(d, a, b) that takes parameters:
d: Dictionary mapping a season to an amount of precipitation for that season.
a: One season
b: Another season
Your function should return True if the rainfall in season a was greater than it was in season b, and False otherwise. If the rainfall was equal, return False.
Your function should handle the following errors the following ways:
If either a or b is not a valid season in the dictionary, you should return an error message (as a string) formatted exactly as:
"Error: Key is not in Dictionary."
If the values for the rainfall in each season are not valid for comparison, that is, one of them is not a number, return an error message (as a string) formatted exactly as:
"Error: Invalid data types in Dictionary?"
You may assume that no test case will produce both types of errors (so you do not need to decide whether or not to return a Key Error or Invalid Type error when you encounter both). However, you should not make any assumptions about the seasons that exist--sometimes there may be a 'potato' season.
I wrote a function that is mostly correct
def precipitation(d, a, b):
try:
if d[a] > d[b]:
return True
else:
return False
except:
if a not in d or b not in d:
return ("Error: Key is not in Dictionary.")
if d[a] not in (int) or d[b] not in (int):
return ("Error: Invalid data types in Dictionary?")
When I run this function with test case
precipitation({"Spring": 'cats', "Summer": 313, "Fall": 1457, "Winter": 354}, "Summer", "Spring") == 'Error: Invalid data types in Dictionary?'
I get an error
argument of type 'type' is not iterable
How can I fix this and what is causing the problem
This is your problem:
if d[a] not in (int)
int is not a container, it's a type, so d[a] can't be in it.*
Are you trying to make sure it's an integer? Then try isinstance():
if not isinstance(d[a], int) ...
* You could write a metaclass that had a __contains__() method that let you treat types as containers and check for instance types in this way, which is actually a kind of interesting idea, but int does not do that.
In addition to the correct answers already provided,
since you are using try and except, you can also specify the type of exception for each block as well:
def precipitation(d, a, b):
try:
return d[a] > d[b]
except KeyError:
return "Error: Key is not in Dictionary."
except TypeError:
return "Error: Invalid data types in Dictionary?"
To check if a parameter is a specific type, use isinstance - in checks if a specific value is present in an iterable.
if not isinstance(d[a], int) or not isinstance(d[b], int):
return ("Error: Invalid data types in Dictionary?")
use this as this is exact way of error handling
if ValueError:
return ("Error: Invalid data types in Dictionary?")
instead of
if if d[a] not in (int) or d[b] not in (int):
return ("Error: Invalid data types in Dictionary?")

Exception handling is ignored with try-except around a function definition

My message "Divide by 0 error" is not going through, instead I'm getting a normal ZeroDivisionError.
#!/usr/bin/python
t = raw_input("do you want to play a game?[y/n]" )
#r = raw_input("Please enter a number")
#e = raw_input("Please enter a number again")
try:
def di (a, b):
return a/b
except ZeroDivisionError:
print "Divide by 0 Error"
while t == "y":
u = raw_input("Please enter / sign ")
if u == "/":
r = int(raw_input("Please enter a number"))
try:
e = int(raw_input("Please enter a number again"))
print "the answer is", di(r, e)
t = raw_input("do you want to play a game?[y/n]" )
except ValueError:
t = raw_input( "Invalid input, must be a number. Press yes to continue, no stop")
Look at the code more closely:
try:
def di (a, b):
return a/b
except ZeroDivisionError:
print "Divide by 0 Error"
Your try/except block includes the entire function definition: it applies specifically to defining the function. There is no exception block active while the function is executing from a call.
Use this instead:
def di (a, b):
try:
return a/b
except ZeroDivisionError:
print "Divide by 0 Error"
My take on this question (clearly interesting enough to provoke multiple answers, well done) is to remember that in Python class and function definitions are executed like most other statements.
try:
def di (a, b):
return a/b
except ZeroDivisionError:
print "Divide by 0 Error"
says:
"Attempt to define a function called di that returns the dividend of its arguments. If defining the function raises a ZeroDivisionError exception, print an explanatory message." No exception will be raised.
I suspect what is required is instead:
"Define a function that attempts to return the dividend of its arguments. If the division raises a ZeriDivisionError exception the function prints an explanatory message and returns None." So the def should be around the whole function's logic:
def di(a, b):
try:
return a/b
except ZeroDivisionError:
print "Divide by 0 error"
As a more general point of program design, such a function is somewhat badly-coupled. Python programmers would probably conclude, unless constrained by other factors, that it was simpler to leave the exception uncaught: presumably the caller currently has to test for None to determine whether an exception occurred, so why not just trap the exception wherever it actually has to be handled, and handle it there?
Indicating the invalidity of data by returning an object of a different type makes for complex and hard-to-read code, and is probably best avoided in the long term. Perfectly acceptable for a learning exercise, though!
TLDR: Move the exception handler into the function, where the exception actually occurs:
def di(a, b):
try:
return a/b
except ZeroDivisionError:
print("Divide by 0 Error")
Function definitions in Python are executed, and this execution can have side-effects -- such as modifying objects or raising exception. However, on definition only the function signature is run immediately; the body is stored and only run when the function is called.
>>> def func(arg=print("default evaluated")):
... print("body evaluated")
...
default evaluated
>>> func
<function __main__.func(arg=None)>
>>> func()
body evaluated
When you define a function inside an exception handler, this exception handler only receives exceptions raised from evaluating the signature. For example, computing a default argument may raise a ZeroDivisionError:
>>> def invalid_def(arg=10/0):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
An exception handler for this case is rarely what you want. It can be useful to conditionally define a function, e.g. if a NameError indicates a dependency is not available.
Commonly you want to handle an exception originating in the body of a function. These are raised whenever the function is actually called:
>>> def invalid_call():
... return 10 / 0
...
>>> invalid_call()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in invalid_call
ZeroDivisionError: division by zero
>>> invalid_call()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in invalid_call
ZeroDivisionError: division by zero
There are two ways to handle such exceptions: externally or internally.
External handling requires an exception handler at each call site. This is more flexible but requires boilerplate, since it requires an exception handler for each call.
>>> try:
... invalid_call()
... except ZeroDivisionError:
... print("suppressed an external error")
Internal handling requires an exception handler in the body. This is less flexible but needs no boilerplate, since one exception handler covers all cases.
>>> def valid_call():
... try:
... return 10 / 0
... except ZeroDivisionError:
... print("suppressed an internal error")
Both approaches are valid; which to select depends on whether you rather need usability or re-usability. Notably, it is not uncommon to combine both approaches: an internal handler generalises the exception, and external handler expects only general exceptions.
For example, in your case that would allow to handle multiple operations:
def div(a, b):
try:
return a / b
# convert operation-specific exception to general one
except ZeroDivisionError:
raise ValueError("Cannot divide by 0")
# may be another operation -- add, mul, sub, ...
operation = div
try:
operation(10, 0)
# only handle exception general to all operations
except ValueError as err:
print("Invalid values: %s" % err)

Try Except float but not integer

So, I've approached an obstacle in a programming exercise. I understand the concept of try except but how can I use a try except handler to only accept a float or decimal and if a whole number or integer is entered, it throws an error message. I know in theory it's not possible but is there a way?
Ideally I want to use a try except block of code as that's the current lesson I am on.
Thanks to all in advance!
How about using .is_integer() on float?
>>> float(5).is_integer()
True
>>> float(5.12).is_integer()
False
>>>
so
if float(x).is_integer():
raise ValueError('Non integers please')
There are good answers here, but so far the answers do not use try/except as requested. To use try except, you need try something that will throw an exception if false and then catch the exception.
try:
x / (x - int(x))
except ZeroDivisionError:
raise Exception("No integers allowed.")
if type(variable) is not float:
raise ValueError('Invalid number provided')
OR
if type(variable) is int:
raise ValueError('Invalid number provided')
OR (to check if whole number):
if abs(variable) - floor(abs(variable)) < 1.0e-9:
raise ValueError('Invalid number provided')
you can check the number against types.
# add or remove types from the list
if type(num) in (float, int, Decimal):
do something

How to better write multiple exceptions with redundant code in Python?

How can I better write the following snippet in Python:
try:
statement-1
except Exception1:
codeblock-1
codeblock-2
except Exception2:
codeblock-2
Just to be clear, I want to execute two codeblocks when the first exception occurs, while only the latter of these two codeblocks when the second exception occurs.
You have two options, as I see it; either:
Extract codeblock-2 into a function and just call it (you repeat only one line this way); or
Catch both exceptions in the same except, then handle the two cases appropriately by checking the type of the caught exception.
Note that these aren't mutually exclusive, and the second approach is probably more readable if combined with the first. A snippet of the latter:
try:
statement-1
except (Exception1, Exception2) as exc:
if isinstance(exc, Exception1):
codeblock-1
codeblock-2
In action:
>>> def test(x, y):
try:
return x / y
except (TypeError, ZeroDivisionError) as exc:
if isinstance(exc, TypeError):
print "We got a type error"
print "We got a type or zero division error"
>>> test(1, 2.)
0.5
>>> test(1, 'foo')
We got a type error
We got a type or zero division error
>>> test(1, 0)
We got a type or zero division error
I would just straightforwardly use local function:
def exception_reaction():
codeblock2()
try:
statement1()
except Exception1:
codeblock1()
exception_reaction()
except Exception2:
exception_reaction()

Categories