{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Python basics\n", "\n", "## Variables\n", "In python, as in many programming language, objects are stored in variables.\n", "* A value is assigned to a variable using the `=` sign. \n", "* **Warning:** unlike in mathematics, the `=` sign in python is directional: the variable name must always be on the left of the `=`, and the value to assign to the variable on the right. \n", " Example:\n", " ```python\n", " a = 23 # is a valid assignment.\n", " 8 = b # is NOT a valid assignment.\n", " ```\n", "\n", "In python, variables names must adhere to these restrictions:\n", "* Variable names must be composed solely of uppercase and lowercase letters (`A-Z`, `a-z`), \n", " digits (`0-9`), and the underscore character `_`.\n", "* the first character of a variable name cannot be a digit.\n", "* by convention, variable names starting with a single or double underscore `_`/`__` are reserved \n", " for \"special\" variables (class private attributes, \"magic\" variables).\n", "* Examples:\n", " * `var_1` is a valid variable name.\n", " * `1_var` is **not** a valid name (starts with a digit)\n", " * `var-1` is **not** a valid name (contains a the non-authorized character `-`)\n", " * `__var_1__` is valid, but **should not be used**, whith the exception of very specific situations.\n", "\n", "> **Pro tip**: using explicit variable names makes your code easier to read for others, and possibly \n", " yourself in a not-so-distant future. \n", " For instance `input_file` is better than `iptf`, even if it is a bit longer." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "myVariable = 35 # assign the value 35 to variable \"myVariable\".\n", "var_a = 2.3 # assign the value 2.3 to variable \"a\".\n", "var_b = var_a # assign to value of \"var_a\" to \"var_b\".\n", "\n", "# By the way, text located after a \"#\" character - just like this line - are comments. \n", "# Comments is text that will not be executed, but is useful for code documentation\n", "print(myVariable)\n", "print(var_a)\n", "print(var_b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Code indentation - the importance of white spaces in Python\n", "**Indentation** is the number of white spaces on a given line before the first text element.\n", "```\n", " |var_1 = 2\n", " | var_1 = 2\n", " ^\n", " The line above is indented by 1 space.\n", " | var_1 = 2\n", " ^^\n", " The line above is indented by 2 space.\n", "```\n", "\n", "* Indentation has a very important meaning in python, as it it used to define \"code blocks\" \n", " (more on that later in the course). \n", "* When outside of a \"code block\", there should be no indentation on the line.\n", "* A arong level of indentation will trigger an `IndentationError`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "var_1 = 'abc' # No indentation -> valid syntax.\n", " var_1 = 'abc' # unexpected indentation (i.e. outside of a code block) -> IndentationError\n", " \n", " # Comment lines, however, can be indented as you wish." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When assigning a variable, white spaces after the variable name not matter. However the [Python style convention](https://www.python.org/dev/peps/pep-0008/#whitespace-in-expressions-and-statements) is to have **exactly 1 space** on each side of the `=` operator.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "var_1 = 'abc' # Valid syntax and good style.\n", "var_1 = 'abc' # Valid syntax, bad style -> please avoid.\n", "print(var_1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Functions\n", "Another very important concept in Python - as in most programming language - are **functions**.\n", "* Functions are a **re-usable blocks of code** that have been given a name and are ready to perform an action.\n", " How to define your your own functions will be detailed later in this course.\n", "* Functions can be written to perform anything, from the simplest task to the most complex.\n", "* To call a function, one uses its name followed by parentheses `()`, which contain an eventual set of \n", " arguments\n", "* **Arguments** are the variables/values that the function uses as input to do its job. \n", " In Python, we differentiate between two types of arguments:\n", " * **positional** arguments:\n", " * are mandatory.\n", " * their position in the call to the function is important.\n", " * **keyword** arguments:\n", " * are optional and have a **default value**.\n", " * are passed to the function with the syntax `argument_name=value`.\n", " * can be passed passed in any order (as long as they are passed after positional arguments).\n", " * depending on the case, keyword arguments can also be passed without their name being specified.\n", " * positonal arguments must always be passed **before** keyword arguments.\n", " \n", "Example of the `print()` function\n", "\n", " print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"This\", \"will\", \"be\", \"printed\")\n", "print(\"This\", \"will\", \"be\", \"printed\", sep=\"--\")\n", "print(\"This\", \"will\", \"be\", \"printed\", \"--\")\n", "#print(sep=\"--\", \"This\", \"will\", \"be\", \"printed\") # -> raises a SyntaxError" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The help function - your best friend in Python\n", "In python, almost any object or function is extensively documented: what it is, what it does, how to use it, ... \n", "This information is accessed using the `help()` function, which takes as argument the object we want to get help with." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Let's try to look up the help page of the print function that we encountered moments ago.\n", "help(print)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It tells us that:\n", " * `print` is a function.\n", " * It \"Prints the values to a stream, or to sys.stdout by default.\". So the function prints the \n", " values that are passed to it to the console (or possibly to a file).\n", " * Its arguments are the things that will be printed.\n", " * It has 4 optional arguments that refines its use (e.g. `sep` and `end`).\n", "\n", "Let's try to apply our new knowledge of the `print` function :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print('test') # simple usage.\n", "print('test' , 42) # we can make it print several values. by default, they are separated by spaces.\n", "print('test' , 42 , sep='/') # the \"sep\" argument can be used to change the separator between values.\n", "print('first line')\n", "print('second line')\n", "print('first line', end='') # the 'end' argument can be used to modify the character printed at the end of\n", "print('second line') # each line. It defaults to \\n (new line character)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Don't hesitate to use the `help` function on any object or function to understand how they work.**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Reading and understanding errors\n", "\n", "Unless you are a perfect human being, your code will contain errors at some point. \n", "Errors ~~can sometimes be~~ are frustrating, but they are unavoidable, and the best way to correct them is to actually read and try to understand them.\n", "\n", "Here is an error example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "var_a = 42\n", "var_b = var_a + 3\n", "print(var_c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The python error message gives us a number of useful info:\n", "* The first line indicates the **type** of ther error. In our example we got a `NameError`, \n", " meaning that a name (of an object) has not been found. \n", " If you want to know more about a certain error type, you can use the help function on it: `help(NameError)`.\n", "\n", "* The following lines point out the line where the error occured, which is very useful when there are \n", " hundreds of lines. Here the error occured on line `3` (pointed-to by the arrow), the line of the \n", " `print` statement.\n", "\n", "* Finally, we have `NameError: name 'var_c' is not defined`, which points out that we tried to print \n", " the variable `var_c` when that variable does not exists (i.e., that name is not defined).\n", "\n", "> Arguably, being able to **read and understand errors** and being able to **read the help** accounts for ~50% of \"coding skills\"....\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Micro Exercise:\n", "* look at the error given by the following code. Try to understand it and modify the code accordingly." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "42 + \"a\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Object types: simple types\n", "Everything in python is an objct, and Python divides objects into several categories called **types**. \n", "There exist plenty of type (is it even common to define your own new type), but there a few very common ones - known as **built-in** types - that you ought to know.\n", "* `bool`: boolean/logical values, either `True` or `False`, like 0 or 1.\n", "* `int` : integer number.\n", "* `float`: floating point number (numbers with a decimal fraction).\n", "\n", "To know the type of an object, we can make use of the `type()` function. \n", "\n", "A few comments about types in python:\n", "* Python is (by default\\*\\*) a **dynamically typed** language (as opposed to **statically typed** \n", " languages such as C or C++ e.g.). This means that variables are declared without a specific type, \n", " and the type is assigned based on what object is assigned to the variable. \n", " This has its advantages (easier and faster to write code) and downsides (e.g. type error bugs can \n", " remain hidden for a long time until they are triggered by some unusual input data).\n", " \n", "* A corollary is that variables in Python are not restricted to a single type and can be reassigned \n", " another type of value at any time.\n", " \n", " \\*\\* Starting with python 3.6, it is possible (as an option) to define static types for variables." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# In this example we successively assign different values and types to the variable \"a\".\n", "# boolean\n", "a = True\n", "print(\"type of a is:\", type(a))\n", "\n", "# float\n", "a = 4.2\n", "print(\"type of a is:\", type(a))\n", "\n", "# integer\n", "a = 42\n", "print(\"type of a is:\", type(a))\n", "print(\"type of 42 is:\", type(42))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Type conversion** is (often) fairly easy : juste use the type name as a function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Convert a integer to a float:\n", "a = 42\n", "print(\"type of a before conversion:\", type(a))\n", "a = float(a)\n", "print(\"type of a after conversion:\", type(a))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Mirco Exercise:\n", "* Convert `a` back to an integer (`int`). Look up the `help` for integers." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Operators\n", "Now that we have variables containing objects of a certain **type**, we can begin to play with them using operators.\n", "\n", "### Arithmetic operators \n", "You know most of these already:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print( 3 + 7 ) # + : addition\n", "print( 1.1 - 5 ) # - : substraction\n", "print( 5 / 2 ) # / : division\n", "print( 5 // 2 ) # //: integer division (fractional part is discarded: 2.5 -> 2)\n", "print( 5 * 2 ) # * : multiplication\n", "print( 2 ** 4 ) # **: power\n", "print( 5 % 2 ) # % : modulus (remainder of the division)\n", "\n", "# Variables can be used there as well:\n", "x = 4\n", "y = 16 * x**2 - 2 * x + 0.5 \n", "print(y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now you can use Python as a fancy calculator!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Bonus:** when modifying the value of a variable, you can use the following shortcut operators: \n", "(e.g. useful to increment the value of a variable in a loop)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = 0\n", "print(\"The start value of 'a' is\", a)\n", "\n", "# Same as a = a + 3\n", "a += 3\n", "print(\"The value of 'a' is now:\", a)\n", "\n", "# Same as a = a - 1\n", "a -= 1 \n", "print(\"The value of 'a' is now:\", a)\n", "\n", "# Same as a = a * 3\n", "a *= 3\n", "print(\"The value of 'a' is now:\", a)\n", "\n", "# Same as a = a / 2\n", "a /= 2\n", "print(\"The value of 'a' is now:\", a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "### Comparison operators\n", "\n", "These operators return a `bool` value (`True` or `False`)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = 5\n", "print(\"is a equal to 1?:\", a == 1) # == : equality\n", "print(\"is a different to 13.37?:\", a != 13.37) # != : inequality\n", "print(\"is a greater than 5?:\", a > 5 ) # > : larger than\n", "print(\"is a lower than 10?:\", a < 10 ) # < : lower than\n", "print(\"is a above 5?:\", a >= 5 ) # <= : lower or equal\n", "print(\"is a lower than 10?:\", a <= 10 ) # >= : larger or equal" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Warning:** comparisons are type-sensitive, so the following expression evaluates to **False**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = 5\n", "print(\"is a equal to '5'?:\", a == \"5\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Boolean values (the result from a comparison) can be:\n", "* combined using `and` or `or`.\n", "* inversed using `not` (True becomes False and False becomes True)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"'and' requires both elements to be True:\" , True and ( 1 + 1 != 2 ) )\n", "print(\"'or' requires at least element to be True:\" , ( a * 2 > 10 ) or ( a > 0 ) )\n", "print(\"'not' inverses a boolean value! This is simply\", not False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Micro Exercise:\n", "* Compute the product of 348 and 157.2.\n", "* Use a comparison operator to check if the result is larger than 230 square (`230**2`)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Object types: container types\n", "These types are object that contain other objects:\n", "* `str`: string - text\n", "* `list`: \"mutable\" list of python object\n", "* `tuple`: \"immutable\" list of python object\n", "* `dict`: dictionnary associating 'key' to 'value'\n", "\n", "They all have a dedicated `[]` operator that lets user access one - or several - of the object they contain. \n", "In addition, the number of objects a container has (its length) can be accessed using the `len()` function.\n", "\n", "**Important:** in python (unlike e.g. in R), **indexing is zero-based**. This means that the first element of a container type object is accessed with `object[0]`, and not `object[1]`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Strings\n", "* In python, the `string` type is a **sequences of characters** that can be used to represent text of any length.\n", "* Strings are represented surrounded by single `'` or double `\"` quotes. One can also use triple \n", " quotes `\"\"\"` to make a multi-line string." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Both single and double quotes can be used to define a string.\n", "gene_seq = \"ATGCGACTGATCGATCGATCGATCGATGATCGATCGATCGATGCTAGCTAC\"\n", "name = 'Sir Lancelot of Camelot'\n", "\n", "# Triple quotes can be used to define multi-line strings.\n", "long_string = \"\"\"Let me tell you something, my lad. \n", "When you’re walking home tonight and some great \n", "homicidal maniac comes after you with a bunch \n", "of loganberries, don’t come crying to me!\\n\"\"\"\n", "print(long_string)\n", "\n", "# Special characters are possible in strings.\n", "my_quote = \"\"\"Gracieux : « aimez-vous à ce point les oiseaux\n", "que paternellement vous vous préoccupâtes\n", "de tendre ce perchoir à leurs petites pattes ? »\"\"\"\n", "\n", "# We also commonly use special characters, such as:\n", "print('a\\tb') # \\t : tabulation\n", "print('a\\nb') # \\n : newline\n", "\n", "# We can use the len() function to know the length of a string:\n", "print(\"The length of the string in the 'name' variable is:\", len(name))\n", "\n", "# NB: strings can be added together and multiplied by an integer:\n", "print( 'dead' + 'parrot' ) \n", "print( 'spam' * 5 ) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Because strings are a type of sequence, the different letters of a string can be accessed using the **`[]` operator**, with the index of the desired element. \n", "Remember that in python, the index of the first element is `[0]`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "my_string = \"And now, something completely different.\"\n", "print(\"The first element of this string is:\", my_string[0] ) # 0 is the index of the 1st element of the string.\n", "print(\"The 5th element of this string is:\", my_string[4] ) # 5th element of the string.\n", "print(\"The last element of this string is:\", my_string[-1] ) # -1 is the index of the last element of the string." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Indices can also be used to retrieve several element at once: this is called a **slice operation** or **slicing**:\n", "* The general syntax of slicing is [start index: excluded end index: step]\n", "* The end index position is **excluded from the slice**.\n", "* The **default step value is 1**, and it is therefore very often omitted." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(my_string[0:5]) # slice operation: get all elements from index 0 (included) to index 5 (excluded)\n", "print(my_string[:5]) # implicitely slices from the beginning of the string up to (but not included) index 5.\n", "print(my_string[5:]) # implicitely slices until the end of the string.\n", "print(my_string[5::2]) # keep every second letter, starting from index 5 to the end of the string.\n", "print(my_string[::-1]) # goes through the string from end to start -> reverses the string !" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Micro exercise: \n", "* create a `str` variable containing your name.\n", "* Extract the last 3 letters from it using slicing." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "### Lists and tuples\n", "Lists and tuples are **sequence type** objects that can contain any type of elements (other objects). \n", "* Lists are declared by surrounding a comma separated list of objects with `[]`. \n", "* Tuples are declared similarly, but using `()`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Declaring a list.\n", "my_list = [1 , 2 , 3 , 5 , 5.2 , 6.99]\n", "print(\"my list is:\", my_list)\n", "\n", "# Declaring a tuple.\n", "my_tuple = ('a' , 4.2 , 5) # Lists/tuples can contain a mix of different types.\n", "print(\"my tuple is:\", my_tuple)\n", "\n", "# Creating a list from a tuple, or a tuple from a list.\n", "another_list = list((1, 2, 3))\n", "another_tuple = tuple([1, 2, 3])\n", "print(\"my other list is:\", another_list)\n", "print(\"my other tuple is:\", another_tuple)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The **`[]` operator** works in much the same way than with strings, and allows **accessing individual objects** from a list/tuple, or **slicing** it:\n", "* as with strings, remember that the end position index is **excluded** from the slicing." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(my_tuple[0]) # get the 1st item of the list.\n", "print(my_list[2:]) # get all elements from index 2 (i.e. the 3rd element) to the end of the list." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Mutability - an important difference between lists and tuples\n", "* A `tuple` is **immutable**: its length is fixed and its elements cannot be changed.\n", "* A `list` is **mutable**: it can be extended, reduced, and its elements can be changed. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Changing an element in a list\n", "my_list = [1 , 2 , 3 , 5 , 5.2 , 6.99]\n", "my_list[3] = \"Spam\"\n", "print(my_list[3])\n", "print(my_list)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# Trying the same with a tuple raises a TypeError:\n", "my_tuple = (1 , 2 , 3 , 5) \n", "my_tuple[3] = \"Spam\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What can be done however, is to assign a new tuple to the same variable - this will *look* line we have modified a tuple, but in fact we have created a new tuple object and assigned it to our variable." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "my_tuple = (1 , 2 , 3 , \"spam\") # We do not modify an existing tuple: we create a new one.\n", "print(my_tuple)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Remember the `help()` function ? Let's use it to gain a better undertsanding of the lists :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "help(list)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That's a lot of information... let's go through it! \n", "* First we learn that `list` is a class (i.e. a function that can generate objects of a certain type).\n", " It can thus create objects of type `list`.\n", "* The help page then tells us that lists are `Built-in mutable sequence.`, and describes the behaviour \n", " of `list()` if no argument is given (creates an empty list). \n", "* Then, it says `Methods defined here:`. **Methods** are functions that can be called on objects of the\n", " class they belong to. This often enable some basic manipulation of objects of that type. \n", " * Methods are called using the syntax `object.method(...)`\n", "\n", "Let's focus on two methods of the `list` class:\n", " * `append(self, object, /) `: this method adds an object - given as argument - at the end of the list.\n", " * `insert(self, index, object, /)`: this method inserts an object - given as the 2nd argument - before \n", " the index given as the 1st argument.\n", " \n", "Let's try out these methods:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "my_list = [1 , 2 , 3 , 5]\n", "print(\"Initially, my list is:\", my_list)\n", "\n", "# Calling the \"append()\" method of the my_list list to add an element at the end of it.\n", "my_list.append(\"ham\") \n", "print(\"The list, after appending ham is now:\", my_list)\n", "\n", "# Calling the method insert of my_list to add an element in second position. \n", "# Remember that python indices start with 0, so inserting before position 1 puts \n", "# the new object in second position in my_list (and not in the first).\n", "my_list.insert(1 , \"beans\") \n", "print(\"list after insert:\", my_list)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Methods are a very important part of python, and provide tons of functionalities to objects. Before you start writing your own code to manipulate an object, **always check** if the object already has a method that does exactly (or nearly) what you want. \n", "This will save you a lot of time and grief." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### From list to string, and back again ...\n", "Since string variable are iterables (i.e. sequences), they can be converted to lists using the `list()` function:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "my_string = \"Drop your panties Sir William, I cannot wait till lunchtime.\"\n", "list_from_string = list(my_string)\n", "print(list_from_string)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As can be seen above, the default behavior is that each letter of the string becomes an element in the list.\n", "\n", "However, often we prefer to create a list that contains each word of the string. For this we use the `split()` method of string:\n", "* The `split()` method is very useful when reading formatted text files.\n", "* By default, it splits on white space (i.e. spaces, tabs, newlines).\n", "* It accepts an optional `sep` argument that allows separation of fields using the specified character (look up `help(str.split)` for details)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "my_string = \"Drop your panties Sir William, I cannot wait till lunchtime.\"\n", "my_list = my_string.split()\n", "print(my_list)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To convert a list to a string, the `join()` method can be used (which may be seen as the inverse of `split()`).\n", "Somehow counter-intuitively, the `join()` method applies to strings, and takes a list as argument:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Here, the separator calls the join method which accepts the list \"my_words\" as argument.\n", "my_string = \" \".join(my_words) \n", "print(my_string)\n", "\n", "# One can use a more exotic separator - in fact, any string can be used as separator.\n", "my_string = \"_SEP_\".join(my_words) \n", "print(my_string)\n", "\n", "# TIP: use an empty separator to just join letters.\n", "my_string = \"\".join(['to','ba','c','co','ni','st']) \n", "print(my_string)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Bonus**: lists can be concatenated with the `+` operator, extended with `+=` (addition assignment) and \"multiplied\" with `*`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Crate a new list by appending two lists.\n", "list_one = [ ',' , 1159 ]\n", "list_two = list_one + [10.1, '45', 7] \n", "print(list_two)\n", "\n", "# Extend a list with the += operator.\n", "# This could also have been written with the += operator:\n", "# list_one += [10.1, '45', 7] \n", "\n", "# As well as multiplication\n", "menu = ['spam', 'eggs'] * 3 \n", "print(menu)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Micro Exercise:\n", "* create a list with all integers from 0 to 3 in it.\n", "* Add two numbers at the end of the list.\n", "* Use a slicing operation to select the fourth element in the list.\n", "\n", "* **If you have the time:**\n", " * What is the difference between `list.append()` and `list.extend()`? Try to figure-it out empirically\n", " by trying to append a list to another list.\n", " * Why does `print(my_list.append(\"something\"))` print \"None\"?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

\n", "\n", "### Dictionnaries\n", "Dictionnaries, or `dict`, are containers that associate a **key** to a **value**, just like a real world dictionnary associates a word to its definition.\n", "* Dictionaries are instantiated with the `{key:value}` or `dict()` syntax.\n", "* **keys** must be unique in the dictionnary.\n", "* **values** can appear as many time as desired in the dictionnary.\n", "* the `[]` operator is used to select objects from the dictionnary, but using their key instead of their index.\n", " ```python\n", " color_code = {'blue': 23, 'green': 45, 'red': 8}\n", " color_code['blue'] # returns 23\n", " color_code['red'] # returns 8\n", " ```\n", "* Unlike **Lists** or **Tuples**, **Dict** are unordered collections: they do not record element position \n", " or order of insertion. Therefore values cannot be retrieved by index position. \n", " E.g. `color_code[0]` is not a valid syntax (and will raise a `keyError`), unless there is a key value \n", " of \"0\" in the dict.\n", "* Dictionaries are **mutable** objects: key:value pairs can be added and removed, values can be modified. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create an empty dictionnary.\n", "student_age = dict()\n", "student_age = {}\n", "\n", "# Create a dictionnary and directly add values to it.\n", "student_age = {'Anne': 26 , \n", " 'Viktor': 31 }\n", "student_age = dict(Anne=26 , Viktor=31)\n", "\n", "# Adding key:value pairs to an existing dictionary is as easy as:\n", "student_age['Eleonore'] = 5\n", "print('dictionnary:', student_age)\n", "\n", "# Modifying the value associated to a key is equally easy:\n", "student_age['Eleonore'] = 25\n", "print('dictionnary:',student_age)\n", "\n", "# We are not restricted to a particular type for keys, nor for values. \n", "# We can e.g. make dict of lists or dict of dict.\n", "student_age[0] = 'zero' \n", "student_age['group_1'] = [23, 25, 28] \n", "student_age['group_2'] = {'bob':26, 'alice':27}\n", "print('dictionnary:', student_age)\n", "\n", "# Removing objects from the dictionnary is done with the pop() method, look at the help for more details.\n", "student_age.pop('Anne') \n", "print('dictionnary:',student_age)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

\n", "\n", "## Exercises: 1.1 - 1.4\n", "\n", "You can do the additionnal exercises if you have the time." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We recommend you have a look at the `Mutable_vs_immutable.ipynb` notebook to gain a better understanding of the difference between some the objects presented here.\n", "This is an important notation that newcomers to Python need to be aware of, which otherwise can lead to serious bugs in our codes." ] } ], "metadata": { "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.8.6" } }, "nbformat": 4, "nbformat_minor": 4 }