Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions episodes/01-introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,63 @@ else:

:::::::::::::::::::::::::::::::::::::::::::::::

::::::::::::::::::::::::::::::::::::::::: callout

## Formatting Variables and Objects in Strings

Throughout this course, we will be printing the values of variables inside strings to demonstrate what the code does. There are a number of ways to this in Python; in this course we will be using `f-strings` which are the recommended string interpolation syntax from version 3.6 onwards.

To use `f-strings` simply start a string literal with `f` or `F`, then embed whatever you want interpolating into the string within curly braces `{}`:

```python
two_int = 2
two_str = "2"
f_string = f"{two_int} + {two_str} = {2 + 2}"
print(f_string)
```
```output
2 + 2 = 4
```

Numerical values can be formatted using `:` inside the curly braces. For example, an integer `i` can be made to have a width `n` using `{i:nd}`, or `{i:0nd}` to pad it out with zeros:

```python
print(f"One with four leading spaces {1:5d}")
print(f"One with four leading zeros {1:05d}")
```
```output
One with four leading spaces 1
One with four leading zeros 00001
```

Floating point variables can have their precision specified with a number after a decimal point and an `f`:
```python
pi = 3.141592653589793
print(pi)
print(f"pi to three decimal places is {pi:.3f}")
```
```output
3.141592653589793
pi to three decimal places is 3.142
```

Or made to use scientific notation with an `e`:

```python
print(1e9)
print(f"A billion in scientific notation is {1e9:.1e}")
```
```output
1000000000.0
A billion in scientific notation is 1.0e+09
```

