diff --git a/lectures/3/3.md b/lectures/3/3.md index 17aed45..0af61a5 100644 --- a/lectures/3/3.md +++ b/lectures/3/3.md @@ -15,7 +15,7 @@ _class: titlepage ###### Pasquale Claudio Africa, Dario Coscia -###### 14 Feb 2025 +###### 18 Feb 2025 --- @@ -23,8 +23,8 @@ _class: titlepage 1. Scientific data types 2. The role of Python in modern scientific computing -3. Dependency management -4. Error handling +3. Error handling +4. Dependency management 5. Docker 6. Continuous Integration/Continuous Deployment @@ -484,6 +484,107 @@ _class: titlepage _class: titlepage --> +# Error handling + +--- + +# Exceptions + +If something goes wrong, we don't want our code to crash - we want it to **fail gracefully**. In Python, this can be accomplished using `try`/`except`. Here is a basic example: + +```python +this_variable_does_not_exist +print("Another line") # Code fails before getting to this line. +``` +> NameError: name 'this_variable_does_not_exist' is not defined + +--- + +# `try-except` + +```python +try: + this_variable_does_not_exist +except: + pass # Do nothing. + print("You did something bad! But I won't raise an error.") +print("Another line") +``` + + You did something bad! But I won't raise an error. + Another line + + +Python tries to execute the code in the `try` block. If an error is encountered, we *catch* this in the `except` block (also called `try`/`catch` in other languages). There are many different error types, or **exceptions** - we saw `NameError` above. + +```python +5 / 0 +``` +> ZeroDivisionError: division by zero + +--- + +# A complete example + +```python +x = 2 +y = 0 + +try: + result = x / y +except ZeroDivisionError: + print("Sorry! You are dividing by zero.") +else: + print("Yeah! Your answer is: ", result) +finally: + # This block is always executed + # regardless of exception generation. + print('This is always executed') +``` + +--- + +# More exception types + +```python +my_list = [1, 2, 3] +my_list[5] +``` +> IndexError: list index out of range + +```python +my_tuple = (1,2,3) +my_tuple[0] = 0 +``` +> TypeError: 'tuple' object does not support item assignment + +--- + +# Raise exceptions + +We can also write code that raises an exception on purpose, using `raise`: + +```python +def add_one(x): + if not isinstance(x, float) and not isinstance(x, int): + raise TypeError(f"Sorry, x must be numeric, you entered a {type(x)}.") + + return x + 1 + +add_one("blah") +``` +> TypeError: Sorry, x must be numeric, you entered a . + +This is useful when your function is complicated and would fail in a complicated way, with a weird error message. You can make the cause of the error much clearer to the *user* of the function. + +Finally, we can even define our own exception types by inheriting from the `Exception` class! + +--- + + + # Dependency management --- @@ -648,107 +749,6 @@ dependencies: _class: titlepage --> -# Error handling - ---- - -# Exceptions - -If something goes wrong, we don't want our code to crash - we want it to **fail gracefully**. In Python, this can be accomplished using `try`/`except`. Here is a basic example: - -```python -this_variable_does_not_exist -print("Another line") # Code fails before getting to this line. -``` -> NameError: name 'this_variable_does_not_exist' is not defined - ---- - -# `try-except` - -```python -try: - this_variable_does_not_exist -except: - pass # Do nothing. - print("You did something bad! But I won't raise an error.") -print("Another line") -``` - - You did something bad! But I won't raise an error. - Another line - - -Python tries to execute the code in the `try` block. If an error is encountered, we *catch* this in the `except` block (also called `try`/`catch` in other languages). There are many different error types, or **exceptions** - we saw `NameError` above. - -```python -5 / 0 -``` -> ZeroDivisionError: division by zero - ---- - -# A complete example - -```python -x = 2 -y = 0 - -try: - result = x / y -except ZeroDivisionError: - print("Sorry! You are dividing by zero.") -else: - print("Yeah! Your answer is: ", result) -finally: - # This block is always executed - # regardless of exception generation. - print('This is always executed') -``` - ---- - -# More exception types - -```python -my_list = [1, 2, 3] -my_list[5] -``` -> IndexError: list index out of range - -```python -my_tuple = (1,2,3) -my_tuple[0] = 0 -``` -> TypeError: 'tuple' object does not support item assignment - ---- - -# Raise exceptions - -We can also write code that raises an exception on purpose, using `raise`: - -```python -def add_one(x): - if not isinstance(x, float) and not isinstance(x, int): - raise TypeError(f"Sorry, x must be numeric, you entered a {type(x)}.") - - return x + 1 - -add_one("blah") -``` -> TypeError: Sorry, x must be numeric, you entered a . - -This is useful when your function is complicated and would fail in a complicated way, with a weird error message. You can make the cause of the error much clearer to the *user* of the function. - -Finally, we can even define our own exception types by inheriting from the `Exception` class! - ---- - - - # Introduction to Docker --- @@ -982,7 +982,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Python environment run: | @@ -1013,7 +1013,7 @@ jobs: sphinx-build -b html . _build/html - name: Upload documentation - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: documentation path: docs/_build/html/ @@ -1038,6 +1038,5 @@ jobs: # Additional resources -- Testing and documenting Python code: see lecture notes. - [Productivity tools](https://aaltoscicomp.github.io/python-for-scicomp/productivity/). - More about [unit testing in Python](https://pytest-with-eric.com/comparisons/pytest-vs-unittest/).