Python exception handling context attribute - python

I'm learning about exception handling in python and am a little stumped how exactly the context attribute works, or at least why the code I have written produces the outcome it does.
My understanding is that when an exception,E, is raised implicitly during the handling of another exception,P, the exception's E context attribute will store a reference to P.
So I have set up the following code:
def g():
try: 1/0
except Exception as E:
print('E context', E.__context__)
try: raise Exception
except Exception as J:
print('J context', J.__context__)
try: raise Exception
except Exception as M:
print('M context', M.__context__)
try: raise Exception
except Exception as T:
print('T context', T.__context__)
The output I get is:
E context None
J context division by zero
M context
T context
What I was expecting to see was M context and T context to have references to previous exceptions, but that doesn't seem to be the case. Would appreciate knowing where I am going wrong on my thinking on this.

Since you raised a blank exception, print(M.__context__) outputs an empty string (because str(Exception()) is an empty string).
Consider this:
try:
1/0
except Exception as E:
print('E context', E.__context__)
try:
raise Exception('non blank 1')
except Exception as J:
print('J context', J.__context__)
try:
raise Exception('non blank 2')
except Exception as M:
print('M context', M.__context__)
Outputs
E context None
J context division by zero
M context non blank 1

Related

How can I catch an exception raised inside of a catch clause, If the finally clause corresponding to the catch clause contains a return statement?

Suppose that:
TEF is a try-except-finally block.
an exception is raised from within the try clause of TEF
The finally clause, F of block T contains a return statement
TEF contains an except clause E
an exception e is raised inside of E
How can we catch e from outside of clause F and outside of clause E?
If that was confusing, then some code is shown below:
def e():
out = "hello world"
try:
raise ValueError("my name is Sarah")
except BaseException as exc:
# HOW DO I CATCH THE FIRST OF THE FOLLOWING
# exceptions from outside of this, current,
# except clause?
raise ValueError("secret info it would be good to know")
raise AttributeError
raise type("Hell", (Exception,), dict())()
[0, 1, 2][99999]
class AnythingYouCanThinkOf(Exception):
pass
raise AnythingYouCanThinkOf
out = "definitely not `hello world`"
finally:
return out
print(e())
print("No error!!! wowza!")
The code above prints:
hello world
No error!!! wowza!
If we comment out the line out = "hello world" then we get UnboundLocalError: local variable 'out' referenced before assignment. However, I am still not sure how to recover ValueError("secret info it would be good to know")
Also, if you put almost the same code outside of the function e, you get very different results. Why?
if True:
out = "hello world"
try:
raise ValueError("my name is Bob")
except BaseException as exc:
# HOW DO I CATCH THE FIRST OF THE FOLLOWING
# exceptions from outside of this, current,
# except clause?
raise ValueError("what is this madness?")
class AnythingYouCanThinkOf(Exception):
pass
raise AnythingYouCanThinkOf
out = "definitely not `hello world`"
finally:
print(out)
The above results in unhandled exception ValueError: what is this madness? before, we got No error!!! wowza!

Why dose preceding list assignment cause break statement not to execute?

I have come across a strange behavior using the python break statement within a try-except block.
i=0
lst=[]
while i < 5:
try:
if i < 3:
raise Exception('spam', 'eggs')
#lst[0]=i
print('-'+str(i)+'-')
break
except:
i=i+1
print(str(i)+' ',end='')
1 2 3 -3-
But if I remove the commented line:
i=0
lst=[]
while i < 5:
try:
if i < 3:
raise Exception('spam', 'eggs')
lst[0]=i
print('-'+str(i)+'-')
break
except:
i=i+1
print(str(i)+' ',end='')
1 2 3 4 5
Why has the list assignment caused the break to no longer happen? Can someone explain what is going on here.
lst is an empty list. Attempting to access elements that do not exist, such as lst[0] will raise an IndexError exception. That exception is then caught in the exception handler, corrupting your expected results.
First of all, you generally should not use bare exception handlers; restrict your exception handler to those exceptions that it knows how to handle. Unrestricted exception handlers make it possible for unexpected exceptions to be hidden, as is the case here.
If you want to store the index in lst either make sure that your list is long enough, or use append() or insert() to add it to the end or at the beginning of the list.
Using Exception to create your own exceptions is often not the best thing to do either because it makes it difficult to distinguish your exception from others:
for i in range(2):
try:
if i == 0:
raise Exception('spam', 'eggs')
else:
1/0 # cause ZeroDivisionError
except Exception as e:
print(repr(e))
Running that code outputs:
Exception('spam', 'eggs')
ZeroDivisionError('division by zero',)
Because ZeroDivisionError is a subclass of Exception it is also caught by the handler. To solve this you can create your own Exception subclass:
class MyException(Exception):
pass
Now you can easily check for the exception that you know how to handle:
for i in range(2):
try:
if i == 0:
raise MyException('spam', 'eggs')
else:
1/0 # cause ZeroDivisionError
except MyException as e:
print(repr(e))
Running this code:
MyException('spam', 'eggs')
Traceback (most recent call last):
File "", line 6, in
ZeroDivisionError: division by zero
shows that your custom exception is caught and handled, but unexpected exceptions are not. If you want to handle the unexpected ones too then add a second exception handler after the first:
except MyException as e:
print(repr(e))
except Exception as e:
print('Unexpected exception', e)
raise
If you treat the exception:
i=0
lst=[]
while i < 5:
try:
if i < 3:
raise Exception('spam', 'eggs')
lst[0]=i
print('-'+str(i)+'-')
break
except Exception as e:
print(e)
i=i+1
print(str(i))
You will realize that you get an IndexError:
list assignment index out of range
since your list is empty, you can not access/assign at that index. If you want to insert items to the list use append:
lst.append(i)
or insert:
lst.insert(0, i)
depending on what you want to do. Read more here.

