python try except 0 - python

I am reading some python code written a while ago, and found this:
try:
# do some stuff
except 0:
# exception handling stuff
And I'm just not sure what except 0 means? I do have my guesses: Supposed to catch nothing i.e. let the exception propagate or it could be some sort of switch to turn debugging mode on and off by removing the 0 which will then catch everything.
Can anyone lend some insight? a google search yielded nothing...
Thanks!
Some sample code (by request):
try:
if logErrors:
dbStuffer.setStatusToError(prop_id, obj)
db.commit()
except 0:
traceback.print_exc()

From what I understand, This is very useful for debugging purposes (Catching the type of exception)
In your example 0 acts as a placeholder to determine the type of exception.
>>> try:
... x = 5/1 + 4*a/3
... except 0:
... print 'error'
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
NameError: name 'a' is not defined
>>> try:
... x = 5/0 + 4*a/3
... except 0:
... print 'error'
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: integer division or modulo by zero
In the first case, the exception is NameError and ZeroDivisionError in the second.
the 0 acts as a placeholder for any type of exception being caught.
>>> try:
... print 'error'
... except:
...
KeyboardInterrupt
>>> try:
... x = 5/0 + 4*a/3
... except:
... print 'error'
...
error

From the Python docs:
"[...] the [except] clause matches the exception if the resulting object is “compatible” with the exception. An object is compatible with an exception if it is the class or a base class of the exception object, or a tuple containing an item compatible with the exception."
In effect the type of the expression is used to determine whether the except clauses matches the exception. As 0 is of an integer type, and exception of that type would match.
Since integers cannot be raised as exception, this is a disabled exceptclass that will not catch anything.

Related

Python2 vs Python3 : Exception variable not defined [duplicate]

