diff --git a/episodes/05-defensive_programming.md b/episodes/05-defensive_programming.md index 41ea540..83dff9a 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') @@ -108,16 +111,13 @@ 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`: ```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 +130,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 +214,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 +242,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 +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" -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