Why is the Exception not printing?

In the REPL, I can print the string representation of an exception:
>>> print(str(ValueError))
<class 'ValueError'>
>>> print(ValueError)
<class 'ValueError'>
In this simple code, the value is not printing. What am I missing?
First flavor:
try:
raise ValueError
except Exception as e:
print(str(e))
print('We crashed!')
This just outputs We crashed!
The second flavor outputs the same. What happened to print(str(e))?
Second flavor:
def crash():
raise ValueError
try:
crash()
except Exception as e:
print(str(e))
print('We crashed!')
In the REPL, I can print the string representation of an exception:
>>> print(str(ValueError))
<class 'ValueError'>
No, you're printing the string representation of an exception class. When you do
raise ValueError
ValueError isn't actually the exception object that gets raised. Python implicitly raises ValueError() instead, and the str of that is empty.
It does print the exception message, but you have to look closely:
>>> def crash():
... raise ValueError
>>> try:
... crash()
... except Exception as e:
... print(str(e))
... print('We crashed!')
We crashed!
The empty line in front of "We crashed" is the error message (empty string) you supplied when doing raise ValueError. To have the representation of your exceptions use repr instead of str:
>>> try:
... crash()
... except Exception as e:
... print(repr(e))
... print('We crashed!')
ValueError()
We crashed!
Note that raise ValueError is just a shorthand for raise ValueError() (note the paranthesis).
You're not supplying any args to the instance that is eventually created, there's nothing to print.
Supply the message that will eventually get printed out by initializing and supplying it as an argument:
try:
raise ValueError("What value error?")
except Exception as e:
print(str(e))
print('We crashed!')
What value error?
We crashed!
Also, though I know this is just a demonstration, I am obliged to point out that using Exception as the target in your handlers is bad practice :-)
As in user2357112 's answer in your except block your are trying to print an instance of ValueError not the ValueError class. If you want to print the class try something like below.
try:
raise ValueError
except Exception as e:
print(e.__class__)
print('We crashed!')

Catch exception gets UnboundLocalError