This question already has an answer here:
Why do I get a `NameError` (or `UnboundLocalError`) from using a named exception after the `except` block?
(1 answer)
Closed last month.
I wrote this small snippet in python2 (2.7.18) to catch the exception in a variable and it works
>>> ex = None
>>> try:
... raise Exception("test")
... except Exception as ex:
... print(ex)
...
test
>>> ex
Exception('test',)
>>>
>>> ex2 = None
>>> try:
... raise Exception("test")
... except Exception as ex2:
... print(ex2)
... finally:
... print(ex2)
...
test
test
When I run the same in python3 (3.10.8), I get NameError
>>> ex = None
>>> try:
... raise Exception("test")
... except Exception as ex:
... print(ex)
...
test
>>> ex
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'ex' is not defined. Did you mean: 'hex'?
>>>
>>> ex2 = None
>>> try:
... raise Exception("test")
... except Exception as ex2:
... print(ex2)
... finally:
... print(ex2)
...
test
Traceback (most recent call last):
File "<stdin>", line 6, in <module>
NameError: name 'ex2' is not defined
What is the reason for this? Is the new python3 compiler doing optimisation where None assignment doesn't mean anything or is the try/except clause doing some magic?
What is the workaround for this which works in both python2 and python3?
It's not a magic really. It's documented here:
When an exception has been assigned using as target, it is cleared at the end of the except clause. This is as if:
except E as N:
foo
was translated to
except E as N:
try:
foo
finally:
del N
And the reason:
Exceptions are cleared
because with the traceback attached to them, they form a reference
cycle with the stack frame, keeping all locals in that frame alive
until the next garbage collection occurs.
You can get the traceback object with ex.__traceback__.
What is the workaround for this which works in both python2 and
python3?
You have to explicitly assign it to a different name(something other than target in as target as it's gonna get deleted):
exc_object = None
try:
raise Exception("test")
except Exception as ex:
print(ex)
exc_object = ex
print(exc_object)
Note: This is only the case with except block and has nothing to do with as assignment statement as you can see in context managers: with...as... block for example.

Why we could not catch Stopiteration exception in a generator definite function?

def simple_generator():
print("-> start ..")
try:
x = yield
print("-> receive {} ..".format(x))
except StopIteration:
print("simple_generator exit..")
I know that each call of next on the generator object runs the code until the next yield statement, and returns the yielded value. If there is no more to get, StopIteration is raised.
So I wanted to catch the StopIteration in function simple_generator as the code above. Then I tried:
>>>
>>> sg3 = simple_generator()
>>> sg3.send(None)
-> start ..
>>> sg3.send("hello generator!")
-> receive hello generator! ..
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
It did throw StopIteration while the try ...excep dit not catch it at all, I could not understand what's underlying reason, could anyone explain that? Thanks in advance.
Of course, I also knew that if I dealed with the StopIteration exception outside function simple_generator, it did work as what I expected, for example.
>>> try:
... sg4 = simple_generator()
... while True:
... next(sg4)
... except StopIteration:
... print("sg4 exit ..")
...
-> start ..
-> receive None ..
sg4 exit ..
>>>
So my question is Why we could not catch Stopiteration exception in a generator definite function?

Value Error and String exception

I am having issues with a ValueError working the way I want.
I have a function that is returning a string but I do not want it too evaluate to a ValueError if it is not raised from the function
Sample Code
def test(a):
if a == a:
raise ValueError('There was a error # 2')
a = 'a'
if ValueError:
print "There was a error # 1"
test(a)
Output
There was a error # 1
Traceback (most recent call last):
File "/home/user/Test_1.py", line 13, in <module>
test(a)
File "/home/user/Test_1.py", line 5, in test
raise ValueError('There was a error # 2')
ValueError: There was a error # 2
Process finished with exit code 1
If I read the docs correctly it said it can be raised by a string, how do i prevent this behavior?
https://docs.python.org/2/library/exceptions.html#exceptions.IndexError
Not sure why it was working before but I made it more explicit and it works now. Also the first example was more vague and I was trying to catch error from a function that was in the library.
Sample Code
def test(a):
try:
if a == a:
pass
raise ValueError('There was a error # 2')
except Exception, e:
str(e)
return e
a = 'a'
b = test(a)
if type(b) == ValueError:
print b
Output
There was a error # 2
Process finished with exit code 0

Python: try except else Strange behavior

When I execute the following code, I am getting an exception instead of normal behavior.
try:
fun1(1)
fun1(1)
except Exception as e:
print "exception"
else:
print "hi"
def fun1(i):
if i == 0:
raise Exception()
else:
print "no exception"
The above code doesn't have any exceptions, so instead of printing "no exception" it shows "exception" as output.
You do have an exception; you are catching the NameError exception (which is a subclass of Exception). You get that exception because fun1 doesn't exist yet.
Move the fun1() definition to before the try..except or move that code into a function you call after fun1() has been created.
You'd also be better off with using a less-generic exception, it'd would have made the problem apparent much earlier; you could use ValueError if you want to test things, it is far less likely to be thrown for unrelated issues:
>>> try:
... fun1(1)
... fun1(1)
... except ValueError:
... print "exception"
... else:
... print "hi"
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
NameError: name 'fun1' is not defined
>>> def fun1(i):
... if i == 0:
... raise ValueError()
... else:
... print "no exception"
...
>>> try:
... fun1(1)
... fun1(1)
... except ValueError:
... print "exception"
... else:
... print "hi"
...
no exception
no exception
hi
>>> try:
... fun1(0)
... except ValueError:
... print "exception"
... else:
... print "hi"
...
exception

How to re-raise an exception in nested try/except blocks?

I know that if I want to re-raise an exception, I simple use raise without arguments in the respective except block. But given a nested expression like
try:
something()
except SomeError as e:
try:
plan_B()
except AlsoFailsError:
raise e # I'd like to raise the SomeError as if plan_B()
# didn't raise the AlsoFailsError
how can I re-raise the SomeError without breaking the stack trace? raise alone would in this case re-raise the more recent AlsoFailsError. Or how could I refactor my code to avoid this issue?
As of Python 3, the traceback is stored in the exception, so a simple raise e will do the (mostly) right thing:
try:
something()
except SomeError as e:
try:
plan_B()
except AlsoFailsError:
raise e # or raise e from None - see below
The traceback produced will include an additional notice that SomeError occurred while handling AlsoFailsError (because of raise e being inside except AlsoFailsError). This is misleading because what actually happened is the other way around - we encountered AlsoFailsError, and handled it, while trying to recover from SomeError. To obtain a traceback that doesn't include AlsoFailsError, replace raise e with raise e from None.
In Python 2 you'd store the exception type, value, and traceback in local variables and use the three-argument form of raise:
try:
something()
except SomeError:
t, v, tb = sys.exc_info()
try:
plan_B()
except AlsoFailsError:
raise t, v, tb
Even if the accepted solution is right, it's good to point to the Six library which has a Python 2+3 solution, using six.reraise.
six.reraise(exc_type, exc_value, exc_traceback=None)
Reraise an exception, possibly with a different traceback.
[...]
So, you can write:
import six
try:
something()
except SomeError:
t, v, tb = sys.exc_info()
try:
plan_B()
except AlsoFailsError:
six.reraise(t, v, tb)
As per Drew McGowen's suggestion, but taking care of a general case (where a return value s is present), here's an alternative to user4815162342's answer:
try:
s = something()
except SomeError as e:
def wrapped_plan_B():
try:
return False, plan_B()
except:
return True, None
failed, s = wrapped_plan_B()
if failed:
raise
Python 3.5+ attaches the traceback information to the error anyway, so it's no longer necessary to save it separately.
>>> def f():
... try:
... raise SyntaxError
... except Exception as e:
... err = e
... try:
... raise AttributeError
... except Exception as e1:
... raise err from None
>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 9, in f
File "<stdin>", line 3, in f
SyntaxError: None
>>>

Categories