What does except really do in Python? - 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

Related

Python: Raise exception but not from sub functions

Is it possible in Python, to catch an exception at the current function level, but not from called sub functions?
Please consider this example:
def func(some_dict):
print(some_dict["special_value"])
some_dict = {
"general_value": True,
# "special_value": True
}
try:
if some_dict["general_value"]:
func(some_dict)
except KeyError:
print("General value not set")
I would like to catch the KeyError that if some_dict["general_value"]: might throw, but raise any KeyErrors from within func(...)
However, the example above will show General value not set although the key general_value is set.
I can think of the following workaround, but I'm wondering if there's a better way
temp_value = None
try:
temp_value = some_dict["general_value"]
except KeyError:
print("General value not set")
if temp_value:
func(some_dict)
Another way to ask this question: Is it possible to exclude certain parts within a try/except block from being caught?
Your workaround is the right general idea, but can be done more neatly as:
try:
some_dict["general_value"]
except KeyError:
print("General value not set")
else:
func(some_dict)
or perhaps:
if "general_value" in some_dict:
func(some_dict)
else:
print("General value not set")
which seems a little clearer to me.
you could use a nested try/except - but this is not recommended.
try:
if some_dict["general_value"]:
try:
func(some_dict)
except KeyError:
print("special error")
except KeyError:
print("general value not set")

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.

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

nested try/except in Python

try:
commands
try:
commands
try:
commands
try:
commands
except:
commands
return to final commands
except:
commands
return to final commands
except:
commands
return to final commands
except:
commands
final commands
Which instruction have I to write in place of return to final commands to make that any except returns to the top-level instructions following the outer try? And is it an acceptable structure?
Edit: Here is a toy example (I know I can do it using ifs, it's only an example; suppose you have to write it using try/except).
# calculate arcsin(log(sqrt(x)-4))
x = choose one yourself
try
x1=sqrt(x)
return to final message
try
x1=log(x1-4)
return to final message
try
x2=arcsin(x1)
return to final message
except
message="Impossible to calculate arcsin: maybe an argument outside [-1,+1]?"
except
message="Impossible to calculate logarithm: maybe a not positive argument?"
except
message="impossible to calculate square root: maybe a negative argument?"
final message:
print message
At the very least you should be able to reduce this structure to only 2 nested levels by reraising the exception to avoid the rest of the block:
# calculate arcsin(log(sqrt(x)-4))
x = ?
message = None
try:
try:
x1 = sqrt(x)
except Exception:
message = "can't take sqrt"
raise
try:
x1 = log(x1-4)
except Exception:
message = "can't compute log"
raise
try:
x2 = arcsin(x1)
except Exception:
message = "Can't calculate arcsin"
raise
except Exception:
print message
Really, this is not the way to do it, at least in this example. The problem is that you are trying to use exceptions like return error codes. What you should be doing is putting the error message into the exception. Also, normally the outer try/except would be in a higher level function:
def func():
try:
y = calculate_asin_log_sqrt(x)
# stuff that depends on y goes here
except MyError as e:
print e.message
# Stuff that happens whether or not the calculation fails goes here
def calculate_asin_log_sqrt(x):
try:
x1 = sqrt(x)
except Exception:
raise MyError("Can't calculate sqrt")
try:
x1 = log(x1-4)
except Exception:
raise MyError("Can't calculate log")
try:
x2 = arcsin(x1)
except Exception:
raise MyError("Can't calculate arcsin")
return x2

Categories

Resources