def FancyDivide(numbers, index):
try:
try:
denom = numbers[index]
for i in range(len(numbers)):
numbers[i] /= denom
except IndexError, e:
FancyDivide(numbers, len(numbers) - 1)
else:
print "1"
finally:
print "0"
except ZeroDivisionError, e:
print "-2"
Function Output
>>> FancyDivide([0, 2, 4], 0)
0
-2
I expect only -2 as the answer but why 0. According to me ZeroDivisionError should be caught by last except statement and therefore the answer should be -2. Confused. Please Help.
The finally block will execute regardless of if an Exception is thrown or not.
With your code throwing the exception inside the nested try, the associated finally block will execute before the outer except.
You're right, the ZeroDivisionError will be caught by the outer try block, but finally clauses are always executed before leaving their respective try block (even when an exception is raised within it).
So in your case, the inner try raises the exception, the inner finally is executed, then the outer try catches the exception.
More info here: https://docs.python.org/2/tutorial/errors.html#defining-clean-up-actions
Related
I only want my list to have one element in it. There should be one exception raised if the list is empty and a different exception raised if the list has more than one element.
The following code accomplishes the task, but I don't think it's written as well as it should by any standards out there. Additionally, if the condition is met that the list is greater than one, I want it to print the python error "index out of range" as it does in the other condition. How can I improve upon this?
x = []
try:
if len(x) > 1:
raise Exception
else:
testVar = x[0]
except IndexError as e:
print(e)
print("list does not have any elements.")
except Exception as e:
print(e)
print("There are too many elements in the list.")
Here is a better way to write that.
def func(x):
if not x:
print("list does not have any elements.")
return None
if len(x) > 1:
print("There are too many elements in the list.")
return None
return x[0]
Note that if we omit the first three lines, then Python will automatically raise an IndexError when you refer to x[0].
I'm having trouble understanding the following:
import sys
def f(n):
try:
print('try', n)
f(n + 1)
except:
print('except', n)
if n > 0:
raise
sys.setrecursionlimit(1000)
f(0)
It's output is:
try 0
try 1
try 2
...
try 995
except 996
except 995
...
except 0
I understand that the try block would iterate and print n until the systems recursion limit is met, in which case the except block is entered. My question is, in the except block, why is n decreasing and where is recursion occurring here? Furthermore, why does n not meet the recursion limit precisely? That is, why does the sequence not reach try 1000? Thanks!
Your first quesition on why you don't reach the recursion limit has been answered previously by Why Python raises RecursionError before it exceeds the real recursion limit? illustrates there are:
recursion limit refers maximum depth of the stack frames
there are frames on the stack before your function f is called
other functions (such as the print you're using) places things on the stack
you can use the inspect module to get the current depth of stack frame using len(inspect.stack()) as described in How do I get the current depth of the Python interpreter stack?
Regarding your second question of why the except numbers are decreasing:
Your code creates a stack of calls:
f(0)
f(1)
...
f(997) # Exception is raised when you get to the stack limit
The code lines:
except:
print('except', n)
if n > 0:
raise
The exception is reported to the parent and caught by the parents except block which:
prints the value of n
re-raises the exception (i.e. raise statement), passing it back to its parent
So we get the exception sequence of:
f(996) # receives except from f(1+996), prints 996, and raises exception to its parent
f(995) # receives exception from f(1+995) call, print 995, and raises exception to its parent
...
f(1) # receives exception from f(1+1) call, prints 1, and raises except to its aprent
f(0) # receives exception from f(1+0) call and prints 0
when you get the exception in the deepest call you go to the except part, and print, that easy enough to understand, right?, then you raise again the same exception you got, now is the previous caller that get the exception and in turn go to except block and print and because it is the previous caller it will have the previous value of n and thus print one less, rinse a repeat, you are just walking back your recursive path
>>> sys.setrecursionlimit(5)
>>> f(0)
try 0
try 1
try 2
try 3
try 4
try 5
try 6
try 7
try 8
try 9
try 10
try 11
try 12
try 13
try 14
try 15
try 16
except 16
except 15
except 14
except 13
except 12
except 11
except 10
except 9
except 8
except 7
except 6
except 5
except 4
except 3
except 2
except 1
except 0
>>>
And as to why n does not get to the exact value you set, I'm not sure that is something with python internal that I'm not familiar with, in my case it goes over by 11
The second part of your question "why does the sequence not reach try 1000" is actually a really interesting question, but I'll start with your first question ("why is n decreasing) since it is much simpler to answer.
The value of n decreases because when you reach the maximum recursion limit, your call stack starts to unravel. When a function is done executing, it will return back to whoever called it. Think of it like adding 10 pancakes to your plate, and then eating them from top to bottom one by one. The first one you eat will be the top pancake (the last function call), and the last one you eat will be at the bottom (the first function call, which was f(0)). So n increases as you recursively call the functions, and then decreases it begins to unravel back down to the original caller (ie main).
The reason why it doesn't reach 1000 precisely is a bit more interesting. If I try the below code, we acc get the answer we might except of 999:
def f(n):
n += 1
try:
f(n)
except RecursionError:
print(n)
f(0)
>>> 999
The answer is 999 and not 1000 because the stack starts with main already pushed onto it. Now if we add a print statement before we recurse, the answer becomes 996:
def f(n):
n += 1
try:
print(n)
f(n)
except RecursionError:
print(n)
f(0)
>>> 1
>>> 2
>>> ...
>>> 996
I suspect if you look at the underlying implementation of the print statement, it has some additional nested function calls. This means the f(n) call isn't triggering the recursion error, but the print statement is, which is why we get 996 instead of 999 (ie the depth of the print statement would be 3).
Suppose there are a list called 'my_list' and an int variable called 'list_index'. Basically, the list 'my_list' might change over time and hence the 'list_index' might raise 'IndexError: list index out of range'. However, I just want to make record when this error occurs since it is not that important. To avoid this error, my basic solutions currently are:
# My first way
if my_list[list_index: list_index +1]:
print('item exists')
else:
print('item does not exist')
# My second way
if -len(my_list) <= list_index < len(my_list):
print('item exists')
else:
print('item does not exist')
Except for try/except statement, are there other solutions to avoid the 'IndexError: list index out of range' error?
You can use a try-except.
a = [1,2,3]
try:
print(a[4])
except IndexError:
pass
What we can do in this scenario is we know a possible error can happen, so we encapsulate the statements where the error is prone to happen inside try and we add an except block with an error type where we define what the program should do if it encounters that error.
The general syntax for it is,
try:
# statements that can possibly cause an error
except error_type:
# what to do if an error occurred
So here the error you are mentioning is IndexError which catches the out of index exception in runtime. So a neat and pythonic way to do it is as follows.
try:
index_value = my_list[list_index]
except IndexError:
index_value = -1
print('Item index does not exist')
Use range(len(LIST)-1):
for i in range(len(LIST)-1):
if LIST[i] < LIST[i+1]:
... # you got an idea; no index error since range(len(LIST)-1)
actually you don't need to catch it, you need to avoid it by using following construction:
my_list = [1, 2, 3, 4]
for i in range(0, len(my_list)):
print(my_list[i])
len(my_list) - will prevent you to access to item that doesn't exist
I am having trouble understanding the following control flow.
try:
# normal execution block
except A:
# handle exception A
except B:
# handle exception B
except:
# handle other exceptions
else:
# if no exceptions, go here
finally:
# always do this
I don't understand the purpose of the a else in this context. I am coming from Java where there is no else clause for handling exceptions.
If I have something to write in the else part, I would assume that I can directly write it outside of the exception handling part either.
So, whats the necessity of the else clause in Python exception handling?
If I have something to write in else clause,I can directly write outside of the exception handle part either.
No.
def with_else(x):
try:
int(x)
except ValueError:
print('that did not work')
else:
print('that worked!')
def without_else(x):
try:
int(x)
except ValueError:
print('that did not work')
print('that worked!')
Demo:
>>> with_else(1)
that worked!
>>> without_else(1)
that worked!
>>> with_else('foo')
that did not work
>>> without_else('foo')
that did not work
that worked!
processing = True
try:
x = might_raise_a_key_error()
# a
except KeyError:
...
else:
# b
finally:
processing = False
# c
If you have a piece of code which 1) depends on x, 2) you don’t want handled by except KeyError, but 3) you do want covered by the finally clause, do you put it in # a, # b or # c?
Answer: # b.
I have built a max heap and trying to extract max as long as there are elements. If there isn't I'm returning an IndexError. This the code I'm trying to execute:
while True:
try:
print hp.extract_max()
except:
break
and in the extract_max() method:
def extract_max(self):
if self.size == 0:
return IndexError
item = self.items[0]
self.items[0] = self.items[self.size - 1]
self.heapify_down()
del self.items[len(self.items) - 1]
return item
However, the code is not breaking upon encountering an IndexError, rather printing it too. The while loop is not breaking.
<type 'exceptions.IndexError'>
<type 'exceptions.IndexError'>
....
it keeps printing the exception, without breaking the loop.
What's the problem?
As the other answer stated, you should raise the exception instead of return so:
if self.size == 0:
raise IndexError
I just want to add that you are catching all type of exceptions with except, you might want to change it to catch IndexError only to avoid catching other exceptions (ex: KeyboardInterrupt) as the following:
while True:
try:
print hp.extract_max()
except IndexError:
break
You should be raising an exception, not returning it. Do raise IndexError.