Commit cb9cbb01 authored by Michiel Cottaar's avatar Michiel Cottaar
Browse files

Minor edits to first practical

parent 3e79b7bd
%% Cell type:markdown id: tags:
# Basic python
This tutorial is aimed at briefly introducing you to the main language
features of python, with emphasis on some of the common difficulties
and pitfalls that are commonly encountered when moving to python.
When going through this make sure that you _run_ each code block and
look at the output, as these are crucial for understanding the
explanations. You can run each block by using _shift + enter_
(including the text blocks, so you can just move down the document
with shift + enter).
It is also possible to _change_ the contents of each code block (these pages
are completely interactive) so do experiment with the code you see and try
some variations!
> **Important**: We are exclusively using Python 3 in FSL - as of FSL 6.0.4 we
> are using Python 3.7. There are some subtle differences between Python 2 and
> Python 3, but instead of learning about these differences, it is easier to
> simply forget that Python 2 exists. When you are googling for Python help,
> make sure that the pages you find are relevant to Python 3 and *not* Python
> 2! The official Python docs can be found at https://docs.python.org/3/ (note
> the _/3/_ at the end!).
## Contents
* [Basic types](#Basic-types)
- [Strings](#Strings)
+ [Format](#Format)
+ [String manipulation](#String-manipulation)
- [Tuples and lists](#Tuples-and-lists)
+ [Adding to a list](#Adding-to-a-list)
+ [Indexing](#Indexing)
+ [Slicing](#Slicing)
- [List operations](#List-operations)
+ [Looping over elements in a list (or tuple)](#Looping)
+ [Getting help](#Getting-help)
- [Dictionaries](#Dictionaries)
+ [Adding to a dictionary](#Adding-to-a-dictionary)
+ [Removing elements from a dictionary](#Removing-elements-dictionary)
+ [Looping over everything in a dictionary](#Looping-dictionary)
- [Copying and references](#Copying-and-references)
* [Control flow](#Control-flow)
- [Boolean operators](#Boolean-operators)
- [If statements](#If-statements)
- [For loops](#For-loops)
- [While loops](#While-loops)
- [A quick intro to conditional expressions and list comprehensions](#quick-intro)
+ [Conditional expressions](#Conditional-expressions)
+ [List comprehensions](#List-comprehensions)
* [Functions](#functions)
* [Exercise](#exercise)
---
<a class="anchor" id="Basic-types"></a>
# Basic types
Python has many different types and variables are dynamic and can change types (like MATLAB). Some of the most commonly used in-built types are:
* integer and floating point scalars
* strings
* tuples
* lists
* dictionaries
N-dimensional arrays and other types are supported through common modules (e.g., numpy, scipy, scikit-learn). These will be covered in a subsequent exercise.
N-dimensional arrays and other types are supported through common modules (e.g., [numpy](https://numpy.org/), [scipy](https://docs.scipy.org/doc/scipy-1.4.1/reference/), [scikit-learn](https://scikit-learn.org/stable/)). These will be covered in a subsequent exercises.
%% Cell type:code id: tags:
```
a = 4
b = 3.6
c = 'abc'
d = [10, 20, 30]
e = {'a' : 10, 'b': 20}
print(a)
```
%% Cell type:markdown id: tags:
Any variable or combination of variables can be printed using the function `print()`:
%% Cell type:code id: tags:
```
print(d)
print(e)
print(a, b, c)
```
%% Cell type:markdown id: tags:
> _*Python 3 versus python 2*_:
>
> Print - for the print statement the brackets are compulsory for *python 3*, but are optional in python 2. So you will see plenty of code without the brackets but you should never use `print` without brackets, as this is incompatible with Python 3.
>
> Division - in python 3 all division is floating point (like in MATLAB), even if the values are integers, but in python 2 integer division works like it does in C.
---
<a class="anchor" id="Strings"></a>
## Strings
Strings can be specified using single quotes *or* double quotes - as long as they are matched.
Strings can be indexed like lists (see later).
For example:
%% Cell type:code id: tags:
```
s1 = "test string"
s2 = 'another test string'
print(s1, ' :: ', s2)
```
%% Cell type:markdown id: tags:
You can also use triple quotes to capture multi-line strings. For example:
%% Cell type:code id: tags:
```
s3 = '''This is
a string over
multiple lines
'''
print(s3)
```
%% Cell type:markdown id: tags:
<a class="anchor" id="Format"></a>
### Format
More interesting strings can be created using the
[`format`](https://docs.python.org/3/library/string.html#formatstrings)
statement, which is very useful in print statements:
More interesting strings can be created using an [f-string](https://realpython.com/python-f-strings/),
which is very useful in print statements:
%% Cell type:code id: tags:
```
x = 1
y = 'PyTreat'
s = 'The numerical value is {} and a name is {}'.format(x, y)
s = f'The numerical value is {x} and a name is {y}'
print(s)
print('A name is {} and a number is {}'.format(y, x))
print(f'A name is {y} and a number is {x}')
```
%% Cell type:markdown id: tags:
Python also supports C-style [`%`
formatting](https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting):
Note the `f` before the initial quote. This lets python know to fill in the variables between the curly brackets.
%% Cell type:code id: tags:
```
x = 1
y = 'PyTreat'
s = 'The numerical value is %i and a name is %s' % (x, y)
print(s)
print('A name is %s and a number is %i' % (y, x))
```
%% Cell type:markdown id: tags:
There are also other options along these lines, which will be discussed in the next practical.
This is the more modern version, although you will see plenty of the other alternatives in "old" code
(to python coders this means anything written before last week).
<a class="anchor" id="String-manipulation"></a>
### String manipulation
The methods `lower()` and `upper()` are useful for strings. For example:
%% Cell type:code id: tags:
```
s = 'This is a Test String'
print(s.upper())
print(s.lower())
```
%% Cell type:markdown id: tags:
Another useful method is:
%% Cell type:code id: tags:
```
s = 'This is a Test String'
s2 = s.replace('Test', 'Better')
print(s2)
```
%% Cell type:markdown id: tags:
Strings can be concatenated just by using the `+` operator:
%% Cell type:code id: tags:
```
s3 = s + ' :: ' + s2
print(s3)
```
%% Cell type:markdown id: tags:
If you like regular expressions then you're in luck as these are well supported in python using the `re` module. To use this (like many other "extensions" - called _modules_ in Python - you need to `import` it). For example:
%% Cell type:code id: tags:
```
import re
s = 'This is a test of a Test String'
s1 = re.sub(r'a [Tt]est', "an example", s)
print(s1)
```
%% Cell type:markdown id: tags:
where the `r` before the quote is used to force the regular expression specification to be a `raw string` (see [here](https://docs.python.org/3.5/library/re.html) for more info).
For more information on matching and substitutions, look up the regular expression module on the web.
Two common and convenient string methods are `strip()` and `split()`. The
first will remove any whitespace at the beginning and end of a string:
%% Cell type:code id: tags:
```
s2 = ' A very spacy string '
print('*' + s2 + '*')
print('*' + s2.strip() + '*')
```
%% Cell type:markdown id: tags:
With `split()` we can tokenize a string (to turn it into a list of strings) like this:
%% Cell type:code id: tags:
```
print(s.split())
print(s2.split())
```
%% Cell type:markdown id: tags:
By default it splits at whitespace, but it can also split at a specified delimiter:
%% Cell type:code id: tags:
```
s4 = ' This is, as you can see , a very weirdly spaced and punctuated string ... '
print(s4.split(','))
```
%% Cell type:markdown id: tags:
A neat trick, if you want to change the delimiter in some structured data (e.g.
replace `,` with `\t`), is to use `split()` in combination with another string
method, `join()`:
%% Cell type:code id: tags:
```
csvdata = 'some,comma,separated,data'
tsvdata = '\t'.join(csvdata.split(','))
tsvdata = tsvdata.replace('comma', 'tab'))
print('csvdata:', csvdata)
print('tsvdata:', tsvdata)
```
%% Cell type:markdown id: tags:
There are more powerful ways of dealing with this like csv files/strings,
which are covered in later practicals, but even this can get you a long way.
> Note that strings in python 3 are _unicode_ so can represent Chinese
> characters, etc, and is therefore very flexible. However, in general you
> can just be blissfully ignorant of this fact.
Strings can be converted to integer or floating-point values by using the
`int()` and `float()` calls:
%% Cell type:code id: tags:
```
sint='23'
sfp='2.03'
print(sint + sfp)
print(int(sint) + float(sfp))
print(float(sint) + float(sfp))
```
%% Cell type:markdown id: tags:
> Note that calling `int()` on a non-integer (e.g., on `sfp` above) will raise an error.
---
<a class="anchor" id="Tuples-and-lists"></a>
## Tuples and lists
Both tuples and lists are builtin python types and are like vectors,
but for numerical vectors and arrays it is much better to use `numpy`
arrays (or matrices), which are covered in a later tutorial.
A tuple is like a list or a vector, but with less flexibility than a full list (tuples are immutable), however anything can be stored in either a list or tuple, without any consistency being required. Tuples are defined using round brackets and lists are defined using square brackets. For example:
%% Cell type:code id: tags:
```
xtuple = (3, 7.6, 'str')
xlist = [1, 'mj', -5.4]
print(xtuple)
print(xlist)
```
%% Cell type:markdown id: tags:
They can also be nested:
%% Cell type:code id: tags:
```
x2 = (xtuple, xlist)
x3 = [xtuple, xlist]
print('x2 is: ', x2)
print('x3 is: ', x3)
```
%% Cell type:markdown id: tags:
<a class="anchor" id="Adding-to-a-list"></a>
### Adding to a list
This is easy:
%% Cell type:code id: tags:
```
a = [10, 20, 30]
a = a + [70]
a += [80]
print(a)
```
%% Cell type:markdown id: tags:
> Similar things can be done for tuples, except for the last one: that is,
> `a += (80)` as a tuple is immutable so cannot be changed like this.
> `a += (80)` because a tuple is immutable so cannot be changed like this.
<a class="anchor" id="Indexing"></a>
### Indexing
Square brackets are used to index tuples, lists, strings, dictionaries, etc. For example:
%% Cell type:code id: tags:
```
d = [10, 20, 30]
print(d[1])
```
%% Cell type:markdown id: tags:
> _*Pitfall:*_
> Python uses zero-based indexing, unlike MATLAB
%% Cell type:code id: tags:
```
a = [10, 20, 30, 40, 50, 60]
print(a[0])
print(a[2])
```
%% Cell type:markdown id: tags:
Indices naturally run from 0 to N-1, _but_ negative numbers can be used to
reference from the end (circular wrap-around).
%% Cell type:code id: tags:
```
print(a[-1])
print(a[-6])
```
%% Cell type:markdown id: tags:
However, this is only true for -1 to -N. Outside of -N to N-1 will generate an `index out of range` error.
%% Cell type:code id: tags:
```
print(a[-7])
```
%% Cell type:code id: tags:
```
print(a[6])
```
%% Cell type:markdown id: tags:
Length of a tuple or list is given by the `len()` function:
%% Cell type:code id: tags:
```
print(len(a))
```
%% Cell type:markdown id: tags:
Nested lists can have nested indexing:
%% Cell type:code id: tags:
```
b = [[10, 20, 30], [40, 50, 60]]
print(b[0][1])
print(b[1][0])
```
%% Cell type:markdown id: tags:
but *not* an index like `b[0, 1]`. However, numpy arrays (covered in a later practical) can be indexed like `b[0, 1]` and similarly for higher dimensions.
> Note that `len` will only give the length of the top level.
> In general, numpy arrays should be preferred to nested lists when the contents are numerical.
<a class="anchor" id="Slicing"></a>
### Slicing
A range of values for the indices can be specified to extract values from a list. For example:
%% Cell type:code id: tags:
```
print(a[0:3])
```
%% Cell type:markdown id: tags:
> _*Pitfall:*_
>
> Slicing syntax is different from MATLAB in that second number is
> exclusive (i.e., one plus final index) - this is in addition to the zero index difference.
%% Cell type:code id: tags:
```
a = [10, 20, 30, 40, 50, 60]
print(a[0:3]) # same as a(1:3) in MATLAB
print(a[1:3]) # same as a(2:3) in MATLAB
```
%% Cell type:markdown id: tags:
> _*Pitfall:*_
>
> Unlike in MATLAB, you cannot use a list as indices instead of an
> integer or a slice (although these can be done in `numpy`).
> integer or a slice (although this can be done in `numpy`).
%% Cell type:code id: tags:
```
b = [3, 4]
print(a[b])
```
%% Cell type:markdown id: tags:
In python you can leave the start and end values implicit, as it will assume these are the beginning and the end. For example:
%% Cell type:code id: tags:
```
print(a[:3])
print(a[1:])
print(a[:-1])
```
%% Cell type:markdown id: tags:
in the last example remember that negative indices are subject to wrap around so that `a[:-1]` represents all elements up to the penultimate one.
You can also change the step size, which is specified by the third value (not the second one, as in MATLAB). For example:
%% Cell type:code id: tags:
```
print(a[0:4:2])
print(a[::2])
print(a[::-1])
```
%% Cell type:markdown id: tags:
the last example is a simple way to reverse a sequence.
<a class="anchor" id="List-operations"></a>
### List operations
Multiplication can be used with lists, where multiplication implements replication.
%% Cell type:code id: tags:
```
d = [10, 20, 30]
print(d * 4)
```
%% Cell type:markdown id: tags:
There are also other operations such as:
%% Cell type:code id: tags:
```
d.append(40)
print(d)
d.extend([50, 60])
print(d)
d = d + [70, 80]
print(d)
d.remove(20)
print(d)
d.pop(0)
print(d)
```
%% Cell type:markdown id: tags:
> Note that `d.append([50,60])` would run but instead of adding two extra elements it only adds a single element, where this element is a list of length two, making a messy list. Try it and see if this is not clear.
<a class="anchor" id="Looping"></a>
### Looping over elements in a list (or tuple)
%% Cell type:code id: tags:
```
d = [10, 20, 30]
for x in d:
print(x)
```
%% Cell type:markdown id: tags:
> Note that the indentation within the loop is _*crucial*_. All python control blocks are delineated purely by indentation. We recommend using **four spaces** and no tabs, as this is a standard practice and will help a lot when collaborating with others.
<a class="anchor" id="Getting-help"></a>
### Getting help
The function `help()` can be used to get information about any variable/object/function in python. It lists the possible operations. In `ipython` you can also just type `?<blah>` or `<blah>?` instead:
%% Cell type:code id: tags:
```
help(d)
```
%% Cell type:markdown id: tags:
There is also a `dir()` function that gives a basic listing of the operations:
%% Cell type:code id: tags:
```
dir(d)
```
%% Cell type:markdown id: tags:
> Note that google is often more helpful! At least, as long as you find pages
> relating to Python 3 - Python 2 is no longer supported, but there is still
> lots of information about it on the internet, so be careful!
---
<a class="anchor" id="Dictionaries"></a>
## Dictionaries
These store key-value pairs. For example:
%% Cell type:code id: tags:
```
e = {'a' : 10, 'b': 20}
print(len(e))
print(e.keys())
print(e.values())
print(e['a'])
```
%% Cell type:markdown id: tags:
The keys and values can take on almost any type, even dictionaries!
Python is nothing if not flexible. However, each key must be unique
and [hashable](https://docs.python.org/3.5/glossary.html#term-hashable).
<a class="anchor" id="Adding-to-a-dictionary"></a>
### Adding to a dictionary
This is very easy:
%% Cell type:code id: tags:
```
e['c'] = 555 # just like in Biobank! ;)
print(e)
```
%% Cell type:markdown id: tags:
<a class="anchor" id="Removing-elements-dictionary"></a>
### Removing elements from a dictionary
There are two main approaches - `pop` and `del`:
%% Cell type:code id: tags:
```
e.pop('b')
print(e)
del e['c']
print(e)
```
%% Cell type:markdown id: tags:
<a class="anchor" id="Looping-dictionary"></a>
### Looping over everything in a dictionary
Several variables can jointly work as loop variables in python, which is very convenient. For example:
%% Cell type:code id: tags:
```
e = {'a' : 10, 'b': 20, 'c':555}
for k, v in e.items():
print((k, v))
```
%% Cell type:markdown id: tags:
The print statement here constructs a tuple, which is often used in python.
Another option is:
%% Cell type:code id: tags:
```
for k in e:
print((k, e[k]))
```
%% Cell type:markdown id: tags:
> In older versions of Python 3, there was no guarantee of ordering when using dictionaries.
> However, a of Python 3.7, dictionaries will remember the order in which items are inserted,
> and the `keys()`, `values()`, and `items()` methods will return elements in that order.
>
> If you want a dictionary with ordering, *and* you want your code to work with
> Python versions older than 3.7, you can use the
> [`OrderedDict`](https://docs.python.org/3/library/collections.html#collections.OrderedDict)
> class.
---
<a class="anchor" id="Copying-and-references"></a>
## Copying and references
In python there are immutable types (e.g. numbers) and mutable types (e.g. lists). The main thing to know is that assignment can sometimes create separate copies and sometimes create references (as in C++). In general, the more complicated types are assigned via references. For example:
%% Cell type:code id: tags:
```
a = 7
b = a
a = 2348
print(b)
```
%% Cell type:markdown id: tags:
As opposed to:
%% Cell type:code id: tags:
```
a = [7]
b = a
a[0] = 8888
print(b)
```
%% Cell type:markdown id: tags:
But if an operation is performed then a copy might be made:
%% Cell type:code id: tags:
```
a = [7]
b = a * 2
a[0] = 8888
print(b)
```
%% Cell type:markdown id: tags:
If an explicit copy is necessary then this can be made using the `list()` constructor:
%% Cell type:code id: tags:
```
a = [7]
b = list(a)
a[0] = 8888
print(b)
```
%% Cell type:markdown id: tags:
There is a constructor for each type and this can be useful for converting between types:
%% Cell type:code id: tags:
```
xt = (2, 5, 7)
xl = list(xt)
print(xt)
print(xl)
```
%% Cell type:markdown id: tags:
> _*Pitfall:*_
>
> When writing functions you need to be particularly careful about references and copies.
%% Cell type:code id: tags:
```
def foo1(x):
x.append(10)
print('x: ', x)
def foo2(x):
x = x + [10]
print('x: ', x)
def foo3(x):
print('return value: ', x + [10])
return x + [10]
a = [5]
print('a: ', a)
foo1(a)
print('a: ', a)
foo2(a)
print('a: ', a)
b = foo3(a)
print('a: ', a)
print('b: ', b)
```
%% Cell type:markdown id: tags:
> Note that we have defined some functions here - and the syntax
> should be relatively intuitive. See <a href="#functions">below</a>
> for a bit more detail on function definitions.
---
<a class="anchor" id="Control-flow"></a>
## Control flow
<a class="anchor" id="Boolean-operators"></a>
### Boolean operators
There is a boolean type in python that can be `True` or `False` (note the
capitals). Other values can also be used for True or False (e.g., `1` for
`True`; `0` or `None` or `[]` or `{}` or `""` for `False`) although they are
not considered 'equal' in the sense that the operator `==` would consider them
the same.
Relevant boolean and comparison operators include: `not`, `and`, `or`, `==` and `!=`
Relevant boolean and comparison operators include: `not`, `and`, `or`, `==` and `!=`.
For example:
%% Cell type:code id: tags:
```
a = True
print('Not a is:', not a)
print('Not 1 is:', not 1)
print('Not 0 is:', not 0)
print('Not {} is:', not {})
print('{}==0 is:', {}==0)
```
%% Cell type:markdown id: tags:
There is also the `in` test for strings, lists, etc:
%% Cell type:code id: tags:
```
print('the' in 'a number of words')
print('of' in 'a number of words')
print(3 in [1, 2, 3, 4])
```
%% Cell type:markdown id: tags:
A useful keyword is `None`, which is a bit like "null". This can be a default value for a variable and should be tested with the `is` operator rather than `==` (for technical reasons that it isn't worth going into here). For example: `a is None` or `a is not None` are the preferred tests.
A useful keyword is `None`, which is a bit like "null".
This can be a default value for a variable and should be tested with the `is` operator rather than `==` (for technical reasons that it isn't worth going into here). For example: `a is None` or `a is not None` are the preferred tests.
Do not use the `is` instead of the `==` operator for any other comparisons (unless you know what you are doing).
<a class="anchor" id="If-statements"></a>
### If statements
The basic syntax of `if` statements is fairly standard, though don't forget that you _*must*_ indent the statements within the conditional/loop block as this is the way of delineating blocks of code in python. For example:
%% Cell type:code id: tags:
```
import random
a = random.uniform(-1, 1)
print(a)
if a>0:
print('Positive')
elif a<0:
print('Negative')
else:
print('Zero')
```
%% Cell type:markdown id: tags:
Or more generally:
%% Cell type:code id: tags:
```
a = [] # just one of many examples
if not a:
print('Variable is true, or at least not empty')
```
%% Cell type:markdown id: tags:
This can be useful for functions where a variety of possible input types are being dealt with.
---
<a class="anchor" id="For-loops"></a>
### For loops
The `for` loop works like in bash:
%% Cell type:code id: tags:
```
for x in [2, 'is', 'more', 'than', 1]:
print(x)
```
%% Cell type:markdown id: tags:
where a list or any other sequence (e.g. tuple) can be used.
If you want a numerical range then use:
%% Cell type:code id: tags:
```
for x in range(2, 9):
print(x)
```
%% Cell type:markdown id: tags:
Note that, like slicing, the maximum value is one less than the value specified. Also, `range` actually returns an object that can be iterated over but is not just a list of numbers. If you want a list of numbers then `list(range(2, 9))` will give you this.
A very nice feature of python is that multiple variables can be assigned from a tuple or list:
%% Cell type:code id: tags:
```
x, y = [4, 7]
print(x)
print(y)
```
%% Cell type:markdown id: tags:
and this can be combined with a function called `zip` to make very convenient dual variable loops:
%% Cell type:code id: tags:
```
alist = ['Some', 'set', 'of', 'items']
blist = list(range(len(alist)))
print(list(zip(alist, blist)))
for x, y in zip(alist, blist):
print(y, x)
```
%% Cell type:markdown id: tags:
This type of loop can be used with any two lists (or similar) to iterate over them jointly.
<a class="anchor" id="While-loops"></a>
### While loops
The syntax for this is pretty standard:
%% Cell type:code id: tags:
```
import random
n = 0
x = 0
while n<100:
x += random.uniform(0, 1)**2 # where ** is a power operation
if x>50:
break
n += 1
print(x)
```
%% Cell type:markdown id: tags:
You can also use `continue` as in other languages.
> Note that there is no `do ... while` construct.
---
<a class="anchor" id="quick-intro"></a>
### A quick intro to conditional expressions and list comprehensions
These are more advanced bits of python but are really useful and common, so worth having a little familiarity with at this stage.
<a class="anchor" id="Conditional-expressions"></a>
#### Conditional expressions
A general expression that can be used in python is: A `if` condition `else` B
For example:
%% Cell type:code id: tags:
```
import random
x = random.uniform(0, 1)
y = x**2 if x<0.5 else (1 - x)**2
print(x, y)
```
%% Cell type:markdown id: tags:
<a class="anchor" id="List-comprehensions"></a>
#### List comprehensions
This is a shorthand syntax for building a list like a for loop but doing it in one line, and is very popular in python. It is quite similar to mathematical set notation. For example:
%% Cell type:code id: tags:
```
v1 = [ x**2 for x in range(10) ]
print(v1)
v2 = [ x**2 for x in range(10) if x!=7 ]
print(v2)
```
%% Cell type:markdown id: tags:
You'll find that python programmers use this kind of construction _*a lot*_.
---
<a class="anchor" id="functions"></a>
## Functions
You will find functions pretty familiar in python to start with,
although they have a few options which are really handy and different
from C++ or matlab (to be covered in a later practical). To start
with we'll look at a simple function but note a few key points:
* you _must_ indent everything inside the function (it is a code
block and indentation is the only way of determining this - just
like for the guts of a loop)
* you can return _whatever you want_ from a python function, but only
a single object - it is usual to package up multiple things in a
tuple or list, which is easily unpacked by the calling invocation:
e.g., `a, b, c = myfunc(x)`
* parameters are passed by reference (see section on <a
href="#Copying-and-references">copying and references</a>)
%% Cell type:code id: tags:
```
def myfunc(x, y, z=0):
r2 = x*x + y*y + z*z
r = r2**0.5
return r, r2
rad = myfunc(10, 20)
print(rad)
rad, dummy = myfunc(10, 20, 30)
print(rad)
rad, _ = myfunc(10,20,30)
print(rad)
```
%% Cell type:markdown id: tags:
> Note that the `_` is used as shorthand here for a dummy variable
> that you want to throw away.
>
> The return statement implicitly creates a tuple to return and is equivalent to `return (r, r2)`
One nice feature of python functions is that you can name the
arguments when you call them, rather than only doing it by position.
For example:
%% Cell type:code id: tags:
```
def myfunc(x, y, z=0, flag=''):
if flag=='L1':
r = abs(x) + abs(y) + abs(z)
else:
r = (x*x + y*y + z*z)**0.5
return r
rA = myfunc(10, 20)
rB = myfunc(10, 20, flag='L1')
rC = myfunc(10, 20, flag='L1', z=30)
print(rA, rB, rC)
```
%% Cell type:markdown id: tags:
You will often see python functions called with these named arguments. In fact, for functions with more than 2 or 3 variables this naming of arguments is recommended, because it clarifies what each of the arguments does for anyone reading the code.
---
<a class="anchor" id="exercise"></a>
## Exercise
Let's say you are given a single string with comma separated elements
that represent filenames and ID codes: e.g., `/vols/Data/pytreat/AAC, 165873, /vols/Data/pytreat/AAG, 170285, ...`
Write some code to do the following:
* separate out the filenames and ID codes into separate lists (ID's
should be numerical values, not strings) - you may need several steps for this
* loop over the two and generate a _string_ that could be used to
rename the directories (e.g., `mv /vols/Data/pytreat/AAC /vols/Data/pytreat/S165873`) - we will cover how to actually execute these in a later practical
* convert your dual lists into a dictionary, with ID as the key
* write a small function to determine if an ID is present in this
set of not, and also return the filename if it is
* write a for loop to create a list of all the odd-numbered IDs (you can use the `%` operator for modulus - i.e., `5 % 2` is 1)
* re-write the for loop as a list comprehension
* now generate a list of the filenames corresponding to these odd-numbered IDs
%% Cell type:code id: tags:
```
mstr = '/vols/Data/pytreat/AAC, 165873, /vols/Data/pytreat/AAG, 170285, /vols/Data/pytreat/AAH, 196792, /vols/Data/pytreat/AAK, 212577, /vols/Data/pytreat/AAQ, 385376, /vols/Data/pytreat/AB, 444600, /vols/Data/pytreat/AC6, 454578, /vols/Data/pytreat/V8, 501502, /vols/Data/pytreat/2YK, 667688, /vols/Data/pytreat/C3PO, 821971'
```
......
......@@ -63,7 +63,7 @@ Python has many different types and variables are dynamic and can change types (
* lists
* dictionaries
N-dimensional arrays and other types are supported through common modules (e.g., numpy, scipy, scikit-learn). These will be covered in a subsequent exercise.
N-dimensional arrays and other types are supported through common modules (e.g., [numpy](https://numpy.org/), [scipy](https://docs.scipy.org/doc/scipy-1.4.1/reference/), [scikit-learn](https://scikit-learn.org/stable/)). These will be covered in a subsequent exercises.
```
a = 4
......@@ -114,28 +114,20 @@ print(s3)
<a class="anchor" id="Format"></a>
### Format
More interesting strings can be created using the
[`format`](https://docs.python.org/3/library/string.html#formatstrings)
statement, which is very useful in print statements:
More interesting strings can be created using an [f-string](https://realpython.com/python-f-strings/),
which is very useful in print statements:
```
x = 1
y = 'PyTreat'
s = 'The numerical value is {} and a name is {}'.format(x, y)
s = f'The numerical value is {x} and a name is {y}'
print(s)
print('A name is {} and a number is {}'.format(y, x))
print(f'A name is {y} and a number is {x}')
```
Note the `f` before the initial quote. This lets python know to fill in the variables between the curly brackets.
Python also supports C-style [`%`
formatting](https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting):
```
x = 1
y = 'PyTreat'
s = 'The numerical value is %i and a name is %s' % (x, y)
print(s)
print('A name is %s and a number is %i' % (y, x))
```
There are also other options along these lines, which will be discussed in the next practical.
This is the more modern version, although you will see plenty of the other alternatives in "old" code
(to python coders this means anything written before last week).
<a class="anchor" id="String-manipulation"></a>
### String manipulation
......@@ -263,7 +255,7 @@ print(a)
```
> Similar things can be done for tuples, except for the last one: that is,
> `a += (80)` as a tuple is immutable so cannot be changed like this.
> `a += (80)` because a tuple is immutable so cannot be changed like this.
<a class="anchor" id="Indexing"></a>
### Indexing
......@@ -337,7 +329,7 @@ print(a[1:3]) # same as a(2:3) in MATLAB
> _*Pitfall:*_
>
> Unlike in MATLAB, you cannot use a list as indices instead of an
> integer or a slice (although these can be done in `numpy`).
> integer or a slice (although this can be done in `numpy`).
```
b = [3, 4]
......@@ -574,7 +566,7 @@ capitals). Other values can also be used for True or False (e.g., `1` for
not considered 'equal' in the sense that the operator `==` would consider them
the same.
Relevant boolean and comparison operators include: `not`, `and`, `or`, `==` and `!=`
Relevant boolean and comparison operators include: `not`, `and`, `or`, `==` and `!=`.
For example:
```
......@@ -594,7 +586,9 @@ print(3 in [1, 2, 3, 4])
```
A useful keyword is `None`, which is a bit like "null". This can be a default value for a variable and should be tested with the `is` operator rather than `==` (for technical reasons that it isn't worth going into here). For example: `a is None` or `a is not None` are the preferred tests.
A useful keyword is `None`, which is a bit like "null".
This can be a default value for a variable and should be tested with the `is` operator rather than `==` (for technical reasons that it isn't worth going into here). For example: `a is None` or `a is not None` are the preferred tests.
Do not use the `is` instead of the `==` operator for any other comparisons (unless you know what you are doing).
<a class="anchor" id="If-statements"></a>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment