Skip to content
Snippets Groups Projects
Commit 6a721dfa authored by Nicola Spallanzani's avatar Nicola Spallanzani
Browse files

updates

parent f02bc745
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
![](images/title_intro_python.png) ![](images/title_intro_python.png)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# error handling # error handling
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
Error handling is a complex problem, which the modern languages face off in a completely different way than the "old" ones. Error handling is a complex problem, which the modern languages face off in a completely different way than the "old" ones.
First, we must be aware of the fact that the place where an error is detected (for example, a library function such as `sqrt`) is not the same place where the error can be "treated" (for example, the main program). First, we must be aware of the fact that the place where an error is detected (for example, a library function such as `sqrt`) is not the same place where the error can be "treated" (for example, the main program).
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
The requirements of a modern system for handling errors are: The requirements of a modern system for handling errors are:
* Low or no impact on performance, when no error are generated * Low or no impact on performance, when no error are generated
* Little invasiveness on code * Little invasiveness on code
* You should not have to "pass" the error by hand * You should not have to "pass" the error by hand
* It must be possible to manage the error "partially" (sometimes you can not completely solve the error at one point, but you can apply only a part of the correction) * It must be possible to manage the error "partially" (sometimes you can not completely solve the error at one point, but you can apply only a part of the correction)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
Suppose you have a stack of function calls like this: Suppose you have a stack of function calls like this:
``` ```
main main
|__compute_matrix <- here the error ZeroDivisionError can be handled completely |__compute_matrix <- here the error ZeroDivisionError can be handled completely
|__compute_cell <- here the errot BadStartingPoint can be handled, and the error |__compute_cell <- here the errot BadStartingPoint can be handled, and the error
| ZeroDivisionError can be handled partially | ZeroDivisionError can be handled partially
|__compute_radix_of_function |__compute_radix_of_function
|__ newton -> here the error BadStartingPoint can be detected |__ newton -> here the error BadStartingPoint can be detected
|__function_C -> here the error ZeroDivisionError can be detected |__function_C -> here the error ZeroDivisionError can be detected
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
In Fortran, for example, it is used a variable returned by the function/subroutine to pass any error. In Fortran, for example, it is used a variable returned by the function/subroutine to pass any error.
In this case, the variable containing the error should be passed manually backwards, for example from `function_C`, to `newton`, to `compute_radix_of_function`, to `compute_cell`, to `compute_matrix`. In this case, the variable containing the error should be passed manually backwards, for example from `function_C`, to `newton`, to `compute_radix_of_function`, to `compute_cell`, to `compute_matrix`.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
What are the drawbacks? What are the drawbacks?
* It is a tedious and boring activity that normally lead to errors * It is a tedious and boring activity that normally lead to errors
* It makes the code much longer and more complicated * It makes the code much longer and more complicated
* Adds overhead even without error (there will be some __if__ checking the state variables of the function that generates the error, for example). * Adds overhead even without error (there will be some __if__ checking the state variables of the function that generates the error, for example).
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
All modern systems use a different approach. All modern systems use a different approach.
Consider the error BadStartingPoint. Consider the error BadStartingPoint.
At the point where the error can be identified (newton), an exception of type `BadStartingPoint` is launched. For now, do not worry about what `BadStartingPoint` is: it could be anything, an `int`, a `string`, a `list` etc... At the point where the error can be identified (newton), an exception of type `BadStartingPoint` is launched. For now, do not worry about what `BadStartingPoint` is: it could be anything, an `int`, a `string`, a `list` etc...
In python, exceptions are launched with the `raise` command. In `fun_B` it will appear something like: In python, exceptions are launched with the `raise` command. In `fun_B` it will appear something like:
```python ```python
if ...: if ...:
raise BadStartingPoint() raise BadStartingPoint()
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
When an exception is launched, the program flow is interrupted, and the stack is automatically "rolled back”, back to the function that called the one who launched the exception, and back again if necessary, up to a point where the error can be "treated". The computation resumes from this point. When an exception is launched, the program flow is interrupted, and the stack is automatically "rolled back”, back to the function that called the one who launched the exception, and back again if necessary, up to a point where the error can be "treated". The computation resumes from this point.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
How do you determine who can treat a certain error? How do you determine who can treat a certain error?
It's simple: the code block that could handle a `BadStartingPoint` exception is enclosed in a special section; when that exception occurs, it will be executed the associated handling section. The syntax is based on the python `try/except` statement. It's simple: the code block that could handle a `BadStartingPoint` exception is enclosed in a special section; when that exception occurs, it will be executed the associated handling section. The syntax is based on the python `try/except` statement.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
Therefore, in the function where we determined that the error can be treated (compute_cell) it is inserted a `try/except` block: Therefore, in the function where we determined that the error can be treated (compute_cell) it is inserted a `try/except` block:
<pre> <pre>
def compute_cell(matrix, i, j): def compute_cell(matrix, i, j):
# ... # ...
try: try:
matrix[i][j] += compute_radix_of_function(f, cell, x_0) matrix[i][j] += compute_radix_of_function(f, cell, x_0)
except BadStartingPoint as e: except BadStartingPoint as e:
print("ERR: {0}: {0}".format(e.__class__.__name__, e)) print("ERR: {0}: {0}".format(e.__class__.__name__, e))
X_0 += 0.4 X_0 += 0.4
# ... # ...
</pre> </pre>
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
In the intermediate functions nothing changes: they are not involved from the exception. In the intermediate functions nothing changes: they are not involved from the exception.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
In the case of `ZeroDivisionError`, however, the handling is more complex: `compute_cell` can partially repair the error, but not completely. In the case of `ZeroDivisionError`, however, the handling is more complex: `compute_cell` can partially repair the error, but not completely.
The rest of the work is done by `compute_matrix`. The rest of the work is done by `compute_matrix`.
In this case, the exception is collected, partially managed and relaunched, with the `raise` command: In this case, the exception is collected, partially managed and relaunched, with the `raise` command:
<pre> <pre>
# ... # ...
except ZeroDivisionError as e: except ZeroDivisionError as e:
print("ERR: ZeroDivisionError: resetting cell") print("ERR: ZeroDivisionError: resetting cell")
matrix[i][j] = 0.0 matrix[i][j] = 0.0
raise raise
# ... # ...
</pre> </pre>
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
At this point the stack is again rolled back to `compute_matrix`, which completes the error handling. At this point the stack is again rolled back to `compute_matrix`, which completes the error handling.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
Generally, exceptions are defined hierarchically. In our example, there are three types of BadStartingPoint errors: Generally, exceptions are defined hierarchically. In our example, there are three types of BadStartingPoint errors:
* `StationaryStartingPoint` * `StationaryStartingPoint`
* `CyclingStartingPoint` * `CyclingStartingPoint`
* `SlowlyConvergingStartingPoint` * `SlowlyConvergingStartingPoint`
`newton` launches all these three errors. `newton` launches all these three errors.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
These three types of error are handled the same way by compute_cell, but it is possible that other functions that call `newton` must treat them differently. These three types of error are handled the same way by compute_cell, but it is possible that other functions that call `newton` must treat them differently.
This is accomplished by creating a class `BadStartingPoint`, and the three classes `StationaryStartingPoint`, `CyclingStartingPoint`, `SlowlyConvergingStartingPoint` that inherit from `BadStartingPoint`. This is accomplished by creating a class `BadStartingPoint`, and the three classes `StationaryStartingPoint`, `CyclingStartingPoint`, `SlowlyConvergingStartingPoint` that inherit from `BadStartingPoint`.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## error handling ## error handling
What `BadStartingPoint`, `StationaryStartingPoint`, ... are? They are "types" of exceptions, or, more generally, "types": like `int`, `str`, ... What `BadStartingPoint`, `StationaryStartingPoint`, ... are? They are "types" of exceptions, or, more generally, "types": like `int`, `str`, ...
However, they are user-defined types, or `classes`. However, they are user-defined types, or `classes`.
[Built-in Exceptions](https://docs.python.org/3/library/exceptions.html)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## try/except ## try/except
<pre style="font-size:70%;"> <pre style="font-size:70%;">
try: try:
... ...
... ...
except Exc0: except Exc0:
... # catches exceptions type Exc0 ... # catches exceptions type Exc0
except Exc1 as excInstance: except Exc1 as excInstance:
... # catches exceptions type Exc1, ... # catches exceptions type Exc1,
# and its instance is excInstance # and its instance is excInstance
except (Exc2, Exc3): except (Exc2, Exc3):
... # catches exceptions type Exc2 o Exc3 ... # catches exceptions type Exc2 o Exc3
except (Exc4, Exc5) as excInstance: except (Exc4, Exc5) as excInstance:
... # catches exceptions type Exc2 o Exc3, ... # catches exceptions type Exc2 o Exc3,
# and their instance is excInstance # and their instance is excInstance
except: except:
... # catches any exception ... # catches any exception
else: else:
... # executed only if no exceptions were captured ... # executed only if no exceptions were captured
finally: finally:
... # executed always and anyway ... # executed always and anyway
</pre> </pre>
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## else/finally example ## else/finally example
<pre> <pre>
try: try:
f = open("a.txt", "r") # NEVER DO THIS! USE: with open(...) f = open("a.txt", "r") # NEVER DO THIS! USE: with open(...)
do_some_action_on_file(f) do_some_action_on_file(f)
except: except:
print("ERROR") print("ERROR")
else: else:
print("OK") print("OK")
finally: finally:
f.close() f.close()
</pre> </pre>
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## standard exceptions ## standard exceptions
Now we can better understand what happens when there is an error in a program: Now we can better understand what happens when there is an error in a program:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
a = 4/0 a = 4/0
``` ```
%% Output %% Output
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last) ZeroDivisionError Traceback (most recent call last)
<ipython-input-1-a8fd08e7d073> in <module>() <ipython-input-1-a8fd08e7d073> in <module>()
----> 1 a = 4/0 ----> 1 a = 4/0
ZeroDivisionError: division by zero ZeroDivisionError: division by zero
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## standard exceptions ## standard exceptions
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
l = [1, 2, 3] l = [1, 2, 3]
print(l[10]) print(l[10])
``` ```
%% Output %% Output
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
IndexError Traceback (most recent call last) IndexError Traceback (most recent call last)
<ipython-input-2-52ff604b2b94> in <module>() <ipython-input-2-52ff604b2b94> in <module>()
1 l = [1, 2, 3] 1 l = [1, 2, 3]
----> 2 print(l[10]) ----> 2 print(l[10])
IndexError: list index out of range IndexError: list index out of range
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## standard exceptions ## standard exceptions
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
l.remove(444) l.remove(444)
``` ```
%% Output %% Output
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
ValueError Traceback (most recent call last) ValueError Traceback (most recent call last)
<ipython-input-3-51b8b8a7aebb> in <module>() <ipython-input-3-51b8b8a7aebb> in <module>()
----> 1 l.remove(444) ----> 1 l.remove(444)
ValueError: list.remove(x): x not in list ValueError: list.remove(x): x not in list
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
d = {} d = {}
print(d['alfa']) print(d['alfa'])
``` ```
%% Output %% Output
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
KeyError Traceback (most recent call last) KeyError Traceback (most recent call last)
<ipython-input-4-9f1ad2efe7e6> in <module>() <ipython-input-4-9f1ad2efe7e6> in <module>()
1 d = {} 1 d = {}
----> 2 print(d['alfa']) ----> 2 print(d['alfa'])
KeyError: 'alfa' KeyError: 'alfa'
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## standard exceptions ## standard exceptions
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
l = [1, 2] l = [1, 2]
il = iter(l) il = iter(l)
next(il) next(il)
``` ```
%% Output %% Output
1 1
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
next(il) next(il)
``` ```
%% Output %% Output
2 2
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
next(il) next(il)
``` ```
%% Output %% Output
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
StopIteration Traceback (most recent call last) StopIteration Traceback (most recent call last)
<ipython-input-7-794757028666> in <module>() <ipython-input-7-794757028666> in <module>()
----> 1 next(il) ----> 1 next(il)
StopIteration: StopIteration:
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## standard exceptions ## standard exceptions
We now know that a for loop ends when the iterator on which it operates launches an exception StopIterator! We now know that a for loop ends when the iterator on which it operates launches an exception StopIterator!
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
def rangeIter(n): def rangeIter(n):
i = 0 i = 0
while True: while True:
if i >= n: raise StopIteration if i >= n: raise StopIteration
yield i yield i
i += 1 i += 1
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
for i in rangeIter(3): for i in rangeIter(3):
print(i) print(i)
``` ```
%% Output %% Output
0 0
1 1
2 2
/Users/nicola/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py:1: DeprecationWarning: generator 'rangeIter' raised StopIteration /home/nicola/Utils/miniconda3/lib/python3.6/site-packages/ipykernel_launcher.py:1: DeprecationWarning: generator 'rangeIter' raised StopIteration
"""Entry point for launching an IPython kernel. """Entry point for launching an IPython kernel.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## test (primes.py) ## test (primes.py)
* Change the function `is_prime` to generate an error if the argument is not an integer, or if it is a negative integer. * Change the function `is_prime` to generate an error if the argument is not an integer, or if it is a negative integer.
* Write a test program with error handling. * Write a test program with error handling.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment