{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "This section is meant as a general introduction to Python and is by far not complete. It is based amongst others on the [IPython notebooks from J. R. Johansson](http://github.com/jrjohansson/scientific-python-lectures), on http://www.stavros.io/tutorials/python/ and on http://www.swaroopch.com/notes/python.\n", "\n", "Important: a very good interactive tutorial for Python can also be found on https://www.codecademy.com/learn/python" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The goal of this section is to give you a short introduction to Python and help beginners to get familiar with this programming language.\n", "\n", "Following chapters are available:\n", "\n", "- [Module](#Module)\n", "- [Help and Descriptions](#Help-and-Descriptions)\n", "- [Variables and types](#Variables-and-types)\n", " - [Symbol names](#Symbol-names)\n", " - [Assignment](#Assignment)\n", " - [Fundamental types](#Fundamental-types)\n", "- [Operators and comparisons](#Operators-and-comparisons)\n", " - [Shortcut math operation and assignment](#Shortcut-math-operation-and-assignment)\n", "- [Strings, List and dictionaries](#Strings,-List-and-dictionaries)\n", " - [Strings](#Strings)\n", " - [List](#List)\n", " - [Tuples](#Tuples)\n", " - [Dictionaries](#Dictionaries)\n", "- [Indentation](#Indentation)\n", "- [Control Flow](#Control-Flow)\n", " - [Conditional statements: `if`, `elif`, `else`](#Conditional-statements:-if,-elif,-else)\n", "- [Loops](#Loops)\n", " - [`for` loops](#for-loops)\n", " - [`break`, `continue` and `pass`](#break,-continue-and-pass)\n", "- [Functions](#Functions)\n", " - [Default argument and keyword arguments](#Default-argument-and-keyword-arguments)\n", " - [`*args` and `*kwargs` parameters](#*args-and-*kwargs-parameters)\n", " - [Unnamed functions: `lambda` function](#Unnamed-functions:-lambda-function)\n", "- [Classes](#Classes)\n", "- [Modules](#Modules)\n", "- [Exceptions](#Exceptions)\n", "- [File I/O](#File-I/O)\n", " - [Reading CSV files](#Reading-CSV-files)\n", " - [Writing CSV files](#Writing-CSV-files)\n", " - [Reading TXT files](#Reading-TXT-files)\n", " - [Writing TXT files](#Writing-TXT-files)\n", " - [with open](#with-open)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Module\n", "\n", "Most of the functionality in Python is provided by *modules*. To use a module in a Python program it first has to be imported. A module can be imported using the `import` statement. For example, to import the module `math`, which contains many standard mathematical functions, we can do:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import math" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This includes the whole module and makes it available for use later in the program. For example, we can do:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.0\n" ] } ], "source": [ "import math\n", "\n", "x = math.cos(2 * math.pi)\n", "\n", "print(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Importing the whole module us often times unnecessary and can lead to longer loading time or increase the memory consumption. An alternative to the previous method, we can also choose to import only a few selected functions from a module by explicitly listing which ones we want to import:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.0\n" ] } ], "source": [ "from math import cos, pi\n", "\n", "x = cos(2 * pi)\n", "\n", "print(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is also possible to give an imported module or symbol your own access name with the `as` additional:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "180.0\n" ] } ], "source": [ "import numpy as np\n", "from math import pi as number_pi\n", "\n", "x = np.rad2deg(number_pi)\n", "\n", "print(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Help and Descriptions\n", "\n", "Using the function `help` we can get a description of almost all functions. " ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on built-in function log in module math:\n", "\n", "log(...)\n", " log(x, [base=math.e])\n", " Return the logarithm of x to the given base.\n", " \n", " If the base not specified, returns the natural logarithm (base e) of x.\n", "\n" ] } ], "source": [ "help(math.log)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.302585092994046" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "math.log(10)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.3219280948873626" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "math.log(10, 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Variables and types\n", "\n", "\n", "### Symbol names \n", "\n", "Variable names in Python can contain alphanumerical characters `a-z`, `A-Z`, `0-9` and some special characters such as `_`. Normal variable names must start with a letter. \n", "\n", "By convention, variable names start with a lower-case letter, and Class names start with a capital letter. \n", "\n", "In addition, there are a number of Python keywords that cannot be used as variable names. These keywords are:\n", "\n", " and, as, assert, break, class, continue, def, del, elif, else, except, exec, finally, for, from, global, if, import, in, is, lambda, not, or, pass, print, raise, return, try, while, with, yield" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Assignment\n", "\n", "The assignment operator in Python is `=`. Python is a dynamically typed language, so we do not need to specify the type of a variable when we create one.\n", "\n", "Assigning a value to a new variable creates the variable:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "# variable assignments\n", "x = 1.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Although not explicitly specified, a variable does have a type associated with it. The type is derived from the value it was assigned." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "float" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we assign a new value to a variable, its type can change." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "x = 1" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "int" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we try to use a variable that has not yet been defined we get an `NameError` (Note, that we will use in the notebooks `try/except` blocks to handle the exception, so the notebook doesn't stop. The code below will try to execute `print` function and if the `NameError` occurs the error message will be printed. Otherwise, an error will be raised. Later in this notebook you will learn more about exception handling.):" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "NameError name 'y' is not defined\n" ] } ], "source": [ "try:\n", " print(y)\n", "except(NameError) as err:\n", " print(\"NameError\", err)\n", "else:\n", " raise" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Fundamental types" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "int" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# integers\n", "x = 1\n", "type(x)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "float" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# float\n", "x = 1.0\n", "type(x)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "bool" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# boolean\n", "b1 = True\n", "b2 = False\n", "\n", "type(b1)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "str" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# string\n", "s = \"hello world\"\n", "\n", "type(s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Operators and comparisons\n", "\n", "Most operators and comparisons in Python work as one would expect:\n", "\n", "* Arithmetic operators `+`, `-`, `*`, `/`, `**` power, `%` modulo\n" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[3, -1, 2, 1]" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[1 + 2, \n", " 1 - 2,\n", " 1 * 2,\n", " 1 % 2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In Python 2.7, what kind of division (`/`) will be executed, depends on the type of the numbers involved. If all numbers are integers, the division will be an integer division, otherwise, it will be a float division. In Python 3 this has been changed and fractions aren't lost when dividing integers (for integer division you can use another operator, `//`). " ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.5\n", "0.5\n" ] } ], "source": [ "# In Python 3 these two operations will give the same result\n", "# (in Python 2 the first one will be treated as an integer division). \n", "print(1 / 2)\n", "print(1 / 2.0)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Note! The power operator in python isn't ^, but **\n", "2 ** 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* The boolean operators are spelled out as words `and`, `not`, `or`. " ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "True and False" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "not False" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "True or False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Comparison operators `>`, `<`, `>=` (greater or equal), `<=` (less or equal), `==` (equal), `!=` (not equal) and `is` (identical)." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(True, False)" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2 > 1, 2 < 1" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(False, False)" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2 > 2, 2 < 2" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(True, True)" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2 >= 2, 2 <= 2" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# equal to\n", "[1,2] == [1,2]" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# not equal to\n", "2 != 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- boolean operator" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "False\n", "True\n" ] } ], "source": [ "x = True\n", "y = False\n", "\n", "print(not x)\n", "print(x and y)\n", "print(x or y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- String comparison" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"lo W\" in \"Hello World\"" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"x\" not in \"Hello World\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Shortcut math operation and assignment" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4\n" ] } ], "source": [ "a = 2\n", "a = a * 2\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The command `a = a * 2`, can be shortcut to `a *= 2`. This also works with `+=`, `-=` and `/=`." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "9\n" ] } ], "source": [ "b = 3\n", "b *= 3\n", "print(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Strings, List and dictionaries\n", "\n", "### Strings\n", "\n", "Strings are the variable type that is used for storing text messages. " ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "str" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s = \"Hello world\"\n", "type(s)" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "11" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# length of the string: number of characters in string\n", "len(s)" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello test\n" ] } ], "source": [ "# replace a substring in a string with something else\n", "s2 = s.replace(\"world\", \"test\")\n", "print(s2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can index a character in a string using `[]`:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'H'" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Heads up MATLAB users:** Indexing start at 0!\n", "\n", "We can extract a part of a string using the syntax `[start:stop]`, which extracts characters between index `start` and `stop`:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello'" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s[0:5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we omit either (or both) of `start` or `stop` from `[start:stop]`, the default is the beginning and the end of the string, respectively:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello'" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s[:5]" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'world'" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s[6:]" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello world'" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s[:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also define the step size using the syntax `[start:end:step]` (the default value for `step` is 1, as we saw above):" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello world'" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s[::1]" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hlowrd'" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s[::2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This technique is called *slicing*." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### String formatting examples" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "str1str2str3\n" ] } ], "source": [ "print(\"str1\" + \"str2\" + \"str3\") # strings added with + are concatenated without space" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "str1str2str3\n", "str1 str2 str3\n", "('str1', 'str2', 'str3')\n" ] } ], "source": [ "print(\"str1\" \"str2\" \"str3\") # The print function concatenates strings differently\n", "print(\"str1\", \"str2\", \"str3\") # depending on how the inputs are specified\n", "print((\"str1\", \"str2\", \"str3\")) # See the three different outputs below" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "str1 1.0 False\n" ] } ], "source": [ "print(\"str1\", 1.0, False) # The print function converts all arguments to strings" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "value = 1.000000\n" ] } ], "source": [ "print(\"value = %f\" %1.0) # we can use C-style string formatting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python has two string formatting styles. An example of the old style is below, specifier `%.2f` transforms the input number into a string, that corresponds to a floating point number with 2 decimal places and the specifier `%d` transforms the input number into a string, corresponding to a decimal number." ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "value1 = 3.14. value2 = 1\n" ] } ], "source": [ "s2 = \"value1 = %.2f. value2 = %d\" % (3.1415, 1.5)\n", "\n", "print(s2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The same string can be written using the new style string formatting." ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "value1 = 3.14, value2 = 1.5\n" ] } ], "source": [ "s3 = 'value1 = {:.2f}, value2 = {}'.format(3.1415, 1.5)\n", "\n", "print(s3)" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Newlines are indicated by \n", "And tabs by \t.\n", "Newlines are indicated by \\nAnd tabs by \\t. Printed as rawstring\n" ] } ], "source": [ "print(\"Newlines are indicated by \\nAnd tabs by \\t.\")\n", "\n", "print(r\"Newlines are indicated by \\nAnd tabs by \\t. Printed as rawstring\")" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Name: Nipype\n", "Number: 3\n", "String: ---\n" ] } ], "source": [ "print(\"Name: {}\\nNumber: {}\\nString: {}\".format(\"Nipype\", 3, 3 * \"-\"))" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "This is\n", "a multiline\n", "string.\n" ] } ], "source": [ "strString = \"\"\"This is\n", "a multiline\n", "string.\"\"\"\n", "print(strString)" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "This is a test.\n" ] } ], "source": [ "print(\"This {verb} a {noun}.\".format(noun = \"test\", verb = \"is\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "\n", "\n", "#### Single Quote\n", "You can specify strings using single quotes such as `'Quote me on this'`.\n", "All white space i.e. spaces and tabs, within the quotes, are preserved as-is.\n", "\n", "#### Double Quotes\n", "Strings in double quotes work exactly the same way as strings in single quotes. An example is `\"What's your name?\"`.\n", "\n", "#### Triple Quotes\n", "\n", "You can specify multi-line strings using triple quotes - (`\"\"\"` or `'''`). You can use single quotes and double quotes freely within the triple quotes. An example is:" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'This is a multi-line string. This is the first line.\\nThis is the second line.\\n\"What\\'s your name?,\" I asked.\\nHe said \"Bond, James Bond.\"\\n'" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'''This is a multi-line string. This is the first line.\n", "This is the second line.\n", "\"What's your name?,\" I asked.\n", "He said \"Bond, James Bond.\"\n", "'''" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### List\n", "\n", "Lists are very similar to strings, except that each element can be of any type.\n", "\n", "The syntax for creating lists in Python is `[...]`:" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "[1, 2, 3, 4]\n" ] } ], "source": [ "l = [1,2,3,4]\n", "\n", "print(type(l))\n", "print(l)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use the same slicing techniques to manipulate lists as we could use on strings:" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 2, 3, 4]\n", "[2, 3]\n", "[1, 3]\n" ] } ], "source": [ "print(l)\n", "print(l[1:3])\n", "print(l[::2])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Heads up MATLAB users:** Indexing starts at 0!" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Elements in a list do not all have to be of the same type:" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 'a', 1.0]\n" ] } ], "source": [ "l = [1, 'a', 1.0]\n", "\n", "print(l)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python lists can be inhomogeneous and arbitrarily nested:" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, [2, [3, [4, [5]]]]]" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nested_list = [1, [2, [3, [4, [5]]]]]\n", "\n", "nested_list" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lists play a very important role in Python and are for example used in loops and other flow control structures (discussed below). There are a number of convenient functions for generating lists of various types, for example, the `range` function (note that in Python 3 `range` creates a generator, so you have to use `list` function to get a list):" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[10, 12, 14, 16, 18, 20, 22, 24, 26, 28]" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "start = 10\n", "stop = 30\n", "step = 2\n", "\n", "list(range(start, stop, step))" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello world\n" ] }, { "data": { "text/plain": [ "['H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# convert a string to a list by type casting:\n", "\n", "print(s)\n", "\n", "s2 = list(s)\n", "\n", "s2" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[' ', 'H', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r', 'w']\n" ] } ], "source": [ "# sorting lists\n", "s2.sort()\n", "\n", "print(s2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Adding, inserting, modifying, and removing elements from lists" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['A', 'd', 'd']\n" ] } ], "source": [ "# create a new empty list\n", "l = []\n", "\n", "# add an elements using `append`\n", "l.append(\"A\")\n", "l.append(\"d\")\n", "l.append(\"d\")\n", "\n", "print(l)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can modify lists by assigning new values to elements in the list. In technical jargon, lists are *mutable*." ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['A', 'p', 't']\n" ] } ], "source": [ "l[1] = \"p\"\n", "l[2] = \"t\"\n", "\n", "print(l)" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['A', 's', 'm']\n" ] } ], "source": [ "l[1:3] = [\"s\", \"m\"]\n", "\n", "print(l)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Insert an element at an specific index using `insert`" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['i', 'n', 's', 'e', 'r', 't', 'A', 's', 'm']\n" ] } ], "source": [ "l.insert(0, \"i\")\n", "l.insert(1, \"n\")\n", "l.insert(2, \"s\")\n", "l.insert(3, \"e\")\n", "l.insert(4, \"r\")\n", "l.insert(5, \"t\")\n", "\n", "print(l)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Remove first element with specific value using 'remove'" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['i', 'n', 's', 'e', 'r', 't', 's', 'm']\n" ] } ], "source": [ "l.remove(\"A\")\n", "\n", "print(l)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Remove an element at a specific location using `del`:" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['i', 'n', 's', 'e', 'r', 't']\n" ] } ], "source": [ "del l[7]\n", "del l[6]\n", "\n", "print(l)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tuples\n", "\n", "Tuples are like lists, except that they cannot be modified once created, that is they are *immutable*. \n", "\n", "In Python, tuples are created using the syntax `(..., ..., ...)`, or even `..., ...`:" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "(10, 20)\n" ] } ], "source": [ "point = (10, 20)\n", "\n", "print(type(point))\n", "print(point)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we try to assign a new value to an element in a tuple we get an error:" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "TypeError: 'tuple' object does not support item assignment\n" ] } ], "source": [ "try:\n", " point[0] = 20\n", "except(TypeError) as er:\n", " print(\"TypeError:\", er)\n", "else:\n", " raise" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Dictionaries\n", "\n", "Dictionaries are also like lists, except that each element is a key-value pair. The syntax for dictionaries is `{key1 : value1, ...}`:" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "{'parameter1': 1.0, 'parameter2': 2.0, 'parameter3': 3.0}\n" ] } ], "source": [ "params = {\"parameter1\" : 1.0,\n", " \"parameter2\" : 2.0,\n", " \"parameter3\" : 3.0,}\n", "\n", "print(type(params))\n", "print(params)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dictionary entries can only be accessed by their key name." ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.0" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "params[\"parameter2\"]" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "parameter1 = 1.0\n", "parameter2 = 2.0\n", "parameter3 = 3.0\n" ] } ], "source": [ "print(\"parameter1 = \" + str(params[\"parameter1\"]))\n", "print(\"parameter2 = \" + str(params[\"parameter2\"]))\n", "print(\"parameter3 = \" + str(params[\"parameter3\"]))" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "parameter1 = A\n", "parameter2 = B\n", "parameter3 = 3.0\n", "parameter4 = D\n" ] } ], "source": [ "params[\"parameter1\"] = \"A\"\n", "params[\"parameter2\"] = \"B\"\n", "\n", "# add a new entry\n", "params[\"parameter4\"] = \"D\"\n", "\n", "print(\"parameter1 = \" + str(params[\"parameter1\"]))\n", "print(\"parameter2 = \" + str(params[\"parameter2\"]))\n", "print(\"parameter3 = \" + str(params[\"parameter3\"]))\n", "print(\"parameter4 = \" + str(params[\"parameter4\"]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Indentation\n", "\n", "Whitespace is important in Python. Actually, whitespace at the beginning of the line is important. This is called indentation. Leading whitespace (spaces and tabs) at the beginning of the logical line is used to determine the indentation level of the logical line, which in turn is used to determine the grouping of statements.\n", "\n", "This means that statements which go together must have the same indentation, for example:" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Value is 5\n", "I repeat, the value is 5\n" ] } ], "source": [ "i = 5\n", "\n", "print('Value is ', i)\n", "print('I repeat, the value is ', i)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Each such set of statements is called a block. We will see examples of how blocks are important later on.\n", "One thing you should remember is that wrong indentation rises `IndentationError`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Control Flow" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Conditional statements: if, elif, else\n", "\n", "The Python syntax for conditional execution of code use the keywords `if`, `elif` (else if), `else`:" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "statement1 and statement2 are False\n" ] } ], "source": [ "statement1 = False\n", "statement2 = False\n", "\n", "if statement1:\n", " print(\"statement1 is True\")\n", " \n", "elif statement2:\n", " print(\"statement2 is True\")\n", " \n", "else:\n", " print(\"statement1 and statement2 are False\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For the first time, here we encountered a peculiar and unusual aspect of the Python programming language: Program blocks are defined by their indentation level. In Python, the extent of a code block is defined by the indentation level (usually a tab or say four white spaces). This means that we have to be careful to indent our code correctly, or else we will get syntax errors. \n", "\n", "**Examples:**" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "both statement1 and statement2 are True\n" ] } ], "source": [ "# Good indentation\n", "statement1 = statement2 = True\n", "\n", "if statement1:\n", " if statement2:\n", " print(\"both statement1 and statement2 are True\")" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [], "source": [ "# Bad indentation! This would lead to error\n", "#if statement1:\n", "# if statement2:\n", "# print(\"both statement1 and statement2 are True\") # this line is not properly indented" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [], "source": [ "statement1 = False \n", "\n", "if statement1:\n", " print(\"printed if statement1 is True\")\n", " \n", " print(\"still inside the if block\")" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "now outside the if block\n" ] } ], "source": [ "if statement1:\n", " print(\"printed if statement1 is True\")\n", " \n", "print(\"now outside the if block\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loops\n", "\n", "In Python, loops can be programmed in a number of different ways. The most common is the `for` loop, which is used together with iterable objects, such as lists. The basic syntax is:\n", "\n", "\n", "## `for` loops" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "2\n", "3\n" ] } ], "source": [ "for x in [1,2,3]:\n", " print(x)," ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `for` loop iterates over the elements of the supplied list and executes the containing block once for each element. Any kind of list can be used in the `for` loop. For example:" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "1\n", "2\n", "3\n" ] } ], "source": [ "for x in range(4): # by default range start at 0\n", " print(x)," ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note: `range(4)` does not include 4 !" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-3\n", "-2\n", "-1\n", "0\n", "1\n", "2\n" ] } ], "source": [ "for x in range(-3,3):\n", " print(x)," ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "scientific\n", "computing\n", "with\n", "python\n" ] } ], "source": [ "for word in [\"scientific\", \"computing\", \"with\", \"python\"]:\n", " print(word)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To iterate over key-value pairs of a dictionary:" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "parameter1 = A\n", "parameter2 = B\n", "parameter3 = 3.0\n", "parameter4 = D\n" ] } ], "source": [ "for key, value in params.items():\n", " print(key + \" = \" + str(value))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes it is useful to have access to the indices of the values when iterating over a list. We can use the `enumerate` function for this:" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 -3\n", "1 -2\n", "2 -1\n", "3 0\n", "4 1\n", "5 2\n" ] } ], "source": [ "for idx, x in enumerate(range(-3,3)):\n", " print(idx, x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `break`, `continue` and `pass`\n", "\n", "To control the flow of a certain loop you can also use `break`, `continue` and `pass`." ] }, { "cell_type": "code", "execution_count": 86, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", "0\n", "1\n", "2\n", "3\n" ] } ], "source": [ "rangelist = list(range(10))\n", "print(list(rangelist))\n", "\n", "for number in rangelist:\n", " # Check if number is one of\n", " # the numbers in the tuple.\n", " if number in [4, 5, 7, 9]:\n", " # \"Break\" terminates a for without\n", " # executing the \"else\" clause.\n", " break\n", " else:\n", " # \"Continue\" starts the next iteration\n", " # of the loop. It's rather useless here,\n", " # as it's the last statement of the loop.\n", " print(number)\n", " continue\n", "else:\n", " # The \"else\" clause is optional and is\n", " # executed only if the loop didn't \"break\".\n", " pass # Do nothing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**List comprehensions: Creating lists using `for` loops**:\n", "\n", "A convenient and compact way to initialize lists:" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 4, 9, 16]\n" ] } ], "source": [ "l1 = [x**2 for x in range(0,5)]\n", "\n", "print(l1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**`while` loops**:" ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "1\n", "2\n", "3\n", "4\n", "done\n" ] } ], "source": [ "i = 0\n", "\n", "while i < 5:\n", " print(i)\n", " \n", " i = i + 1\n", " \n", "print(\"done\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the `print \"done\"` statement is not part of the `while` loop body because of the difference in the indentation." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Functions\n", "\n", "A function in Python is defined using the keyword `def`, followed by a function name, a signature within parentheses `()`, and a colon `:`. The following code, with one additional level of indentation, is the function body." ] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "hello world\n" ] } ], "source": [ "def say_hello():\n", " # block belonging to the function\n", " print('hello world')\n", "\n", "say_hello() # call the function" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Following an example where we also feed two arguments into the function." ] }, { "cell_type": "code", "execution_count": 90, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4 is maximum\n", "7 is equal to 7\n" ] } ], "source": [ "def print_max(a, b):\n", " if a > b:\n", " print( a, 'is maximum')\n", " elif a == b:\n", " print(a, 'is equal to', b)\n", " else:\n", " print(b, 'is maximum')\n", "\n", "# directly pass literal values\n", "print_max(3, 4)\n", "\n", "x = 7\n", "y = 7\n", "\n", "# pass variables as arguments\n", "print_max(x, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Very important**: Variables inside a function are treated as local variables and therefore don't interfere with variables outside the scope of the function." ] }, { "cell_type": "code", "execution_count": 91, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x is 50\n", "Changed local x to 2\n", "x is still 50\n" ] } ], "source": [ "x = 50\n", "\n", "def func(x):\n", " print('x is', x)\n", " x = 2\n", " print('Changed local x to', x)\n", "\n", "func(x)\n", "print('x is still', x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The local scope of a variable inside a function can be extended with the keyword `global`." ] }, { "cell_type": "code", "execution_count": 92, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x is 50\n", "Changed global x to 2\n", "Value of x is 2\n" ] } ], "source": [ "x = 50\n", "\n", "def func():\n", " global x\n", "\n", " print('x is', x)\n", " x = 2\n", " print('Changed global x to', x)\n", "\n", "func()\n", "print('Value of x is', x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Optionally, but highly recommended, we can define a so called \"docstring\", which is a description of the functions purpose and behavior. The docstring should follow directly after the function definition, before the code in the function body." ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [], "source": [ "def func1(s):\n", " \"\"\"\n", " Print a string 's' and tell how many characters it has \n", " \"\"\"\n", " \n", " print(s + \" has \" + str(len(s)) + \" characters\")" ] }, { "cell_type": "code", "execution_count": 94, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on function func1 in module __main__:\n", "\n", "func1(s)\n", " Print a string 's' and tell how many characters it has\n", "\n" ] } ], "source": [ "help(func1)" ] }, { "cell_type": "code", "execution_count": 95, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "test has 4 characters\n" ] } ], "source": [ "func1(\"test\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Functions that return a value use the `return` keyword:" ] }, { "cell_type": "code", "execution_count": 96, "metadata": {}, "outputs": [], "source": [ "def square(x):\n", " \"\"\"\n", " Return the square of x.\n", " \"\"\"\n", " return x ** 2" ] }, { "cell_type": "code", "execution_count": 97, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "16" ] }, "execution_count": 97, "metadata": {}, "output_type": "execute_result" } ], "source": [ "square(4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can return multiple values from a function using tuples (see above):" ] }, { "cell_type": "code", "execution_count": 98, "metadata": {}, "outputs": [], "source": [ "def powers(x):\n", " \"\"\"\n", " Return a few powers of x.\n", " \"\"\"\n", " return x ** 2, x ** 3, x ** 4" ] }, { "cell_type": "code", "execution_count": 99, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(9, 27, 81)" ] }, "execution_count": 99, "metadata": {}, "output_type": "execute_result" } ], "source": [ "powers(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And if we know that a function returns multiple outputs, we can store them directly in multiple variables." ] }, { "cell_type": "code", "execution_count": 100, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "27\n" ] } ], "source": [ "x2, x3, x4 = powers(3)\n", "\n", "print(x3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Default argument and keyword arguments\n", "\n", "In a definition of a function, we can give default values to the arguments the function takes:" ] }, { "cell_type": "code", "execution_count": 101, "metadata": {}, "outputs": [], "source": [ "def myfunc(x, p=2, debug=False):\n", " if debug:\n", " print(\"evaluating myfunc for x = \" + str(x) + \" using exponent p = \" + str(p))\n", " return x**p" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we don't provide a value of the `debug` argument when calling the the function `myfunc` it defaults to the value provided in the function definition:" ] }, { "cell_type": "code", "execution_count": 102, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "25" ] }, "execution_count": 102, "metadata": {}, "output_type": "execute_result" } ], "source": [ "myfunc(5)" ] }, { "cell_type": "code", "execution_count": 103, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "evaluating myfunc for x = 5 using exponent p = 2\n" ] }, { "data": { "text/plain": [ "25" ] }, "execution_count": 103, "metadata": {}, "output_type": "execute_result" } ], "source": [ "myfunc(5, debug=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we explicitly list the name of the arguments in the function calls, they do not need to come in the same order as in the function definition. This is called *keyword* arguments and is often very useful in functions that take a lot of optional arguments." ] }, { "cell_type": "code", "execution_count": 104, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "evaluating myfunc for x = 7 using exponent p = 3\n" ] }, { "data": { "text/plain": [ "343" ] }, "execution_count": 104, "metadata": {}, "output_type": "execute_result" } ], "source": [ "myfunc(p=3, debug=True, x=7)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `*args` and `*kwargs` parameters\n", "\n", "Sometimes you might want to define a function that can take any number of parameters, i.e. variable number of arguments, this can be achieved by using one (`*args`) or two (`**kwargs`) asterisks in the function declaration. `*args` is used to pass a non-keyworded, variable-length argument list and the `**kwargs` is used to pass a keyworded, variable-length argument list. " ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Formal arg: 1\n", "additioanl arg: two\n", "additioanl arg: 3\n", "additioanl arg: [1, 2, 3]\n" ] } ], "source": [ "def args_func(arg1, *args):\n", " print(\"Formal arg:\", arg1)\n", " for a in args:\n", " print(\"additioanl arg:\", a)\n", "\n", "args_func(1, \"two\", 3, [1, 2, 3])" ] }, { "cell_type": "code", "execution_count": 106, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "kwargs is now a dictionary...\n", "Type: \n", "Content: {'myarg2': 'two', 'myarg3': 3}\n", "\n", "Formal arg: 1\n", "another keyword arg: myarg2: two\n", "another keyword arg: myarg3: 3\n" ] } ], "source": [ "def kwargs_func(arg1, **kwargs):\n", " print(\"kwargs is now a dictionary...\\nType: %s\\nContent: %s\\n\" % (type(kwargs), kwargs))\n", "\n", " print(\"Formal arg:\", arg1)\n", " for key in kwargs:\n", " print(\"another keyword arg: %s: %s\" % (key, kwargs[key]))\n", " \n", "kwargs_func(arg1=1, myarg2=\"two\", myarg3=3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Unnamed functions: lambda function\n", "\n", "In Python we can also create unnamed functions, using the `lambda` keyword:" ] }, { "cell_type": "code", "execution_count": 107, "metadata": {}, "outputs": [], "source": [ "f1 = lambda x: x**2\n", " \n", "# is equivalent to \n", "\n", "def f2(x):\n", " return x**2" ] }, { "cell_type": "code", "execution_count": 108, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(4, 4)" ] }, "execution_count": 108, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1(2), f2(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This technique is useful for example when we want to pass a simple function as an argument to another function, like this:" ] }, { "cell_type": "code", "execution_count": 109, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[9, 4, 1, 0, 1, 4, 9]" ] }, "execution_count": 109, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# map is a built-in python function\n", "list(map(lambda x: x**2, range(-3,4)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Classes\n", "\n", "Classes are the key features of object-oriented programming. A class is a structure for representing an object and the operations that can be performed on the object. \n", "\n", "In Python, a class can contain *attributes* (variables) and *methods* (functions).\n", "\n", "A class is defined almost like a function, but using the `class` keyword, and the class definition usually contains a number of class method definitions (a function in a class).\n", "\n", "* Each class method should have an argument `self` as it first argument. This object is a self-reference.\n", "\n", "* Some class method names have special meaning, for example:\n", "\n", " * `__init__`: The name of the method that is invoked when the object is first created.\n", " * `__str__` : A method that is invoked when a simple string representation of the class is needed, as for example when printed.\n", " * There are many more, see http://docs.python.org/3.6/reference/datamodel.html#special-method-names" ] }, { "cell_type": "code", "execution_count": 110, "metadata": {}, "outputs": [], "source": [ "class Point:\n", " \"\"\"\n", " Simple class for representing a point in a Cartesian coordinate system.\n", " \"\"\"\n", " \n", " def __init__(self, x, y):\n", " \"\"\"\n", " Create a new Point at x, y.\n", " \"\"\"\n", " self.x = x\n", " self.y = y\n", " \n", " def translate(self, dx, dy):\n", " \"\"\"\n", " Translate the point by dx and dy in the x and y direction.\n", " \"\"\"\n", " self.x += dx\n", " self.y += dy\n", " \n", " def __str__(self):\n", " return(\"Point at [%f, %f]\" % (self.x, self.y))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To create a new instance of a class:" ] }, { "cell_type": "code", "execution_count": 111, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Point at [0.000000, 0.000000]\n" ] } ], "source": [ "p1 = Point(0, 0) # this will invoke the __init__ method in the Point class\n", "\n", "print(p1) # this will invoke the __str__ method" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To invoke a class method in the class instance `p`:" ] }, { "cell_type": "code", "execution_count": 112, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Point at [1.000000, 1.000000]\n", "Point at [1.250000, 2.500000]\n" ] } ], "source": [ "p2 = Point(1, 1)\n", "print(p2)\n", "\n", "p2.translate(0.25, 1.5)\n", "print(p2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can access any value of a class object directly, for example:" ] }, { "cell_type": "code", "execution_count": 113, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "Point at [10.000000, 0.000000]\n" ] } ], "source": [ "print(p1.x)\n", "\n", "p1.x = 10\n", "\n", "print(p1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Modules\n", "\n", "One of the most important concepts in good programming is to reuse code and avoid repetitions.\n", "\n", "The idea is to write functions and classes with a well-defined purpose and scope, and reuse these instead of repeating similar code in different part of a program (modular programming). The result is usually that readability and maintainability of a program are greatly improved. What this means in practice is that our programs have fewer bugs, are easier to extend and debug/troubleshoot. \n", "\n", "Python supports modular programming at different levels. Functions and classes are examples of tools for low-level modular programming. Python modules are a higher-level modular programming construct, where we can collect related variables, functions, and classes in a module. A python module is defined in a python file (with file-ending `.py`), and it can be made accessible to other Python modules and programs using the `import` statement. \n", "\n", "Consider the following example: the file `mymodule.py` contains simple example implementations of a variable, function and a class:" ] }, { "cell_type": "code", "execution_count": 114, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing mymodule.py\n" ] } ], "source": [ "%%file mymodule.py\n", "\"\"\"\n", "Example of a python module. Contains a variable called my_variable,\n", "a function called my_function, and a class called MyClass.\n", "\"\"\"\n", "\n", "my_variable = 0\n", "\n", "def my_function():\n", " \"\"\"\n", " Example function\n", " \"\"\"\n", " return my_variable\n", " \n", "class MyClass:\n", " \"\"\"\n", " Example class.\n", " \"\"\"\n", "\n", " def __init__(self):\n", " self.variable = my_variable\n", " \n", " def set_variable(self, new_value):\n", " \"\"\"\n", " Set self.variable to a new value\n", " \"\"\"\n", " self.variable = new_value\n", " \n", " def get_variable(self):\n", " return self.variable" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note:** `%%file` is called a cell-magic function and creates a file that has the following lines as content.\n", "\n", "We can import the module `mymodule` into our Python program using `import`:" ] }, { "cell_type": "code", "execution_count": 115, "metadata": {}, "outputs": [], "source": [ "import mymodule" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Use `help(module)` to get a summary of what the module provides:" ] }, { "cell_type": "code", "execution_count": 116, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on module mymodule:\n", "\n", "NAME\n", " mymodule\n", "\n", "DESCRIPTION\n", " Example of a python module. Contains a variable called my_variable,\n", " a function called my_function, and a class called MyClass.\n", "\n", "CLASSES\n", " builtins.object\n", " MyClass\n", " \n", " class MyClass(builtins.object)\n", " | Example class.\n", " | \n", " | Methods defined here:\n", " | \n", " | __init__(self)\n", " | Initialize self. See help(type(self)) for accurate signature.\n", " | \n", " | get_variable(self)\n", " | \n", " | set_variable(self, new_value)\n", " | Set self.variable to a new value\n", " | \n", " | ----------------------------------------------------------------------\n", " | Data descriptors defined here:\n", " | \n", " | __dict__\n", " | dictionary for instance variables (if defined)\n", " | \n", " | __weakref__\n", " | list of weak references to the object (if defined)\n", "\n", "FUNCTIONS\n", " my_function()\n", " Example function\n", "\n", "DATA\n", " my_variable = 0\n", "\n", "FILE\n", " /home/neuro/workshop/notebooks/mymodule.py\n", "\n", "\n" ] } ], "source": [ "help(mymodule)" ] }, { "cell_type": "code", "execution_count": 117, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 117, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mymodule.my_variable" ] }, { "cell_type": "code", "execution_count": 118, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 118, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mymodule.my_function() " ] }, { "cell_type": "code", "execution_count": 119, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 119, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_class = mymodule.MyClass() \n", "my_class.set_variable(10)\n", "my_class.get_variable()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we make changes to the code in `mymodule.py`, we need to reload it using `reload`:" ] }, { "cell_type": "code", "execution_count": 120, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 120, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from importlib import reload\n", "reload(mymodule)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exceptions\n", "\n", "In Python errors are managed with a special language construct called \"Exceptions\". When errors occur exceptions can be raised, which interrupts the normal program flow and fallback to somewhere else in the code where the closest try-except statement is defined.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To generate an exception we can use the `raise` statement, which takes an argument that must be an instance of the class `BaseExpection` or a class derived from it. " ] }, { "cell_type": "code", "execution_count": 121, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Exception: description of the error\n" ] } ], "source": [ "try:\n", " raise Exception(\"description of the error\")\n", "except(Exception) as err:\n", " print (\"Exception:\", err)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A typical use of exceptions is to abort functions when some error condition occurs, for example:\n", "\n", " def my_function(arguments):\n", " \n", " if not verify(arguments):\n", " raise Exception(\"Invalid arguments\")\n", " \n", " # rest of the code goes here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To gracefully catch errors that are generated by functions and class methods, or by the Python interpreter itself, use the `try` and `except` statements:\n", "\n", " try:\n", " # normal code goes here\n", " except:\n", " # code for error handling goes here\n", " # this code is not executed unless the code\n", " # above generated an error\n", "\n", "For example:" ] }, { "cell_type": "code", "execution_count": 122, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "test\n", "Caught an exception\n" ] } ], "source": [ "try:\n", " print(\"test\")\n", " # generate an error: the variable test is not defined\n", " print(test)\n", "except:\n", " print(\"Caught an exception\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To get information about the error, we can access the `Exception` class instance that describes the exception by using for example:\n", "\n", " except Exception as e:" ] }, { "cell_type": "code", "execution_count": 123, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "test\n", "Caught an exception:name 'test' is not defined\n", "This block is executed after the try- and except-block.\n" ] } ], "source": [ "try:\n", " print(\"test\")\n", " # generate an error: the variable test is not defined\n", " print(test)\n", "except Exception as e:\n", " print(\"Caught an exception:\" + str(e))\n", "finally:\n", " print(\"This block is executed after the try- and except-block.\")" ] }, { "cell_type": "code", "execution_count": 124, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Oops, invalid.\n", "We're done with that.\n" ] } ], "source": [ "def some_function():\n", " try:\n", " # Division by zero raises an exception\n", " 10 / 0\n", " except ZeroDivisionError:\n", " print(\"Oops, invalid.\")\n", " else:\n", " # Exception didn't occur, we're good.\n", " pass\n", " finally:\n", " # This is executed after the code block is run\n", " # and all exceptions have been handled, even\n", " # if a new exception is raised while handling.\n", " print(\"We're done with that.\")\n", "\n", "some_function()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You will see more exception handling examples in this and other notebooks. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## File I/O\n", "\n", "This section should give you a basic knowledge about how to read and write CSV or TXT files. First, let us create a CSV and TXT file about demographic information of 10 subjects (experiment_id, subject_id, gender, age)." ] }, { "cell_type": "code", "execution_count": 125, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing demographics.csv\n" ] } ], "source": [ "%%file demographics.csv\n", "ds102,sub001,F,21.94\n", "ds102,sub002,M,22.79\n", "ds102,sub003,M,19.65\n", "ds102,sub004,M,25.98\n", "ds102,sub005,M,23.24\n", "ds102,sub006,M,23.27\n", "ds102,sub007,D,34.72\n", "ds102,sub008,D,22.22\n", "ds102,sub009,M,22.7\n", "ds102,sub010,D,25.24" ] }, { "cell_type": "code", "execution_count": 126, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing demographics.txt\n" ] } ], "source": [ "%%file demographics.txt\n", "ds102\tsub001\tF\t21.94\n", "ds102\tsub002\tM\t22.79\n", "ds102\tsub003\tM\t19.65\n", "ds102\tsub004\tM\t25.98\n", "ds102\tsub005\tM\t23.24\n", "ds102\tsub006\tM\t23.27\n", "ds102\tsub007\tD\t34.72\n", "ds102\tsub008\tD\t22.22\n", "ds102\tsub009\tM\t22.7\n", "ds102\tsub010\tD\t25.24" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Reading CSV files\n", "\n", "Parsing comma-separated-values (CSV) files is a common task. There are many tools available in Python to deal with this. Let's start by using the built-in `csv` module." ] }, { "cell_type": "code", "execution_count": 127, "metadata": {}, "outputs": [], "source": [ "import csv" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Before you can read or write any kind of file, you first have to open the file and go through its content with a reader function or write the output line by line with a write function." ] }, { "cell_type": "code", "execution_count": 128, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['ds102', 'sub001', 'F', '21.94']\n", "['ds102', 'sub002', 'M', '22.79']\n", "['ds102', 'sub003', 'M', '19.65']\n", "['ds102', 'sub004', 'M', '25.98']\n", "['ds102', 'sub005', 'M', '23.24']\n", "['ds102', 'sub006', 'M', '23.27']\n", "['ds102', 'sub007', 'D', '34.72']\n", "['ds102', 'sub008', 'D', '22.22']\n", "['ds102', 'sub009', 'M', '22.7']\n", "['ds102', 'sub010', 'D', '25.24']\n" ] } ], "source": [ "f = open('demographics.csv','r') # open the file with reading rights = 'r'\n", "data = [i for i in csv.reader(f) ] # go through file and read each line\n", "f.close() # close the file again\n", "\n", "for line in data:\n", " print(line)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Writing CSV files\n", "\n", "Now, we want to write the same data without the first experiment_id column in CSV format to a csv-file. First, let's delete the first column in the dataset." ] }, { "cell_type": "code", "execution_count": 129, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['sub001', 'F', '21.94']\n", "['sub002', 'M', '22.79']\n", "['sub003', 'M', '19.65']\n", "['sub004', 'M', '25.98']\n", "['sub005', 'M', '23.24']\n", "['sub006', 'M', '23.27']\n", "['sub007', 'D', '34.72']\n", "['sub008', 'D', '22.22']\n", "['sub009', 'M', '22.7']\n", "['sub010', 'D', '25.24']\n" ] } ], "source": [ "data_new = [line[1:] for line in data]\n", "\n", "for line in data_new:\n", " print(line)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, we first have to open a file again, but this time with writing permissions = `'w'`. After it, we can go through the file and write each line to the new csv-file." ] }, { "cell_type": "code", "execution_count": 130, "metadata": {}, "outputs": [], "source": [ "f = open('demographics_new.csv','w') # open a file with writing rights = 'w'\n", "fw = csv.writer(f) # create csv writer\n", "fw.writerows(data_new) # write content to file\n", "f.close() # close file " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lets now check the content of `demographics_new.csv`." ] }, { "cell_type": "code", "execution_count": 131, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n" ] } ], "source": [ "!cat demographics_new.csv" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Reading TXT files\n", "\n", "The reading of txt files is quite similar to the reading of csv-files. The only difference is in the name of the reading function and the formatting that has to be applied to the input or output." ] }, { "cell_type": "code", "execution_count": 132, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['ds102', 'sub001', 'F', '21.94']\n", "['ds102', 'sub002', 'M', '22.79']\n", "['ds102', 'sub003', 'M', '19.65']\n", "['ds102', 'sub004', 'M', '25.98']\n", "['ds102', 'sub005', 'M', '23.24']\n", "['ds102', 'sub006', 'M', '23.27']\n", "['ds102', 'sub007', 'D', '34.72']\n", "['ds102', 'sub008', 'D', '22.22']\n", "['ds102', 'sub009', 'M', '22.7']\n", "['ds102', 'sub010', 'D', '25.24']\n" ] } ], "source": [ "f = open('demographics.txt','r') # open file with reading rights = 'r'\n", "\n", "# go through file and trim the new line '\\n' at the end\n", "datatxt = [i.splitlines() for i in f.readlines()]\n", "\n", "# go through data and split elements in line by tabulators '\\t'\n", "datatxt = [i[0].split('\\t') for i in datatxt]\n", "\n", "f.close() # close file again\n", "\n", "for line in datatxt:\n", " print(line)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Writing TXT files\n", "\n", "The writing of txt files is as follows:" ] }, { "cell_type": "code", "execution_count": 133, "metadata": {}, "outputs": [], "source": [ "f = open('demograhics_new.txt', 'w') # open file with writing rights = 'w'\n", "\n", "datatxt_new = [line[1:] for line in datatxt] # delete first column of array\n", "\n", "# Go through datatxt array and write each line with specific format to file\n", "for line in datatxt_new:\n", " f.write(\"%s\\t%s\\t%s\\n\"%(line[0],line[1],line[2]))\n", "\n", "f.close() # close file" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `with open`\n", "\n", "The previous methods to open or write a file always required that you also close the file again with the `close()` function. If you don't want to worry about this, you can also use the `with open` approach. For example:" ] }, { "cell_type": "code", "execution_count": 134, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['ds102', 'sub001', 'F', '21.94']\n", "['ds102', 'sub002', 'M', '22.79']\n", "['ds102', 'sub003', 'M', '19.65']\n", "['ds102', 'sub004', 'M', '25.98']\n", "['ds102', 'sub005', 'M', '23.24']\n", "['ds102', 'sub006', 'M', '23.27']\n", "['ds102', 'sub007', 'D', '34.72']\n", "['ds102', 'sub008', 'D', '22.22']\n", "['ds102', 'sub009', 'M', '22.7']\n", "['ds102', 'sub010', 'D', '25.24']\n" ] } ], "source": [ "with open('demographics.txt','r') as f:\n", "\n", " datatxt = [i.splitlines() for i in f.readlines()]\n", " datatxt = [i[0].split('\\t') for i in datatxt]\n", "\n", "for line in datatxt:\n", " print(line)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## File modes\n", "\n", "* Read-only: `r`\n", "* Write-only: `w` (Create a new file or overwrite existing file)\n", "* Append a file: `a`\n", "* Read and Write: `r+`\n", "* Binary mode: `b` (Use for binary files, especially on Windows)" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.8" } }, "nbformat": 4, "nbformat_minor": 2 }