I wrote a crawler to fetch information out of an Q&A website. Since not all the fields are presented in a page all the time, I used multiple try-excepts to handle the situation.
def answerContentExtractor( loginSession, questionLinkQueue , answerContentList) :
while True:
URL = questionLinkQueue.get()
try:
response = loginSession.get(URL,timeout = MAX_WAIT_TIME)
raw_data = response.text
#These fields must exist, or something went wrong...
questionId = re.findall(REGEX,raw_data)[0]
answerId = re.findall(REGEX,raw_data)[0]
title = re.findall(REGEX,raw_data)[0]
except requests.exceptions.Timeout ,IndexError:
print >> sys.stderr, URL + " extraction error..."
questionLinkQueue.task_done()
continue
try:
questionInfo = re.findall(REGEX,raw_data)[0]
except IndexError:
questionInfo = ""
try:
answerContent = re.findall(REGEX,raw_data)[0]
except IndexError:
answerContent = ""
result = {
'questionId' : questionId,
'answerId' : answerId,
'title' : title,
'questionInfo' : questionInfo,
'answerContent': answerContent
}
answerContentList.append(result)
questionLinkQueue.task_done()
And this code, sometimes, may or may not, gives the following exception during runtime:
UnboundLocalError: local variable 'IndexError' referenced before assignment
The line number indicates the error occurs at the second except IndexError:
Thanks everyone for your suggestions, Would love to give the marks that you deserve, too bad I can only mark one as the correct answer...
In Python 2.x, the line
except requests.exceptions.Timeout, IndexError:
is equivalent to
except requests.exceptions.Timeout as IndexError:
Thus, the exception caught by requests.exceptions.Timeout is assigned to IndexError. A simpler example:
try:
true
except NameError, IndexError:
print IndexError
#name 'true' is not defined
To catch multiple exceptions, put the names in parentheses:
except (requests.exceptions.Timeout, IndexError):
Later, an UnboundLocalError can occur because the assignment to IndexError makes it a local variable (shadowing the builtin name):
>>> 'IndexError' in answerContentExtractor.func_code.co_varnames
True
So, if requests.exceptions.Timeout was not raised, IndexError will not have been (incorrectly) defined when the code attempts except IndexError:.
Again, a simpler example:
def func():
try:
func # defined, so the except block doesn't run,
except NameError, IndexError: # so the local `IndexError` isn't assigned
pass
try:
[][1]
except IndexError:
pass
func()
#UnboundLocalError: local variable 'IndexError' referenced before assignment
In 3.x, the problem will occur (after fixing the except syntax, which makes the error more obvious) even if the first exception is caught. This is because the local name IndexError will then be explicitly deld after the first try/except block.
When you say
except requests.exceptions.Timeout ,IndexError:
Python will except requests.exceptions.Timeout error and the error object will be IndexError. It should have been something like this
except (requests.exceptions.Timeout ,IndexError) as e:
except requests.exceptions.Timeout ,IndexError:
means same as except requests.exceptions.Timeout as IndexError
You should use
except (requests.exceptions.Timeout, IndexError):
instead

What does except really do in Python?

I'm really new in Python and a have no experience with exceptions but I've read all the documentation and couldn't find an answer ... so I'm looking for a deeper view in except's semantics.
When we have for example:
try:
x = 2
except GreaterThanOne:
print("The value is greater than one")
In this case I want the message to be printed.Is there a way for the GreaterThanOne class(exception) to be defined to raise when the entered value is greater than one ?
Ok, let me be more specific ...
Every error raises by a specific rule which should be add in the error attributes, am I right ?
For example:
try:
myvalue = x / y
except ZeroDivisionError:
print("Some error message printed ...")
So when I use this code and enter for y to be 0 the exception ZeroDivisionError will raise ... Can I for example redefine ZeroDivisionError to raise like this but if y is set to be ... 2 or 3 or any other value ?
Input:
x = 10
y = 2
try:
myvalue = x / y
except ZeroDivisionError:
print("division by 2")
Output: division by 2
Here's an example that should help you understand. Run this in your Python interpreter and watch how the exception is raised and caught (or not caught) when you call set_val(2).
# Defining our Exception subclass:
class GreaterThanOne(Exception):
pass
# The global value we pretend to care about:
val = 0
# Function to set a value but possibly raise our new Exception
def set_val(new_val):
if new_val > 1:
raise GreaterThanOne("%d > 1" % new_val)
val = new_val
# Catching exception:
try:
set_val(0)
set_val(1)
set_val(2)
except GreaterThanOne:
print "Whoops - one of those values was greater than one"
# Not catching exception:
set_val(0)
set_val(1)
set_val(2)
set_val(3)
an try-except block catches exception in this block.
try:
#some stuff here
except ExceptionClass as e:
#Exception handling here
the class after the except keyword indicates which kind of exception you want to catch. Usually you give a specific class, like ValueError or KeyError. You can also use the Exception class, to catch any exception. Because all the other exceptionclasses inhert from Exception.
so if you want to use this construct, an exception needs to be raised, Either by a function / method you call, or you raise it yourself with the raise keyword.
like this:
try:
raise KeyError('Just for test')
except KeyError as e:
#Exception handling here
The try except doesn't automagically inspect the whole code between it, it just looks for exceptions... Or to be more specific, it looks for those exceptions you tell it to look for.
Of course you can also inspect the exception instance.
try:
raise KeyError('Just for test')
except KeyError as e:
print e.args
For more information, please see:
http://docs.python.org/2/tutorial/errors.html

Categories

Resources