This is only scratching the surface of what you can do with `f-strings`, they are often the most powerful and concise way to format variables inside strings. However, there are occasions when other methods are preferable, and you should be careful using them with Python [before version 3.12](https://realpython.com/python-f-strings/#upgrading-f-strings-python-312-and-beyond).

To learn more, see: [Python f-strings](https://realpython.com/python-f-strings/).

::::::::::::::::::::::::::::::::::::::::::::::::::
Comment thread
Scottan marked this conversation as resolved.

## Generative AI
Comment thread
Scottan marked this conversation as resolved.

We would like to reiterate the [Carpentries](https://carpentries.org/) stance on [Generative AI in coding](https://swcarpentry.github.io/python-novice-inflammation/01-intro.html#generative-ai) which you may have seen when preparing for this course.
Expand Down
35 changes: 16 additions & 19 deletions episodes/02-dictionaries.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,6 @@ Following the previous example, we can create a python dictionary using the name

```python
d = {'alice': 35, 'bob': 18}
```

```python
print(d)
```

Expand Down Expand Up @@ -150,7 +147,7 @@ d4 = dict(zip(['jane','alice','bob'],[24,35,18]))
To access an element of the dictionary we must use the *key*:

```python
print('The age of alice is :', d['alice'])
print(f'The age of alice is: {d["alice"]}')
```

```output
Expand All @@ -161,8 +158,8 @@ We can also use a variable to index the dictionary:

```python
key = 'alice'
print('The name of the person is used as key:', key)
print('The value associated to that key is:', d[key])
print(f'The name of the person is used as key: {key}')
print(f'The value associated to that key is: {d[key]}')
```

```output
Expand All @@ -175,9 +172,9 @@ The value associated to that key is: 35
Adding an element to a dictionary is done by creating a new key and attaching a value to it.

```python
print('Original dictionary:', d)
print(f'Original dictionary: {d}')
d['jane'] = 24
print('New dictionary:', d)
print(f'New dictionary: {d}')
```

```output
Expand All @@ -191,7 +188,7 @@ To add one or more new elements we can also use the `update` method:
d_extra = {'tom': 54, 'david': 87}

d.update(d_extra)
print('Updated dictionary:', d)
print(f'Updated dictionary: {d}')
```

```output
Expand All @@ -202,7 +199,7 @@ To delete an element, use the `del` method:

```python
del d['tom']
print('Dictionary with item deleted:', d)
print(f'Dictionary with item deleted: {d}')
```

```output
Expand All @@ -213,8 +210,8 @@ Alternatively, the `pop` function can be used to take an element out of a dictio

```python
david_age = d.pop('david')
print('Age of David:', david_age)
print('Dictionary with david popped out:', d)
print(f'Age of David: {david_age}')
print(f'Dictionary with david popped out: {d}')
```

```output
Expand Down Expand Up @@ -250,9 +247,9 @@ TypeError: unsupported operand type(s) for +: 'dict' and 'dict'
Keys have to be unique; you cannot have two keys with the same name. If you try to add an item using a key already present in the dictionary you will overwrite the previous value.

```python
print('Original dictionary:', d)
print(f'Original dictionary: {d}')
d['alice'] = 12
print('New dictionary:', d)
print(f'New dictionary: {d}')
```

```output
Expand All @@ -273,9 +270,9 @@ d1 = {'alice': 12, 'bob': 18, 'jane': 24, 'tom': 54, 'david': 87}
d2 = {'tom': 54, 'david': 87}
d3 = {'bob': 18, 'alice': 35, 'jane': 24}
d4 = {'alice': 35, 'bob': 18, 'jane': 24}
print('Dictionary 1 and dictionary 2 are equal:', d1 == d2)
print('Dictionary 1 and dictionary 3 are equal:', d1 == d3)
print('Dictionary 3 and dictionary 4 are equal:', d3 == d4)
print(f'Dictionary 1 and dictionary 2 are equal: {d1 == d2}')
print(f'Dictionary 1 and dictionary 3 are equal: {d1 == d3}')
print(f'Dictionary 3 and dictionary 4 are equal: {d3 == d4}')
```

```output
Expand Down Expand Up @@ -327,7 +324,7 @@ list(d.values())[0]
```

It is also possible to iterate through the keys and items in the dictionary at the same time using the `items` function,
which returns a *dict\_items* object containing `key, value` pairs:
which returns a *dict\_items* object containing *key, value* pairs:

```python
d.items()
Expand All @@ -341,7 +338,7 @@ This is very useful when using a dictionary in a `for` loop:

```python
for key, value in d.items():
print("Name:", key, " Age:", value)
print(f'Name: {key}, Age: {value}')
```

```output
Expand Down
39 changes: 19 additions & 20 deletions episodes/03-numpy_essential.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,13 +271,12 @@ To identify any signal in the data we can use the standard deviation as an estim
```python
stddev_noisy = np.std(noisy)
mean_noisy = np.mean(noisy)
print(f'standard deviation is: {stddev_noisy}')
print(f'mean value is: {mean_noisy}')
print(f'standard deviation is: {stddev_noisy:.5f}')
print(f'mean value is: {mean_noisy:.5f}')
```

```output
standard deviation is: 0.011592652442611553
mean value is: 0.005047252119578472
standard deviation is: 0.01159
mean value is: 0.00505
```

We will create a mask for the data, by selecting all data points below this threshold value (we'll assume here that any signal we might be interested in is positive):
Expand Down Expand Up @@ -394,10 +393,10 @@ To improve the visible output we will carry out some simple analysis of the imag
First we examine the general stats of the data (using built-in methods, except for the median, which has to be called from NumPy directly):

```python
print('mean value im1:', imdata.mean())
print('median value im1:', np.median(imdata))
print('max value im1:', imdata.max())
print('min value im1:', imdata.min())
print(f'mean value im1: {imdata.mean()}')
print(f'median value im1: {np.median(imdata)}')
print(f'max value im1: {imdata.max()}')
print(f'min value im1: {imdata.min()}')
```

```output
Expand Down Expand Up @@ -482,17 +481,17 @@ plt.imshow(immasked.mask, cmap='gray', origin='lower')
This mask is applied to the data for all built-in functions. But where we have to directly use a NumPy function we have to make sure we use the equivalent function in the mask (`ma`) library:

```python
print('original average:', imdata.mean())
print('Masked average:', immasked.mean())
print()
print('original max:', imdata.max())
print('Masked max:', immasked.max())
print()
print('original min:', imdata.min())
print('Masked min:', immasked.min())
print()
print('original median:', np.mean(imdata))
print('Masked median:', np.ma.median(immasked))
print(f'original average: {imdata.mean()}')
print(f'Masked average: {immasked.mean()}\n')

print(f'original max: {imdata.max()}')
print(f'Masked max: {immasked.max()}\n')

print(f'original min: {imdata.min()}')
print(f'Masked min: {immasked.min()}\n')

print(f'original median: {np.mean(imdata)}')
print(f'Masked median: {np.ma.median(immasked)}')
```

```output
Expand Down
32 changes: 16 additions & 16 deletions episodes/05-defensive_programming.md
Original file line number Diff line number Diff line change
Expand Up @@ -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(f'Value: {val} is positive.')
elif val == 0:
print('Value:', val, 'is zero.')
print(f'Value: {val} is zero.')
else:
print('Value:', val, 'is negative.')
print(f'Value: {val} is negative.')
```

::::::::::::::: solution
Expand All @@ -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(f'Value: {val} is positive.')
elif val == 0:
print('Value:', val, 'is zero.')
print(f'Value: {val} is zero.')
else:
print('Value:', val, 'is negative.')
print(f'Value: {val} is negative.')
```

```output
Expand All @@ -64,9 +64,9 @@ TypeError Traceback (most recent call last)
<ipython-input-2-99c0e25bf5e9> in <module>()
1 def check_sign(val):
----> 2 if val > 0:
3 print('Value:', val, 'is positive.')
3 print(f'Value: {val} is positive.')
4 elif val == 0:
5 print('Value:', val, 'is zero.')
5 print(f'Value: {val} is zero.')

TypeError: '>' not supported between instances of 'str' and 'int'
```
Expand All @@ -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(f'Value: {val} is positive.')
elif val == 0:
print('Value:', val, 'is zero.')
print(f'Value: {val} is zero.')
else:
print('Value:', val, 'is negative.')
print(f'Value: {val} is negative.')
```

Then wrap the function call in an `if` statement:
Expand Down Expand Up @@ -121,7 +121,7 @@ try:
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)
print(f'The run-time error is: {err}')
```

As with `if` statements, multiple `except` statements can be used, each with a different error test. These can be followed by an (optional) catch-all bare `except` statement (as we started with) to catch any unexpected errors. Note that only one `try` statement is allowed in the structure.
Expand All @@ -134,12 +134,12 @@ try:
reciprocal = 1/val
except TypeError as err:
print('Val is not a number')
print('The run-time error is:', err)
print(f'The run-time error is: {err}')
except Exception as err:
print('Some error other than a TypeError occured')
print('The run-time error is:', err)
print(f'The run-time error is: {err}')
else:
print('The reciprocal of the value =', reciprocal)
print(f'The reciprocal of the value = {reciprocal}')
finally:
print('release memory')
```
Expand Down Expand Up @@ -214,7 +214,7 @@ To conduct such a test we can use an `assert` statement. This follows the struct
```python
val = 'a'

assert type(val) is float or type(val) is int, "Variable has to be a numerical object"
assert type(val) is float or type(val) is int, 'Variable has to be a numerical object'

check_sign(val)
```
Expand Down
Loading
Loading