Are there any use cases for raise foo, bar in Python? - python

Python 2 supports the following syntax for raise:
raise FooException(bar) # call
raise FooException, bar # positional
I thought that the positional syntax was just a historical result of old Python supporting arbitrary values as exceptions.
Are there any use cases for the positional syntax that can't be done (or are more verbose) with the call syntax?

I'm addressing the edited version of the question in my answer, mainly
However, even Python 3 considers raise Foo() and raise Foo to be equivalent.
The "call" syntax (raise Foo(obj)) will assign arbitrary object obj to the Exception object's args tuple attribute. While any object can be used as obj, this is mainly used for custom strings:
try:
raise ValueError('a custom string')
except ValueError as e:
print(e.args[0])
# 'a custom string'
print(e.args)
# ('a custom string',)
This args tuple is actually used when printing the exception object, so it is pretty handy for logging:
try:
raise ValueError('custom error', 2)
except ValueError as e:
print(e)
# ('custom error', 2)
raise ValueError() assigns an empty tuple to exc_obj.args, so does raise ValueError.
This even works with multiple objects. In this case we will get a tuple of same length:
try:
raise ValueError(1, 2, 3, 4)
except ValueError as e:
print(e.args)
# (1, 2, 3, 4)

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.

How to use raise ValueError?

I want to see ValueError 4 times but it is showing once, why the program cutting to search the other double numbers?
def isitDoubleorSingle(value):
if(value%2!=0):
raise ValueError("Number isn't double")
print(value)
list=[10,22,79,43,11,80]
for x in list:
isitDoubleorSingle(x)
This will solve your problem. You have to catch your Error in the except block or your script will stop running at your first raise ValueError()
edit: As #Nin17 said, you shouldn't redefine the built-in list, so renaming the list in my_list(or any name you want) should be better.
def isitDoubleorSingle(value):
try:
if(value%2!=0):
raise ValueError()
except ValueError:
print(f"Number {value} isn't double")
my_list=[10,22,79,43,11,80]
for x in my_list:
isitDoubleorSingle(x)
When you raise an exception, the program is already closed automatically, so it is not possible to display the ValueError more than once

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)

Handling multiple Try/Except statements

I am using multiple try/except blocks to assign values of a dataframe (say data) to 3 variables(say b,c,d) I want to handle IndexErrors if positional indexer is out-of-bounds. What I am currently doing is shown below:
b,c,d=None,None,None
try:
b=data.iloc[1,1]
except:
pass
try:
c=data.iloc[2,1]
except:
pass
try:
d=data.iloc[0,2]
except:
pass
I want to know if there is a better of doing this like a function try_except() or something so that I can use it as shown below:
try_except(b=data.iloc[1,1])
try_except(c=data.iloc[2,1])
try_except(d=data.iloc[0,2])
You could just write a function that performs a lookup and catches the exception, but incidentally, except: pass is probably a bad idea. You should be more specific with your error handling.
def safe_get(container, i, j):
try:
return container[i,j]
except IndexError: # or whatever specific error you're dealing with
return None
b = safe_get(data.iloc, 1, 1)
c = safe_get(data.iloc, 2, 1)
d = safe_get(data.iloc, 0, 2)

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