Python (very basic) Basics#

Warning

Python Starts counting at 0 unlike R or Matlab which start at 1

Python code can be directly executed from the command line (no need to compile) or by creating a text file with a *.py extension.

Python Console

Indentation#

A key difference of Python compared to most other programming languages is that in Python indentation matters (the spaces at the beginning of every line of code). Python uses indentation to deliminate blocks of code. The number of spaces you use is up to you but you need to be consistent. Commonly 4 spaces are used.
Example:

print("This is the first line of the code") 
a = 10 
print("Here we add an if statement")
if a > 5:
    print(a)
else:
    print("a is < 5")

If you were to skip the indentation, Python will throw an error:

IndentationError: expected an indented block
This might feel like a nuissance at first, but after a while it will feel natural and keep your code organised.

Note

R - {}

In R, a consistent use of indentation will make code much easier to read but is not strictly necessary. Functions, loops and statemtent are delimited by {}.
Example:

print("This is the first line of the code") 
a = 10 
print("Here we add an if statement")
if (a > 5){
    print(a)
}else{
    print("a is < 5")
}

Note

Matlab - end

In Matlab, a consistent use of indentation will make code much easier to read but is not strictly necessary. Ending each line with ; will prevent printing the result to the console. Functions loops and statements are closed by end.
Example

disp("This is the first line of the code");
a = 10;
disp("Here we add an if statement");
if a > 5;
    disp(a);
else
    disp("a is < 5");
end

Comments and docstrings#

Code you be easy to understand for anyone who picks it up. Therefore commenting is very important.
Commenting in Pyhton can be done on a module-level docstrings (describing functions) or as inline expalanations, what is happenign in the code.

Commenting#

Whatever you wrtie after # will be considered a comment and will be ignored during code execution. Example:

# This code will run, but nothing happend, because this is a comment

