From 9817f1dd9b782ab35ed83d1f4cd4bce856473e5a Mon Sep 17 00:00:00 2001 From: scottan <33283688+Scottan@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:42:20 +0000 Subject: [PATCH 1/8] Replace test code with a function to avoid repetition --- episodes/05-defensive_programming.md | 54 +++++++++------------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/episodes/05-defensive_programming.md b/episodes/05-defensive_programming.md index 41ea540..86492f8 100644 --- a/episodes/05-defensive_programming.md +++ b/episodes/05-defensive_programming.md @@ -75,16 +75,24 @@ TypeError: '>' not supported between instances of 'str' and 'int' :::::::::::::::::::::::::::::::::::::::::::::::::: -We can avoid problems like this by wrapping our code in an `if` statement: +We can avoid problems like this by wrapping our code in an `if` statement. +To make things simpler, we will first write the test as a function: ```python -if type(val) is int or type(val) is float: +def check_value(val): if val>0 and val<10: print('Value: ', val, 'is a digit.') elif val==0: print('Value ', val, 'is nul') else: print('Value: ', val, 'is a number.') +``` + +Then wrap the function call in an `if` statement: + +```python +if type(val) is int or type(val) is float: + check_value(val) else: print('val is not a number') ``` @@ -95,12 +103,7 @@ Python provides the `try-except` structure to avoid this issue, enabling develop ```python try: - if val>0 and val<10: - print('Value: ', val, 'is a digit.') - elif val==0: - print('Value ', val, 'is nul') - else: - print('Value: ', val, 'is a number.') + check_value(val) except: print('Val is not a number') print('Enter a new number') @@ -112,12 +115,7 @@ The `except` statement will catch all errors and so we do not, initially at leas ```python try: - if val>0 and val<10: - print('Value: ', val, 'is a digit.') - elif val==0: - print('Value ', val, 'is nul') - else: - print('Value: ', val, 'is a number.') + check_value(val) except TypeError as err: print('Val is not a number') print('But our code does not crash anymore') @@ -130,12 +128,7 @@ As with `if` statements, multiple `except` statements can be used, each with a d ```python try: - if val>0 and val<10: - print('Value: ', val, 'is a digit.') - elif val==0: - print('Value ', val, 'is nul') - else: - print('Value: ', val, 'is a number.') + check_value(val) except TypeError as err: print('Val is not a number') print('But our code does not crash anymore') @@ -219,12 +212,7 @@ val = 'a' assert type(val) is float or type(val) is int, "Variable has to be a numerical object" -if val>0 and val<10: - print('Value: ', val, 'is a digit.') -elif val==0: - print('Value ', val, 'is nul') -else: - print('Value: ', val, 'is a number.') +check_value(val) ``` ```output @@ -252,12 +240,7 @@ val = np.nan assert type(val) is float or type(val) is int, "Variable has to be a numerical object" -if val>0 and val<10: - print('Value: ', val, 'is a digit.') -elif val==0: - print('Value ', val, 'is nul') -else: - print('Value: ', val, 'is a number.') +check_value(val) ``` ```output @@ -281,12 +264,7 @@ val = np.nan assert type(val) is float or type(val) is int, "Variable has to be a numerical object" assert not np.isnan(val), "Variable must not be a NaN" -if val>0 and val<10: - print('Value: ', val, 'is a digit.') -elif val==0: - print('Value ', val, 'is nul') -else: - print('Value: ', val, 'is a number.') +check_value(val) ``` ```output From 81264412c73010cad9e0b8a110abf894b0af724a Mon Sep 17 00:00:00 2001 From: scottan <33283688+Scottan@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:52:43 +0000 Subject: [PATCH 2/8] Enhance explanation of try-except usage in Python Included discussion of EAFP coding style --- episodes/05-defensive_programming.md | 1 + 1 file changed, 1 insertion(+) diff --git a/episodes/05-defensive_programming.md b/episodes/05-defensive_programming.md index 86492f8..e3754bf 100644 --- a/episodes/05-defensive_programming.md +++ b/episodes/05-defensive_programming.md @@ -110,6 +110,7 @@ except: ``` At the top of the statement is the code that we are interested in executing, which is run in the `try` statement. If that fails then the `except` statement comes into effect, (hopefully) returning helpful information to the user about what happened and giving them some guidance on how to avoid the problem in future. +Using `try-except` statements results in clearer, easier to understand code by following the common Python coding style of (EAFP)[https://docs.python.org/3.6/glossary.html#term-eafp] (it's easier to ask for forgiveness than permission). This style shows the code we want to execute first, assuming that the incoming data is correct, before dealing with exceptions if the assumptions are false. The `except` statement will catch all errors and so we do not, initially at least, need to know exactly what errors we are trying to avoid. However, python does provide error codes, which we can use to expand the structure to capture specific error types. For the example above, we would want to capture a `TypeError`: From 34c7fcc1ea72e9bcb26ba0b7df549a2685ac2bf9 Mon Sep 17 00:00:00 2001 From: scottan <33283688+Scottan@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:56:10 +0000 Subject: [PATCH 3/8] Fix EAFP link formatting in defensive programming section Corrected the formatting of the EAFP link in the text. --- episodes/05-defensive_programming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/episodes/05-defensive_programming.md b/episodes/05-defensive_programming.md index e3754bf..f8c360b 100644 --- a/episodes/05-defensive_programming.md +++ b/episodes/05-defensive_programming.md @@ -110,7 +110,7 @@ except: ``` At the top of the statement is the code that we are interested in executing, which is run in the `try` statement. If that fails then the `except` statement comes into effect, (hopefully) returning helpful information to the user about what happened and giving them some guidance on how to avoid the problem in future. -Using `try-except` statements results in clearer, easier to understand code by following the common Python coding style of (EAFP)[https://docs.python.org/3.6/glossary.html#term-eafp] (it's easier to ask for forgiveness than permission). This style shows the code we want to execute first, assuming that the incoming data is correct, before dealing with exceptions if the assumptions are false. +Using `try-except` statements results in clearer, easier to understand code by following the common Python coding style of [EAFP](https://docs.python.org/3.6/glossary.html#term-eafp) (it's easier to ask for forgiveness than permission). This style shows the code we want to execute first, assuming that the incoming data is correct, before dealing with exceptions if the assumptions prove false. The `except` statement will catch all errors and so we do not, initially at least, need to know exactly what errors we are trying to avoid. However, python does provide error codes, which we can use to expand the structure to capture specific error types. For the example above, we would want to capture a `TypeError`: From 609571ea8055103058a22813ca09389af4105598 Mon Sep 17 00:00:00 2001 From: scottan <33283688+Scottan@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:56:57 +0000 Subject: [PATCH 4/8] broke up paragraph --- episodes/05-defensive_programming.md | 1 + 1 file changed, 1 insertion(+) diff --git a/episodes/05-defensive_programming.md b/episodes/05-defensive_programming.md index f8c360b..83dff9a 100644 --- a/episodes/05-defensive_programming.md +++ b/episodes/05-defensive_programming.md @@ -110,6 +110,7 @@ except: ``` At the top of the statement is the code that we are interested in executing, which is run in the `try` statement. If that fails then the `except` statement comes into effect, (hopefully) returning helpful information to the user about what happened and giving them some guidance on how to avoid the problem in future. + Using `try-except` statements results in clearer, easier to understand code by following the common Python coding style of [EAFP](https://docs.python.org/3.6/glossary.html#term-eafp) (it's easier to ask for forgiveness than permission). This style shows the code we want to execute first, assuming that the incoming data is correct, before dealing with exceptions if the assumptions prove false. The `except` statement will catch all errors and so we do not, initially at least, need to know exactly what errors we are trying to avoid. However, python does provide error codes, which we can use to expand the structure to capture specific error types. For the example above, we would want to capture a `TypeError`: From bcd4a7c56103d7a268136596e99196e47c11bd6b Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Mon, 13 Apr 2026 10:30:29 +0100 Subject: [PATCH 5/8] fix: replaced check_value with check_sign function --- episodes/05-defensive_programming.md | 56 ++++++++++++++-------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/episodes/05-defensive_programming.md b/episodes/05-defensive_programming.md index 83dff9a..870c935 100644 --- a/episodes/05-defensive_programming.md +++ b/episodes/05-defensive_programming.md @@ -30,15 +30,15 @@ More importantly, applications are not expected to crash and we are going to lea Please look at the following code. Can you find the fundamental problem in this test? -```bash +```python val = 1 -if val>0 and val<10: - print('Value: ', val, 'is a digit.') -elif val==0: - print('Value ', val, 'is nul') +if val > 0: + print('Value: ', val, 'is positive.') +elif val == 0: + print('Value: ', val, 'is zero.') else: - print('Value: ', val, 'is a number.') + print('Value: ', val, 'is negative.') ``` ::::::::::::::: solution @@ -47,15 +47,15 @@ else: The test assumes that `val` is a number, and throws an uncontrolled error if it is not. -```bash +```python val = 'a' -if val>0 and val<10: - print('Value: ', val, 'is a digit.') -elif val==0: - print('Value ', val, 'is nul') +if val > 0: + print('Value: ', val, 'is positive.') +elif val == 0: + print('Value: ', val, 'is zero.') else: - print('Value: ', val, 'is a number.') + print('Value: ', val, 'is negative.') ``` ```output @@ -64,9 +64,9 @@ TypeError Traceback (most recent call last) in () 1 val = 'a' 2 -----> 3 if val>0 and val<10: - 4 print('Value: ', val, 'is a digit.') - 5 elif val==0: +----> 3 if val > 0: + 4 print('Value: ', val, 'is positive.') + 5 elif val > 0: TypeError: '>' not supported between instances of 'str' and 'int' ``` @@ -79,20 +79,20 @@ We can avoid problems like this by wrapping our code in an `if` statement. To make things simpler, we will first write the test as a function: ```python -def check_value(val): - if val>0 and val<10: - print('Value: ', val, 'is a digit.') - elif val==0: - print('Value ', val, 'is nul') +def check_sign(val): + if val > 0: + print('Value: ', val, 'is positive.') + elif val == 0: + print('Value: ', val, 'is zero.') else: - print('Value: ', val, 'is a number.') + print('Value: ', val, 'is negative.') ``` Then wrap the function call in an `if` statement: ```python if type(val) is int or type(val) is float: - check_value(val) + check_sign(val) else: print('val is not a number') ``` @@ -103,7 +103,7 @@ Python provides the `try-except` structure to avoid this issue, enabling develop ```python try: - check_value(val) + check_sign(val) except: print('Val is not a number') print('Enter a new number') @@ -117,7 +117,7 @@ The `except` statement will catch all errors and so we do not, initially at leas ```python try: - check_value(val) + check_sign(val) except TypeError as err: print('Val is not a number') print('But our code does not crash anymore') @@ -130,7 +130,7 @@ As with `if` statements, multiple `except` statements can be used, each with a d ```python try: - check_value(val) + check_sign(val) except TypeError as err: print('Val is not a number') print('But our code does not crash anymore') @@ -214,7 +214,7 @@ val = 'a' assert type(val) is float or type(val) is int, "Variable has to be a numerical object" -check_value(val) +check_sign(val) ``` ```output @@ -242,7 +242,7 @@ val = np.nan assert type(val) is float or type(val) is int, "Variable has to be a numerical object" -check_value(val) +check_sign(val) ``` ```output @@ -266,7 +266,7 @@ val = np.nan assert type(val) is float or type(val) is int, "Variable has to be a numerical object" assert not np.isnan(val), "Variable must not be a NaN" -check_value(val) +check_sign(val) ``` ```output From 2f2b7d0ee67e2916cd101490eb73ae9419203174 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Mon, 13 Apr 2026 12:14:56 +0100 Subject: [PATCH 6/8] style: changed else clause in try/except/else/finally example --- .gitignore | 3 +++ episodes/05-defensive_programming.md | 12 ++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index c4a48f2..c001767 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,6 @@ vendor/ .docker-vendor/ Gemfile.lock .*history + +# Course developer file to testing lesson code +test.ipynb \ No newline at end of file diff --git a/episodes/05-defensive_programming.md b/episodes/05-defensive_programming.md index 870c935..18bd8c4 100644 --- a/episodes/05-defensive_programming.md +++ b/episodes/05-defensive_programming.md @@ -62,11 +62,11 @@ else: --------------------------------------------------------------------------- TypeError Traceback (most recent call last) in () - 1 val = 'a' - 2 -----> 3 if val > 0: - 4 print('Value: ', val, 'is positive.') - 5 elif val > 0: + 1 def check_sign(val): +----> 2 if val > 0: + 3 print('Value: ', val, 'is positive.') + 4 elif val == 0: + 5 print('Value: ', val, 'is zero.') TypeError: '>' not supported between instances of 'str' and 'int' ``` @@ -136,7 +136,7 @@ except TypeError as err: print('But our code does not crash anymore') print('The run-time error is:', err) else: - print('1/val = ', 1/val) + print('The value provided to the check_sign function did not result in a TypeError') finally: print('release memory') del(val) From d1be0af2c7a72fe9718cec7acde0a5b5c4b7edeb Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Mon, 13 Apr 2026 12:30:56 +0100 Subject: [PATCH 7/8] feat: better try/except/else case --- episodes/05-defensive_programming.md | 30 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/episodes/05-defensive_programming.md b/episodes/05-defensive_programming.md index 18bd8c4..fe82d50 100644 --- a/episodes/05-defensive_programming.md +++ b/episodes/05-defensive_programming.md @@ -34,11 +34,11 @@ Please look at the following code. Can you find the fundamental problem in this val = 1 if val > 0: - print('Value: ', val, 'is positive.') + print('Value:', val, 'is positive.') elif val == 0: - print('Value: ', val, 'is zero.') + print('Value:', val, 'is zero.') else: - print('Value: ', val, 'is negative.') + print('Value:', val, 'is negative.') ``` ::::::::::::::: solution @@ -51,11 +51,11 @@ The test assumes that `val` is a number, and throws an uncontrolled error if it val = 'a' if val > 0: - print('Value: ', val, 'is positive.') + print('Value:', val, 'is positive.') elif val == 0: - print('Value: ', val, 'is zero.') + print('Value:', val, 'is zero.') else: - print('Value: ', val, 'is negative.') + print('Value:', val, 'is negative.') ``` ```output @@ -64,9 +64,9 @@ TypeError Traceback (most recent call last) in () 1 def check_sign(val): ----> 2 if val > 0: - 3 print('Value: ', val, 'is positive.') + 3 print('Value:', val, 'is positive.') 4 elif val == 0: - 5 print('Value: ', val, 'is zero.') + 5 print('Value:', val, 'is zero.') TypeError: '>' not supported between instances of 'str' and 'int' ``` @@ -81,11 +81,11 @@ To make things simpler, we will first write the test as a function: ```python def check_sign(val): if val > 0: - print('Value: ', val, 'is positive.') + print('Value:', val, 'is positive.') elif val == 0: - print('Value: ', val, 'is zero.') + print('Value:', val, 'is zero.') else: - print('Value: ', val, 'is negative.') + print('Value:', val, 'is negative.') ``` Then wrap the function call in an `if` statement: @@ -131,15 +131,19 @@ As with `if` statements, multiple `except` statements can be used, each with a d ```python try: check_sign(val) + reciprocal = 1/val except TypeError as err: print('Val is not a number') print('But our code does not crash anymore') print('The run-time error is:', err) +except Exception as err: + print('Some error other than a TypeError occured') + print('But our code does not crash') + print('The run-time error is:', err) else: - print('The value provided to the check_sign function did not result in a TypeError') + print('The reciprocal of the value =', reciprocal) finally: print('release memory') - del(val) ``` The typical use of the `finally` statement is to deal with the release of external resources (such as files or network connections) whether or not the attempted action has been successful. From 868162d7df8121d37372ffbec1a9f54fb05ae4a8 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Mon, 13 Apr 2026 12:37:54 +0100 Subject: [PATCH 8/8] style: deleted some unnecesary print statements to shorten example --- episodes/05-defensive_programming.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/episodes/05-defensive_programming.md b/episodes/05-defensive_programming.md index fe82d50..bcb82d8 100644 --- a/episodes/05-defensive_programming.md +++ b/episodes/05-defensive_programming.md @@ -134,11 +134,9 @@ try: reciprocal = 1/val except TypeError as err: print('Val is not a number') - print('But our code does not crash anymore') print('The run-time error is:', err) except Exception as err: print('Some error other than a TypeError occured') - print('But our code does not crash') print('The run-time error is:', err) else: print('The reciprocal of the value =', reciprocal)