Python unfortunatley only supports single line commenting (unlike other languarges like Jave for example where everyting between /* and *\ is considered a comment or in Matlab where %{ and }% allows for multiline commenting). One workaround is to start multiple lines with # or to use:

"""
This is a pseudo  multi-line comment
In reality it is only a string
"""

Docsctring#

Doscstrings are multi-line strings, tyoically used to document and describe functions, classes, and modules. By convention they are places as first statement inside code blocks and can be called through funciton.__doc__ or through help(function)

def wave_length(c, f):
    """
    Returns the wavelength of a wave

    Parameters:
    c (int or float): Sound velocity (m/s)
    f (int or float): Frequency (Hz)

    Return:
    float: the wave length in m
    """
    return c / f

We can read the documentaiton by calling:

wave_length.__doc__
'\n    Returns the wavelength of a wave\n\n    Parameters:\n    c (int or float): Sound velocity (m/s)\n    f (int or float): Frequency (Hz)\n\n    Return:\n    float: the wave length in m\n    '

Or by using the help function:

help(wave_length)
Help on function wave_length in module __main__:

wave_length(c, f)
    Returns the wavelength of a wave

    Parameters:
    c (int or float): Sound velocity (m/s)
    f (int or float): Frequency (Hz)

    Return:
    float: the wave length in m

When to use docstring and when comments?#

Purpose

Placement

Execution

Comments (#)

Explain a specific part of the code

Anywhere in the code

Ignored by Python

Docstrings (“”” “””)

Document and describe functions, classes or modules

Always at the beginning of a class, function or module

Stored as metadata (.doc)

Hint

R
Docstrings are somewhat analogous to Roxygen documentaiton in R. The recommended oconvention to document and describe function in R is by using #' . Similarly to the help() command in Python, in R ``?function``` will provide the description.

#' Returns the wavelength of a wave
#'
#' @param c float or int,  Sound velocity (m/s) 
#' @param f float or int, Frequency in Hz 
#'
#' @return
#' @export
#'
#' @examples
#' wave_length(1500, 38000)
wave_length = function(c, f){
    return c/f
}

Classes#

Classes can be seen as containers of specific functions and variables. Let’s think of a class called AcousticWave which we want to use to describe a number of properties of an acoustic wave, like the wave length:

class AcousticWave

Functions#

In Python functions are defined as:

def function_name(v1, v2):
    results = some stuff is happening with the variables
    return results

Functions are starting with def followed by the function name with the dependent variables in brackets. This line ends by :.
The following lines are indented to deliminate the space specific to the given function. The function end typically with a return call. returndefines the output of the function (what is returned from the function).

In our example of the wave length, the function would be wave_length, dependent on the soundspeed c and the frequency f as wave_length \(= \frac{c}{f} [m]\)

def wave_length(c, f):
  return c / f

Note

Python functions compared to R and Matlab The way functions are written in Python is analoguous to R and Matlab:
R

  function_name = function(v1, v2){
      results = some  stuff is happening with the variables
      return(results)
  }

Note

Matlab:

  function [result] = function_name(v1, v2)
       results = some stuff is happening with the variables
  end

Special case: lambda functions

Variables#

Variables can be user defined or defined by initial values. In our examples these would be the sound speed c and frequency f

For example imagine a class AcousticWave which we use to describe acoustic waves. The properties of the acoustic wave depend on variables, that we want the user to provide. These could be c the soundspeed in m/s and f the frequency in Hz. The properties we want to describe could be wave length defined by a function wave_length that depends on c and f

A very minimalistic example would be:

Tip

Naming convention for classes , funcitons and variables
Class names should normally use the CapWords naming convention, e.g. AcousticWave
Variable and Function names should generally by lowercase, with words separated by underscores, e.g. wave_length

  • Mathematical operations:

Python

Operation

Result

a = 3

a = 3 (define or assign)

3

b = 4

b = 4 (define or assign)

4

a + b

Sum a and b (addition)

7

a - b

Subtract b from a (subtraction)

-1

a * b

a times b (multiplicaiton)

12

a / b

a divided by b (division)

0.75

a // b

Integer part of a divided by b (floor division)

0

a % b

Rest of a divided by b (modulus)

3

a**b

a to the power of b (exponention)

81

Warning

The basic mathematical operations are analoguous to R and Matlab with the exception of a**bwhich would be a^bin R or Matlab.

For a lot of other mathematical operations or constants, we need to import the math module:

import math
print(math.e) #Euler's number
print(math.inf ) #positinve infinity floating point number
print(math.nan) #floating point not a number value
print(math.pi) #number pi
print(math.tau) #math tau
2.718281828459045
inf
nan
3.141592653589793
6.283185307179586

Besides these mathematical constants, the math module also contains geomatric funcitons (e.g. math.cos(), math.acos(), math.sin(), math.atan2(), math.hypot()), transformations (math.degrees() - radians to degrees, math.radians() - degrees to radians, math.dist() - euclidean distance, math.close() - checks if values are close to each other), and log functions (e.g. math.log(), math.log10()) and many more.

Python core data structure#

There a re 4 core data structures in Python:

  • List: a collection of values, can be ordered and is changeable. Allows duplicate members.

  • Tuple: a collection which can be ordered and is unchangeable. Allows duplicate members.

  • Set: a collection which is unordered, unchangeable, unindexed. No duplicate members (duplicates ar eremoved). Items can’t be changed but can be removed or added.

  • Dictionary: a collection which is ordered (as of Python 3.7) and changeable. No duplicate members.

Lists#

Are used to store sequences of items, and can hold a mix of data types like strings, integegers and floats. Lists are defined by [].

List operation

Python

Result

List of numbers

int_list = [1, 5, 3, 22, 7, 10]

[1, 5, 3, 22, 7, 10]

List of strings

str_list = ['e','c','h', 'o', 'p','y', 'p', 'e']

['e','c','h', 'o', 'p','y', 'p', 'e']

List with mixed types

mixed_list = ["EK", 80, "38 kHz", 7, "CD"]

['EK', 80, '38 kHz', 7, 'CD']

Access element at first position

mixed_list[0]

'EK'

Access element at fourth position

mixed_list[3]

'7'

Replace an element in a list

int_list[2] = 4

[1, 5, 4, 22, 7, 10]

Get the number of elements in the list

len(mixed_list)

5

Add element to the end of a list

mixed_list.append('ME70')

['EK', 80, '38 kHz', 7, 'CD', 'ME70']

Add element to the 6th position of a list

mixed_list.insert([5, 'Simrad'])

['EK', 80, '38 kHz', 7, 'CD','Simrad' ,'ME70']

Extend list by a list

mixed_list.extend([24,18,36,'ME70','Beam'])

['EK', 80, '38 kHz', 7, 'CD', 'ME70', 24, 18, 36, 'ME70', 'Beam']

Count occurences of an element in a list

mixed_list.count['ME70']

2

Clear list

mixed_list.clear()

[]

Sort list alphabetically or ascending

str_list.sort()

['c', 'e', 'e', 'h', 'o', 'p', 'p', 'y']

Sort list descending

int_list.sort(reverse=True)

[22, 10, 7, 5, 4, 1]

Remove elment from list

int_list.remove(5)

List of lists can be used as matrix structures. We can create a 3x3 grid as a nested list of 3 lists:

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
matrix
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

We can access items with double indices:

matrix[1][2]
6

Tuples#

Tuples are immutable - once created, the elments can’t be changed anymore. Tuples are used if you need data to be read only.

Tuple Operation

Python

Result

Create a tuple

num_tup = (1,2,3)

(1,2,3)

Append values to a tuple

num_tup = num_tup + (4,5,6)

(1,2,3,4,5,6)

Repeat a tuple multiple times

num_tup = num_tup * 3

(1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6)

Get index of first occurence of a value

num_tup.index(5)

4

Count number of occurences of a value

num_tup.count(5)

3

Sets#

Sets are collections of unique items, duplicates are removed automatically. Sets are handy for operations like union (combine), intersection or difference:

Sets operation

Python

Result

Define a Set of unique numbers (duplicates are removed)

num_set={1, 2, 2, 3, 3, 1, 4, 5}

{1,2,3,4,5}

Define a second Set of numbers

num_set2 = {4, 5, 6, 7, 8}

{4, 5, 6, 7, 8}

Combine the two Sets

(num_set|num_set2)

{1, 2, 3, 4, 5, 6, 7, 8}

Intersection of the two Sets
Elements present in both Sets

num_set & num_set2

{4, 5}

Difference the two Sets
Elements unique to the first Set

num_set - num_set2

{1, 2, 3}

Add a value to a Set

num_set.add(6)

{1, 2, 3, 4, 5, 6}

Remove a value from a Set

num_set.remove(1)

{2, 3, 4, 5, 6}

Check if value is in a Set

6 in num_set

True

Dictionaries#

Dictionnaries store data in a key-value structure. Dictionnaries are useful for iterating (for tasks, such as filtering, sorting and grouping) over keys, values or items.

{"key":"value"}
{'key': 'value'}

We could create a nested dictionary containing the center frequency (kHz), maximum transmit power (W), the nominal 3dB beamwidth \(\theta_{3dB}\) (°), and the transducer area (\(10^{-3}\) m) for commonly used echosounders:

max_trans_power = {
    "EK18_11": {
        "frequency_kHz": 18,
        "transducer_area":200,
        "beamwidth_3dB":11,
        "power":5000
    },
    "EK38_7": {  
        "frequency_kHz": 38,
        "transducer_area":100,
        "beamwidth_3dB":7,
        "power":2500
    },
    "EK70_7": {  
        "frequency_kHz": 70,
        "transducer_area":30,
        "beamwidth_3dB":7,
        "power":750
    },
    "EK70_11": {  
        "frequency_kHz": 70,
        "transducer_area":12,
        "beamwidth_3dB":11,
        "power":300
    },
    "EK120_7": {  
        "frequency_kHz": 120,
        "transducer_area":10,
        "beamwidth_3dB":7,
        "power":250
    },
    "EK200_7": {  
        "frequency_kHz": 200,
        "transducer_area":4.4,
        "beamwidth_3dB":7,
        "power":110
    },
    "EK333_7": {  
        "frequency_kHz": 333,
        "transducer_area":100,
        "beamwidth_3dB":7,
        "power":2500
    }
}

Now we just quickly extract the transducer names and the maximum power:

power_dict = {key: vals["power"] for key, vals in max_trans_power.items()}
power_dict
{'EK18_11': 5000,
 'EK38_7': 2500,
 'EK70_7': 750,
 'EK70_11': 300,
 'EK120_7': 250,
 'EK200_7': 110,
 'EK333_7': 2500}

We can use this information to find the transducers with the highest maximum operating power:

max(power_dict, key=power_dict.get)
'EK18_11'

We can also list all echosounder names with a maximum operating power > 1000 W:

keys = list(filter(lambda key: power_dict[key] > 1e3, power_dict))
keys
['EK18_11', 'EK38_7', 'EK333_7']