{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# An Introduction to Python\n", "\n", "[back to main page](index.ipynb)\n", "\n", "[Python](http://www.python.org/) is a general-purpose programming language.\n", "It is an *interpreted* language, i.e. source code is not compiled into an executable file but it is directly executed by an *interpreter*.\n", "A file containing Python code can be executed like this:\n", "\n", " python my_code.py\n", "\n", "Python can also act as an interactive interpreter where you can type and run Python code line-by-line.\n", "It can be started by simply running\n", "\n", " python\n", "\n", "You have the full power of Python in there, but it is not very convenient.\n", "A much better alternative is [Jupyter](https://jupyter.org/) (formerly known as [IPython](http://ipython.org/)), which is described on a [separate page](intro-jupyter.ipynb).\n", "\n", "Actually, this very page you're just reading is a so-called [Jupyter notebook](https://jupyter-notebook.readthedocs.org/) (formerly known as [IPython notebook](http://ipython.org/notebook.html)), which means that you can view it either as a [static web page](http://nbviewer.ipython.org/urls/raw.github.com/mgeier/python-audio/master/intro-python.ipynb) or, if you have IPython installed locally, you can also open the [notebook file](http://raw.github.com/mgeier/python-audio/master/intro-python.ipynb) with Jupyter/IPython and run the code in it interactively. You can also change stuff and play around with it.\n", "To execute a code cell, select it by clicking on it and press Shift+Enter (or click the button in the toolbar).\n", "You can step through all the cells by pressing Shift+Enter repeatedly.\n", "\n", "If you don't want to install Jupyter (yet), you can simply try it out online at https://try.jupyter.org/ (just click on \"New\" and \"Python 3\" or open the notebook \"Welcome to Python\").\n", "You can even launch an interactive online version of this very notebook by clicking on [![Binder](http://mybinder.org/badge.svg)](http://mybinder.org/repo/mgeier/python-audio/intro-python.ipynb)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Python 2 vs. 3\n", "\n", "Bottom line: \n", "\n", "* Always use Python 3!\n", "\n", " * The appropriate commands may be called `python3`, `ipython3`, `jupyter3`, `pip3` etc. on your computer.\n", "\n", "* Ignore old code examples that use `print` without parentheses.\n", "\n", "If you want to know more, read on.\n", "If not, just jump to the next section.\n", "\n", "In the beginning of the year 2006 (= a long time ago), the formal process to create the new 3.x generation of the Python language was started (see [PEP 3000](https://www.python.org/dev/peps/pep-3000/)).\n", "This was before the release of Python 2.5 (which came in September 2006).\n", "A new version of a programming language normally isn't a big deal for casual users of the language, but in this case several fundamental changes were made which led to backwards-incompatibility between Python 2.x and Python 3.x.\n", "This incompatibility is of course annoying, and to ease the pain the Python developers decided to continue supporting the 2.x series until 2015.\n", "This \"period of transition\" was then extended until 2020.\n", "\n", "Many new features from the 3.x branch (those which didn't conflict with the incompatible syntax changes) were back-ported to the old 2.x branch.\n", "Python 2.7 will be the last major release of the old generation, but there will be minor 2.7.x releases until 2020.\n", "\n", "| | 2006 | 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 |\n", "|---|------|------|------|------|------|-------|-------|-------|-------|--------|--------|--------|--------|-------|--------|\n", "| Python 2 | 2.5 | | 2.6 | | 2.7 | 2.7.2 | 2.7.3 | 2.7.6 | 2.7.9 | 2.7.11 | 2.7.13 | 2.7.14 | 2.7.15 | 2.7.? | R.I.P. |\n", "| Python 3 | 3.0 | | | 3.1 | | 3.2 | 3.3 | | 3.4 | 3.5 | 3.6 | | 3.7 | 3.? | 3.? |\n", "\n", "If you know Python 2, you should have a look at the [release notes of Python 3.0](https://docs.python.org/3/whatsnew/3.0.html) for an overview of the most important changes.\n", "\n", "If you are new to Python, you could theoretically ignore all this and just use the newest Python 3.x, but there may be (at least) two problems:\n", "\n", "* You may want to use libraries which are not yet ported to Python 3\n", "\n", "* You may find tutorials and other documentation which still uses Python 2\n", "\n", "The first problem doesn't really happen that much nowadays.\n", "Most libraries support Python 3.\n", "If you still find one you'll either have to search for an alternative, ask the original authors to port it to Python 3 or just try porting it yourself!\n", "\n", "The second problem is more likely to happen, because there is a huge amount of documentation available for Python 2.\n", "Luckily, there is also a lot of documentation available for Python 3, you just have to find out which is which.\n", "The easiest way to find out might be to look for `print` in the first few examples.\n", "In Python 2, `print` was a *statement*, which means there was no need for parentheses:\n", "\n", "```python\n", "print \"Hello, world!\"\n", "```\n", "\n", "In Python 3, `print` is a *function* and therefore needs parentheses:\n", "\n", "```python\n", "print(\"Hello, world!\")\n", "```\n", "\n", "That's it, now all you have to do is find a tutorial which uses parentheses (hint: just continue reading!)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Why \"Python\"?\n", "\n", "The programming language *Python* is named after the famous British comedy group *Monty Python*. If that doesn't ring a bell, you should search the interwebs and watch some videos of them, they are hilarious! In Python example code, you will often find references to their sketches, e.g. a list may contain `['eggs', 'bacon', 'spam']` which would be a reference to [Monty Python's Spam Sketch](http://www.youtube.com/watch?v=anwy2MPT5RE)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Hello, world!\n", "\n", "According to international law, every programming language tutorial has to start by showing how to print the sentence \"Hello, world!\" to the screen. This is how it's done in Python:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, world!\n" ] } ], "source": [ "print(\"Hello, world!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here you can see how a function is called (more precisely, a [built-in function named `print`](http://docs.python.org/3/library/functions.html#print)) with one argument. Furthermore, you see how string literals are created.\n", "It's pretty simple." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Getting Help\n", "\n", "The traditional way to get help from Python is the built-in `help()` function:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on built-in function print in module builtins:\n", "\n", "print(...)\n", " print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n", " \n", " Prints the values to a stream, or to sys.stdout by default.\n", " Optional keyword arguments:\n", " file: a file-like object (stream); defaults to the current sys.stdout.\n", " sep: string inserted between values, default a space.\n", " end: string appended after the last value, default a newline.\n", " flush: whether to forcibly flush the stream.\n", "\n" ] } ], "source": [ "help(print)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In Jupyter/IPython, there is even a simpler way: just append (or prepend) a question mark:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "print?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This will show the help text in the lower section of your browser window.\n", "To close the help display, type \"q\" (like *quit*).\n", "\n", "Of course, there is also a lot of help available in the interwebs, just use your favorite search engine to get started.\n", "I hope you're not afraid of snakes!\n", "\n", "But now to something completely different:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Numbers\n", "\n", "Everybody loves numbers, right? In Python, there are two types of numbers. On the one hand, there are *integers* like" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "42" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "42" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... and on the other hand, there are *floating point* numbers like" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.1415" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3.1415" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You probably know that \"everything in Python is an object\", which is also true for numbers. Numbers are objects. And every object has a type, so let's check that:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "int" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(42)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Looks close enough to \"integer\", doesn't it?" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "float" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(3.1415)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... and this is supposed to mean \"floating point number\"." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want to convert an `int` to a `float`, you can do it like this:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "42.0" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "float(42)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "TODO: infinite precision `int`, double precision `float`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "TODO: more numeric types in external libraries, e.g. NumPy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To be completely honest, there is a third type of numbers built into the core of the Python language: *complex* numbers." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(2.4+3.1j)" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2.4 + 3.1j" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Appending a lower-case `j` to a number (without a space in-between), makes it an *imaginary* number.\n", "Let's look at the type of the whole thing:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "complex" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(2.4 + 3.1j)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A `complex` is basically a pair of `float`s, one for the *real part* and one for the *imaginary part*. Complex numbers can come in very handy when doing scientific computations.\n", "\n", "You can find more information about Python's numeric types in [the official documentation](http://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex).\n", "You should also have a look at the official [Floating Point Arithmetic Tutorial](https://docs.python.org/3/tutorial/floatingpoint.html)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Operators\n", "\n", "Numbers are great. Let's see how they interact with each other." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2 + 3" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5.0" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2.0 + 3.0" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "7.5" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "5 + 2.5" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2 * 3" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-16.5" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "-4 * (3 + 1) - 0.5" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.5" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "5 / 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So far, not really surprising results. You can mix `int`s and `float`s. As soon as a `float` is involved, the result is also a `float`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Attention**: integer division behaves differently in Python 2 and Python 3!\n", "In Python 2, it behaved like in the programming language *C*, i.e. the result was truncated to an integer, e.g. `5 / 2` would return `2` and the result would be of type `int`.\n", "In Python 3, however, the behavior was changed and now even the division of two `int`s returns a `float`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want the old truncating behavior of Python 2, you can use the `//` operator:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "5 // 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On the other hand, if you want the new behaviour in Python 2, just write this line before your calculations (in the beginning of your script):\n", " \n", "```python\n", "from __future__ import division\n", "```\n", "\n", "Alternatively, you can of course also just convert one of the operands (or both) to `float` beforehand." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## More Operators\n", "\n", "Let's see, what else do we have?\n", "Powers, for example. While you might be used to the `^` operator from other languages, Python uses `**` for that. The `^` operator is a very different thing, namely *xor*. Don't confuse the two!" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3 ** 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Of course, there is also a *modulo* operator:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "13 % 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Besides the these [arithmetic operators](https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex), there are also [comparison operators](https://docs.python.org/3/library/stdtypes.html#comparisons) which return *boolean* values." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3 > 4" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3 <= 4" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3 + 1 == 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Expressions yielding boolean values can be combined with [logical operators](https://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not):" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "False and True" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "False or True" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "not True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python also provides the [bit-wise operators](https://docs.python.org/3/library/stdtypes.html#bitwise-operations-on-integer-types)\n", "`|`,\n", "`^`,\n", "`&`,\n", "`<<`,\n", "`>>` and\n", "`~`, but you'll need those only if you're into bit-dwiddling, which you probably aren't, right?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Operator Precedence\n", "\n", "When using more than one operator in the same expression, you should be aware that some operators bind stronger than others, e.g. multiplication binds stronger than addition (which shouldn't come as a surprise!):" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "42" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2 + 4 * 10" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For the full list of operators and their precedence, have a look at the [official docs](https://docs.python.org/3/reference/expressions.html#operator-precedence).\n", "\n", "If you want to interfere with the built-in precedence, you can use parentheses (which again shouldn't come as a surprise):" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "60" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(2 + 4) * 10" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Strings\n", "\n", "As we saw above, strings can be written using double quotes:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello, world!'" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"Hello, world!\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "However, it's also possible to write them with single quotes:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello, world!'" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'Hello, world!'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To the Python interpreter, this doesn't make a difference. It is, however, common to use double quotes for strings containing natural language and anything that is at some point presented to the user. Single quotes are normally used for short strings which only appear inside a program.\n", "In case of doubt, use single quotes (since that's what the Python interpreter defaults to).\n", "\n", "If you want to use one type of quotes as part of the string itself, just use the other type of quotes to delimit the string:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"What's up?\"" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"What's up?\"" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Please print \"Hello, world!\" to the screen.'" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'Please print \"Hello, world!\" to the screen.'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want to use both types of quotes, just choose one of them for delimiting your string.\n", "You'll have to escape those quotes within the string by prepending a backslash (`\\\"` or `\\'`).\n", "\n", "Note how the Python interpreter chooses to display this string:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Let\\'s print \"Hello, world!\" to the screen!'" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"Let's print \\\"Hello, world!\\\" to the screen!\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Both variants have the type `str` (since they are really the same thing):" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "str" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(\"Hello, world!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can use [str()](http://docs.python.org/3/library/stdtypes.html#str) to convert any object to a string:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'42'" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "str(42)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is a special notation for writing multi-line string literals using triple double quotes:" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'One,\\ntwo,\\nthree lines'" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"\"\"One,\n", "two,\n", "three lines\"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The same can also be written with triple single quotes, but this is much less common.\n", "\n", "Strings can be concatenated with the `+` operator:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello, world!'" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'Hello' + ',' + ' ' + 'world' + '!'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `*` operator (in combination with an `int`) has a special meaning for a `str`:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'###############################################################################'" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'#' * 79" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Strings also have an `in`-operator, which makes it very simple to check if a string contains a given substring:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'world' in 'Hello, world!'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you are pessimistic, you can also try `not in`:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'happy' not in 'Hello, world!'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Unlike in many other programming languages, there is no separate type for single characters in Python. Single characters are simply written as strings which happen to contain only one character.\n", "\n", "Each character has a numeric equivalent which can be shown by the [ord()](http://docs.python.org/3/library/functions.html#ord) function.\n", "The function [chr()](http://docs.python.org/3/library/functions.html#chr) can be used to convert in the other direction." ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "32" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ord(' ')" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'A'" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "chr(65)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want to create a string that contains formatted numeric values, it's best to use the [`format()` method](https://docs.python.org/3/library/string.html#formatstrings):" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'The value of 𝜋 is about 3.14'" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'The value of {} is about {:.3}'.format('𝜋', 3.1415)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here you can also see that Python supports [Unicode characters](https://docs.python.org/3/howto/unicode.html) by default.\n", "\n", "In older Python code you might find a different way of string formatting:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'The value of 𝜋 is about 3.14'" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'The value of %s is about %.2f' % ('𝜋', 3.1415)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This [old-style string formatting](https://docs.python.org/3/library/stdtypes.html#old-string-formatting) is quite similar to the above, but sometimes less flexible and more error-prone.\n", "In case of doubt, you should use the more modern `format()` method.\n", "\n", "There is much more to say about strings. To learn more about them, have a look at the [official `str` documentation](https://docs.python.org/3.3/library/stdtypes.html#textseq)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Lists\n", "\n", "A `list` is a container that can hold arbitrary objects. A `list` can be created by putting objects, separated by commas, between a pair of brackets." ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[42, 3.1415, 'Ni!']" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[42, 3.1415, 'Ni!']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that a `list` doesn't contain the actual objects, it just contains *references* to the objects.\n", "\n", "An empty list looks like this:" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Of course, a list can also have just a single element:" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[7]" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[7]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To concatenate multiple lists, the `+` operator can be used:" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 4, 5, 6]" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[1, 2] + [3] + [4, 5, 6]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similar to strings, you can also use the `*` operator (in combination with an `int`) to repeat lists:" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[1, 2, 3] * 5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lists also have an `in`-operator (like strings and other sequence types):" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3 in [1, 2, 3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Like everything else, lists are also objects, and they have a type:" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "list" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type([1, 2, 3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use [list()](http://docs.python.org/3/library/stdtypes.html#list) to create a list from some other object (which must be *iterable*):" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!']" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list('Hello, world!')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It's very easy to create a list of strings from a single space-separated string:" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['eggs', 'bacon', 'spam']" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'eggs bacon spam'.split()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Of course, there are [options available to change the separator](http://docs.python.org/3/library/stdtypes.html#str.split).\n", "\n", "To combine a sequence of strings into a single string, use the [`join()` method](http://docs.python.org/3/library/stdtypes.html#str.join) (applied to the \"glue\" string):" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'eggs + bacon + spam'" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "' + '.join(['eggs', 'bacon', 'spam'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lists are *mutable* data structures, i.e. their elements can be changed. But more about that later ...\n", "\n", "For more information about lists, have a look at the [official docs](https://docs.python.org/3/library/stdtypes.html#lists)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tuples\n", "\n", "Tuples are quite similar to `list`s, with the main difference that they are *immutable* data structures, i.e. their content cannot be changed. Some objects, separated by commas, create a tuple:" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(42, 3.1415, 'Ni!')" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "42, 3.1415, 'Ni!'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Just like lists, tuples can also hold arbitrary objects (and they contain references, not the actual objects).\n", "\n", "Tuples are often enclosed in parentheses, but those are only really required if otherwise the code would be ambiguous, e.g. when creating a tuple of tuples:" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, (2, 3), 4)" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1, (2, 3), 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another situation where parentheses are obligatory, are empty tuples:" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "()" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Attention**: Putting a single item between parentheses does not create a tuple!" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "7" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(7)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is because parentheses can be used around arbitrary expressions to force [operator precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence).\n", "This has nothing to do with `tuple`s:" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "42" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(6 + 1) * 6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A non-empty tuple is created with an obligatory comma, the parentheses are optional:" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(7,)" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "7," ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Like `str` and `list`, `tuple`s can be concatenated with the `+` operator and repeated with `*`:" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, 2, 3, 3, 3, 3, 3)" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(1, 2) + (3,) * 5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the parentheses are obligatory in this case.\n", "\n", "Like lists and strings, tuples also support the `in`-operator:" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3 in (1, 2, 3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It should come as no surprise that tuples also have a type:" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "tuple" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type((1, 2, 3))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that when used as a function argument, the tuple has to be enclosed in parentheses (otherwise it would be interpreted as a function call with multiple arguments).\n", "\n", "For more information about tuples, have a look at the [official docs](https://docs.python.org/3/library/stdtypes.html#tuples)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sets\n", "\n", "Sets are very similar to lists, except that their elements are not ordered and they are unique.\n", "A `set` can be created by putting objects, separated by commas, between a pair of braces." ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{3.1415, 42, 'Ni!'}" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{42, 3.1415, 'Ni!', 42}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An empty set cannot be created with an empty pair of braces, because this would create an empty dictionary (see [below](#Dictionaries)):" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type({})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To create an empty set, you'll have to use the `set()` constructor:" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "set()" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "set()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For a set with a single element, this isn't a problem, though:" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{42}" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{42}" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "set" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type({42})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sets do have a few special operators: *union* ..." ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{1, 2, 3, 4}" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{1, 2, 3} | {2, 3, 4}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... *intersection* ..." ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{2, 3}" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{1, 2, 3} & {2, 3, 4}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... *difference* ..." ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{1}" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{1, 2, 3} - {2, 3, 4}" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{4}" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{2, 3, 4} - {1, 2, 3}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... *exclusive difference* ..." ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{1, 4}" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{1, 2, 3} ^ {2, 3, 4}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... and a few more.\n", "\n", "Of course, we can also simply check if a certain item is contained in a given set:" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3 in {1, 2, 3}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Any *iterable* can be turned into a `set` ..." ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{' ', '!', ',', 'H', 'd', 'e', 'l', 'o', 'r', 'w'}" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "set('Hello, world!')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... and a `set` is itself iterable and can be turned into, e.g. a `list`:" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[42, 3.1415, 'Ni!']" ] }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list({42, 3.1415, 'Ni!'})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For more information about sets, have a look at the [official docs](https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Expressions, Statements, Side Effects\n", "\n", "When you write Python code, you write a sequence of [statements](https://en.wikipedia.org/wiki/Statement_%28computer_science%29).\n", "There are several different kinds of statements, some of which will be explained in this notebook.\n", "\n", "What we were seeing up to now were *expression statements*.\n", "Each of the code cells above holds an [expression](https://en.wikipedia.org/wiki/Expression_%28computer_science%29).\n", "Simply put, an *expression* is a piece of code that can be evaluated which results in some *value*, or more generally speaking, some *object*.\n", "\n", "An *expression* may contain arbitrarily many other *expressions*, but no *statements*.\n", "\n", "A *statement*, however, may contain *expressions* and sometimes also other *statements*.\n", "\n", "An *expression* always returns a *value*, a *statement* never returns a value.\n", "\n", "But never say never ...\n", "\n", "There is this strange thing called *expression statement*, which turns an *expression* into a *statement* by ignoring its return value.\n", "But when used in an interactive Python session, this behaves differently!\n", "When evaluating a *statement* which happens to be an *expression*, on an interactive Python prompt, the result will actually be shown to you.\n", "In a Jupyter/IPython notebook, a *code cell* may contain multiple *statements*, and if the *last* one happens to be an *expression statement*, its *value* is returned:" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "42" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[2 + 2, 4 + 4, 6 + 6]\n", "10 * 9 + 9\n", "'Hello, World!'\n", "4 < 3\n", "7 * 6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you see, there are several *expressions* in the code cell above; all of them are evaluated, but only the result of the last one is shown.\n", "\n", "So what's the use of those expressions above if we don't see their results?\n", "\n", "There is none.\n", "\n", "Unless they have *side effects* ...\n", "\n", "Some expressions not only return a *value*, they also do some other things which don't have anything to do with returning values.\n", "Those other things are called *side effects*.\n", "For more information see [the Wikipedia article][1].\n", "\n", "[1]: http://en.wikipedia.org/wiki/Side_effect_(computer_science)\n", "\n", "For, example, the `print()` function which we saw at the very top of this page, prints the given arguments to the *standard output*." ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, world!\n" ] }, { "data": { "text/plain": [ "42" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print('Hello, world!')\n", "7 * 6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The string `'Hello, world!'` which is printed by the `print()` function, is *not* the *return value* of the function!\n", "What we see here is the so-called *standard output* which, in a Jupyter/IPython notebook, is displayed just below the code cell, but above the actual output values (marked by `Out[...]:`).\n", "\n", "The actual return value is the result of the last expression in the code cell.\n", "\n", "So what's the return value of the `print()` function?\n", "A function call is just an *expression*, so it should have a return value, right?\n", "Let's check:" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, world!\n" ] } ], "source": [ "print('Hello, world!')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you can see, there is no `Out[...]:` section above.\n", "Does this mean that the line isn't an expression?\n", "Or does this mean that, contrary to what I told you, not all expressions return a value?\n", "\n", "No, I didn't lie to you!\n", "\n", "By convention, when a Python expression doesn't have anything meaningful to evaluate to (like the `print()` function), it returns a special Python object called `None`.\n", "This is Python's way of saying \"nothing\".\n", "You see, even \"nothing\" is an object in Python!\n", "\n", "So this function returns `None`, but the interactive interpreter, again by convention, doesn't show this, since it's just \"nothing\", anyway.\n", "Let's check:" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [], "source": [ "None" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Really, we see nothing.\n", "\n", "We can use the `is`-operator to check if some object is `None` (see below for an explanation of the `is`-operator)." ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, world!\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print('Hello, world!') is None" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can see that the `print()` function prints its argument to the standard output and returns `None`.\n", "\n", "Very often, one line of code is one statement, but sometimes statements can also span several lines.\n", "And we can fit multiple statements into one line by separating them with semicolons:" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "semicolons are rare in Python code\n" ] }, { "data": { "text/plain": [ "4" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print('semicolons are rare in Python code'); 2 + 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Most of the time, however, this is not necessary.\n", "Others will understand your code better if you start each statement on a new line.\n", "\n", "Another use of the semicolon, in an interactive Python session, is to ignore the value of the last expression (the ones before are ignored anyway):" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [], "source": [ "7 * 6\n", "3.1415\n", "2 + 2;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In a \"normal\" Python program this is never necessary, because the return value of expressions in *expression statements* is always ignored.\n", "\n", "You will need this very rarely, don't make it a habit to end your lines with semicolons!\n", "\n", "Until now, we've talked about *expression statements*. There are several other kinds of statements which can be used to control program flow, define functions and classes, raise exceptions etc.\n", "\n", "Let's continue with a very important statement: the *assignment statement*." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Assignment\n", "\n", "Assignment may seem to be a trivial topic, but there are some subtleties involved.\n", "So please bear with me, since this is essential stuff.\n", "\n", "Note that assignment is a *statement* and not an *operator*.\n", "An assignment cannot be used as part of an *expression*.\n", "This may be surprising if you're used to programming in C or similar programming languages.\n", "If not, it might seem quite straightforward, though.\n", "\n", "An assignment statement consists of three things:\n", "\n", "* a single equals sign (`=`, not to be confused with the above-mentioned equality operator `==`),\n", "* *something on the left* of the equals sign and\n", "* *an expression* on the right of the equals sign.\n", "\n", "The part to the right is easy, this can be just any *expression*, e.g. any of the expressions from above could be on the right side of an assignment.\n", "\n", "The \"*something on the left*\" is the more interesting part.\n", "This can be one of several quite different things, which are described in the following sections.\n", "For all the gory details, have a look in [the official Python documentation](http://docs.python.org/3/reference/simple_stmts.html#assignment-statements)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Identifiers (a.k.a. Names, a.k.a. Variables)\n", "\n", "The *\"something on the left\"* can be a so-called *identifier*.\n", "This is a *name* that can be *bound* to an object.\n", "An *identifier* may only contain letters, numbers and underscores and it must not start with a number." ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [], "source": [ "answer = 7 * 6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this example, the expression to the right of the equals sign is evaluated, creating a new object (of type `int`) with the value `42`.\n", "The assignment statement *binds* the identifier `answer` to this new object.\n", "\n", "Note that the identifier `answer` didn't exist before.\n", "In Python, it's not necessary to *declare* identifiers, new identifiers are created by just assigning to them.\n", "\n", "Once a name has been assigned, it can be used in an expression, as a *reference* to the original object:" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "answer > 50" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some Python beginners use the wrong mental image when thinking of Python *variables*/*identifiers*.\n", "In some other programming languages, a *variable* can be thought of \"a box where we can store a certain type of value in\".\n", "Over the course of a program, we can put different values into this box.\n", "For example, in the programming language C it might look something like this:\n", "\n", "```c\n", "int answer;\n", "answer = 7 * 6;\n", "```\n", "\n", "In this code snippet, a *variable* named `answer` is first *declared*.\n", "At this point, the *type* of the variable has to be specified.\n", "Later, a value (of the correct type) is assigned to the variable.\n", "\n", "> Note: This is actually bad style.\n", "> You should never declare an uninitialized variable, because if you forget to assign a value to it, this might lead to very strange and hard-to-find errors.\n", "> In this example, it would be better to do the declaration and initialization in one statement:\n", ">\n", "> ```c\n", "> int answer = 7 * 6;\n", "> ```\n", ">\n", "> Anyway, this isn't a C tutorial ...\n", "\n", "In this C-example, the *variable* named `answer` is actually a \"box where we can store an `int` value\".\n", "And later, if we feel like it, we can put another value into the box, which overwrites (and therefore *destroys*) the old value.\n", "\n", "In Python, this is different.\n", "The *identifier* named `answer` is not a \"box\".\n", "It is rather a \"label\", similar to a sticky note which we can stick onto an (already existing) object.\n", "In our example, we stick it to an object that has the type `int` and the value `42`.\n", "This object was created by the Python interpreter during evaluation of the *expression* `7 * 6`.\n", "The object itself doesn't have a name (it just has a memory address), but we can *bind* a name to it, in our example the name `answer`.\n", "\n", "Now what happens in the following statement?" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "int" ] }, "execution_count": 85, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(answer)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It looks like the *identifier* `answer` has a *type* after all!\n", "\n", "But strictly speaking, this isn't true.\n", "An identifier is one of the few things in Python that isn't an object.\n", "Therefore, it doesn't have a *type*, either.\n", "However, an *identifier* is always *bound* to an object.\n", "In other words, an *identifier* is a *reference* to an object.\n", "Whenever we use an *identifier*, it is as if we were using the actual referenced object instead.\n", "This is why the previous statement returned `int`, which isn't the type of the *identifier* but the type of the object it's currently bound to.\n", "\n", "The only place where an identifier is *not* treated like the object it's bound to, is on the left side of an *assignment statement* (and inside a [del](https://docs.python.org/3/reference/simple_stmts.html#del) statement, but let's not worry about that right now).\n", "That's also the reason why assignment is not (and cannot be) an *operator* and why it cannot be used as part of an expression.\n", "\n", "We learned that a new identifier can be created by just using a name that hasn't been used before in an assignment statement.\n", "But what happens if we assign to a name that has already been used?" ] }, { "cell_type": "code", "execution_count": 86, "metadata": {}, "outputs": [], "source": [ "answer = 'Sir Lancelot of Camelot'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Well, nothing special.\n", "The name `answer` is just *re-bound* to the object at the right side of the equals sign.\n", "\n", "Here we also see that the identifier itself doesn't have a type, it's just a label that is bound to some object.\n", "The objects themselves do have types; the previous one was of type `int` while the new one is of type `str`." ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "str" ] }, "execution_count": 87, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(answer)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So what happened to the `int` object with the value `42`?\n", "\n", "It's *not* overwritten, but we cannot access it anymore, because we don't have an identifier that references it.\n", "Have a look at [Garbage Collection](#Garbage-Collection) below to see what the Python interpreter does with objects which are not bound to any name.\n", "\n", "Note that an identifier is only treated specially on the left side of an assignment statement.\n", "The right side of the assignment statement is just a normal expression which can contain other identifiers (or even the same identifier that is going to be re-bound on the left)." ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [], "source": [ "greeting = answer + ', nice to meet you!'" ] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [], "source": [ "greeting = 'My name is ' + greeting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since assignment is a statement (and statements don't return values), we don't see the value of the new object where `greeting` is bound to.\n", "Let's have a look:" ] }, { "cell_type": "code", "execution_count": 90, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'My name is Sir Lancelot of Camelot, nice to meet you!'" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "greeting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Of course, one object can have multiple labels stuck to it:" ] }, { "cell_type": "code", "execution_count": 91, "metadata": {}, "outputs": [], "source": [ "the_same_greeting = greeting" ] }, { "cell_type": "code", "execution_count": 92, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'My name is Sir Lancelot of Camelot, nice to meet you!'" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "the_same_greeting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Obviously, the returned string has exactly the same characters.\n", "In other words, it's *equal* to `greeting`.\n", "We can check this with the *equality operator*:" ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 93, "metadata": {}, "output_type": "execute_result" } ], "source": [ "greeting == the_same_greeting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But the two are more than equal!\n", "They are actually two different names for the same object.\n", "To show that, we can check Python's internal representation of the objects.\n", "Each object that's currently existing in the Python interpreter, has a unique ID, which we can query with the `id()` function:" ] }, { "cell_type": "code", "execution_count": 94, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "139679591174504" ] }, "execution_count": 94, "metadata": {}, "output_type": "execute_result" } ], "source": [ "id(greeting)" ] }, { "cell_type": "code", "execution_count": 95, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "139679591174504" ] }, "execution_count": 95, "metadata": {}, "output_type": "execute_result" } ], "source": [ "id(the_same_greeting)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we can see, the two objects have the same ID, so it's actually just one object that happens to have two names bound to it.\n", "\n", "Python even has a special operator for checking if two objects are actually the same object: the *identity operator*." ] }, { "cell_type": "code", "execution_count": 96, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ "greeting is the_same_greeting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We normally don't care about the actual IDs, if we want to see if two objects are *identical* (which is not the same as *equal*!), we use the `is`-operator.\n", "\n", "If you want to bind several names to the same object in one go, you can use a special form of the assignment statement that uses multiple equals signs:" ] }, { "cell_type": "code", "execution_count": 97, "metadata": {}, "outputs": [], "source": [ "one = two = three = 'data'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now all of the identifiers `one`, `two` and `three` are bound to the same `str` object.\n", "You may not need that very often, but it's still good to know.\n", "\n", "Let me emphasize again:\n", "An *identifier* in Python isn't a *box* where we can put values into, it's rather a *label* that we attach to an existing object.\n", "\n", "Many Python tutorials make the mistake of explaining Python *variables* (which should probably better be called *identifiers*) as \"boxes\", but that's plain wrong.\n", "The error can easily be shown by creating multiple identifiers which are bound to the same object.\n", "Let's use the previous example:\n", "If `one`, `two` and `three` would actually be \"boxes\", *each one* of them would have to hold its own copy of the string `\"data\"`.\n", "Therefore, each of the three strings would have to be a different `str` object.\n", "But we can easily show that the three *identifiers* are bound to the same one and only one object:" ] }, { "cell_type": "code", "execution_count": 98, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 98, "metadata": {}, "output_type": "execute_result" } ], "source": [ "one is two is three" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another misconception that comes with the \"box\"-analogy, is that an assignment puts the new data at the same memory location where the old data was before, effectively overwriting the old object.\n", "\n", "This is far from true.\n", "When assigning to an already existing identifier, we do not change any object, we just stick the *label* onto a different object.\n", "The new object must already exist before it is bound to the *identifier*, therefore it *has to* occupy a different memory area than the old object.\n", "The old object may or may not be destroyed right after the assignment, but that's a very different story (see [Garbage Collection](#Garbage-Collection)).\n", "\n", "It can be easily shown that assignment doesn't overwrite old data:" ] }, { "cell_type": "code", "execution_count": 99, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9078976" ] }, "execution_count": 99, "metadata": {}, "output_type": "execute_result" } ], "source": [ "number = 0\n", "id(number)" ] }, { "cell_type": "code", "execution_count": 100, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9079008" ] }, "execution_count": 100, "metadata": {}, "output_type": "execute_result" } ], "source": [ "number = 1\n", "id(number)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If the second assignment would overwrite the memory area of the old data, `id()` would return the same value as before.\n", "But we see that the IDs are different, therefore, `0` and `1` must be different objects.\n", "\n", "I'm sorry that I repeat my self so often, but this is really important:\n", "Assignment to an existing *identifier* does not modify any object!\n", "\n", "We'll see a bit further down how we can actually modify objects.\n", "\n", "I try to avoid using the term \"variable\" for a Python *identifier*, because I think many people will associate this term with a \"box\", rather than a \"label\".\n", "But it's of course not forbidden to call it *variable*, and sometimes it just sounds more natural.\n", "\n", "By the way, if you want to use more technical terms instead of \"box\" and \"label\", you can use the terms *value semantics* and *reference semantics*, respectively.\n", "Python has *reference semantics*.\n", "\n", "See also [Python Names and Values](https://nedbatchelder.com/text/names1.html), a nice presentation by Ned Batchelder." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Multiple Identifiers (And Other Stuff)\n", "\n", "Binding a name to an object is nothing special; nearly every programming language can do that in one form or another.\n", "\n", "But Python has a very nice additional feature that not many other languages have, that allows to bind *multiple* identifiers to a sequence of objects in a single statement.\n", "Some people also call this *tuple unpacking* or *sequence unpacking*.\n", "See also [Multiple assignment and tuple unpacking improve Python code readability](http://treyhunner.com/2018/03/tuple-unpacking-improves-python-code-readability/), a blog post by Trey Hunner." ] }, { "cell_type": "code", "execution_count": 101, "metadata": {}, "outputs": [], "source": [ "a, b, c = 42, 3.1415, 'Ni!'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This can also be used to easily swap things (again, in a single statement):" ] }, { "cell_type": "code", "execution_count": 102, "metadata": {}, "outputs": [], "source": [ "b, c = c, b" ] }, { "cell_type": "code", "execution_count": 103, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Ni!'" ] }, "execution_count": 103, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On the right side, there can be any *iterable* object.\n", "We already know a few iterable things: a tuple, a list, a string; but there are many more iterable objects out there, just waiting to be discovered!\n", "\n", "On the left side, there are several identifiers, separated by commas.\n", "They can optionally be enclosed in parentheses or brackes.\n", "The number of identifiers must be the same as items in the iterable object on the right.\n", "If not, an error is raised.\n", "\n", "But there is an exception: one of the identifiers may be prefixed with an asterisk, which means that the identifier receives a list of the remaining values, regardless how many they are (the list can also be empty).\n", "Maybe this is best shown in an example:" ] }, { "cell_type": "code", "execution_count": 104, "metadata": {}, "outputs": [], "source": [ "first, *middle, last = 'hello'" ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['e', 'l', 'l']" ] }, "execution_count": 105, "metadata": {}, "output_type": "execute_result" } ], "source": [ "middle" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That's great, isn't it? By the way, this is sometimes called *extended unpacking*.\n", "\n", "> Note, however, that the thing with the starred identifier is only available in Python 3.\n", "\n", "In this example you can see that a string can also be unpacked, since it is *iterable* (yielding single-character strings).\n", "\n", "The list of identifiers doesn't have to be a flat list, it can be arbitrarily nested (using parentheses and/or brackets).\n", "It doesn't even have to be limited to \"plain\" identifiers, it can also contain any of the things mentioned below (attribute references, subscripts, slices)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Attribute References\n", "\n", "It has been quite a while, but I'm still speaking about different variants of the assignment statement.\n", "Until now, we just moved *labels* around, but this one is the first one where we can actually *change* objects.\n", "\n", "Every object has attributes.\n", "They can be accessed by placing a dot (`.`) and the identifier of the attribute after the object.\n", "\n", "If an attribute reference is the \"*something on the left*\" of the equals sign in an assignment statement, it is bound to the object on the right of the equals sign.\n", "If an attribute with the given name doesn't yet exist, it is created.\n", "\n", "Note, however, that not all objects allow attribute assignment and even if they do, only a few special attributes may be allowed to assign to.\n", "\n", "It is especially hard to find objects that allow attribute assignment within the built-in types we've seen so far.\n", "We didn't learn yet how to import stuff from the standard library nor from external libraries; we didn't learn how to create our own classes.\n", "Without explaining any of this, I couldn't find an example that shows attribute assignment.\n", "Bad luck.\n", "But I guess you'll understand it anyway, even without an example." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Element Access (a.k.a. Subscription)\n", "\n", "Another *thing on the left* of the equals sign in an assignment statement can be an object followed by a pair of brackets with some expression inside.\n", "\n", "This is normally available for some kind of collection, like for example a `list`." ] }, { "cell_type": "code", "execution_count": 106, "metadata": {}, "outputs": [], "source": [ "mylist = ['one', 'two', 'five']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In case of a `list`, the subscript (the expression inside of the brackets) must be a single integer.\n", "\n", "Note that Python, like many other programming languages, starts indexing at `0` (which is [the only reasonable choice for a programming language](http://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html)).\n", "So if we want to address the third element of a list, we have to use the subscript `2`:" ] }, { "cell_type": "code", "execution_count": 107, "metadata": {}, "outputs": [], "source": [ "mylist[2] = 'three'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Again, since this is a *statement*, no value is returned." ] }, { "cell_type": "code", "execution_count": 108, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['one', 'two', 'three']" ] }, "execution_count": 108, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that when assigning to a list element, as always, the value is not copied, but merely a reference inside of the list is bound to the object on the right of the equals sign.\n", "\n", "To show this, we can assign a single object to multiple list elements:" ] }, { "cell_type": "code", "execution_count": 109, "metadata": {}, "outputs": [], "source": [ "mylist[0] = mylist[2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The *thing* on the left of the equals sign is again treated specially (because the specified list element is bound to another object).\n", "The *thing* on the right side of the equals sign is just a normal expression, consisting of an *identifier* with the *subscript operator*.\n", "This expression get's evaluated which results in the object which is stored as the third element of the list `mylist` (the string `'three'`).\n", "Strictly speaking, the object is not stored *inside of* the list, the list holds just a reference to this object.\n", "\n", "This assignment statement binds the reference at the first list element to the very same object.\n", "It may seem as if there are two copies of the string stored in the list ..." ] }, { "cell_type": "code", "execution_count": 110, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['three', 'two', 'three']" ] }, "execution_count": 110, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... but the `is`-operator tells us that those are just two references to the same single object:" ] }, { "cell_type": "code", "execution_count": 111, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 111, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist[0] is mylist[2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Negative subscripts are also allowed, which let us index a sequence from the end to the beginning.\n", "The last element corresponds to the index `-1`." ] }, { "cell_type": "code", "execution_count": 112, "metadata": {}, "outputs": [], "source": [ "mylist[-1] = 'one'" ] }, { "cell_type": "code", "execution_count": 113, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['three', 'two', 'one']" ] }, "execution_count": 113, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that assignment to elements of a `tuple` or to characters of a `str` is not possible, since both types are *immutable*!\n", "\n", "However, there are many other *mutable* types which allow *subscription assignment*.\n", "Depending on the type, the *subscript operator* may not (only) accept `int` values but (also) `str` or `tuple` or ...\n", "\n", "One example for such a type is `dict`, which will be explained further down (see [Dictionaries](#Dictionaries))." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Slicing\n", "\n", "Slicing is just a special form of numeric *subscription*.\n", "Instead of a single number, a range of numbers (a so-called *slice*) is specified.\n", "\n", "First, let's re-bind the *identifier* we used before." ] }, { "cell_type": "code", "execution_count": 114, "metadata": {}, "outputs": [], "source": [ "mylist = ['one', 'two', 'three', 'four', 'five']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instead of specifying a single integer as subscript, we use a colon to specify a range of indices." ] }, { "cell_type": "code", "execution_count": 115, "metadata": {}, "outputs": [], "source": [ "mylist[1:4] = 2, 3, 4" ] }, { "cell_type": "code", "execution_count": 116, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['one', 2, 3, 4, 'five']" ] }, "execution_count": 116, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As mentioned before, Python starts indexing at `0`.\n", "\n", "The `stop` value of the slice is also \"special\", since the slice indices go up to, but not including, the `stop` value.\n", "In other words, the subscript in `mylist[start:stop]` describes the half-open interval [`start`, `stop`).\n", "\n", "This may take some time to get used to, but in the long run you'll see that this is a much more straightforward choice then including the `stop` value in the slice.\n", "For more details about this concept, see [Why numbering should start at zero](http://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html) from E. W. Dijkstra.\n", "\n", "The `start` and `stop` values are optional.\n", "If omitted, the slice starts at the beginning of the sequence or goes up to the end, respectively." ] }, { "cell_type": "code", "execution_count": 117, "metadata": {}, "outputs": [], "source": [ "mylist[:3] = '123'" ] }, { "cell_type": "code", "execution_count": 118, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['1', '2', '3', 4, 'five']" ] }, "execution_count": 118, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist" ] }, { "cell_type": "code", "execution_count": 119, "metadata": {}, "outputs": [], "source": [ "mylist[3:] = 'IV', 'V', 'VI'" ] }, { "cell_type": "code", "execution_count": 120, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['1', '2', '3', 'IV', 'V', 'VI']" ] }, "execution_count": 120, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you see here, the number of elements on the left of the equals sign doesn't have to be the same as on the right (except when you use a step size other than one, see below).\n", "\n", "To replace the whole list contents, a single colon (without `start` and `stop`) can be used." ] }, { "cell_type": "code", "execution_count": 121, "metadata": {}, "outputs": [], "source": [ "mylist[:] = 0, 1, 2, 3, 4, 5, 6, 7" ] }, { "cell_type": "code", "execution_count": 122, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 2, 3, 4, 5, 6, 7]" ] }, "execution_count": 122, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that in this case, the actual `list` object is mutated, whereas if an *identifier* is merely re-bound (`mylist = ...`), the original `list` object is *not* mutated.\n", "\n", "In addition to `start` and `stop`, a slice object can also have a `step` size (specified after a second colon)." ] }, { "cell_type": "code", "execution_count": 123, "metadata": {}, "outputs": [], "source": [ "mylist[3::2] = '357'" ] }, { "cell_type": "code", "execution_count": 124, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 2, '3', 4, '5', 6, '7']" ] }, "execution_count": 124, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The default `step` size is, not surprisingly, `1`.\n", "\n", "Like `start` and `stop`, the `step` size can also be negative, meaning a reversed order from the end to the beginning:" ] }, { "cell_type": "code", "execution_count": 125, "metadata": {}, "outputs": [], "source": [ "mylist[::-2] = 'seven', 'five', 'three', 'one'" ] }, { "cell_type": "code", "execution_count": 126, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 'one', 2, 'three', 4, 'five', 6, 'seven']" ] }, "execution_count": 126, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the colon-operator is only allowed within the brackets of a *subscript*.\n", "If you want to create a slice object at a different place, you have to use [slice()](http://docs.python.org/3/library/functions.html#slice)." ] }, { "cell_type": "code", "execution_count": 127, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "slice(None, 4, None)" ] }, "execution_count": 127, "metadata": {}, "output_type": "execute_result" } ], "source": [ "slice(4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If one of `start`, `stop`, `step` is not specified, it is set to `None`.\n", "Like in the colon-notation, each of them is optional." ] }, { "cell_type": "code", "execution_count": 128, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "slice(None, None, None)" ] }, "execution_count": 128, "metadata": {}, "output_type": "execute_result" } ], "source": [ "slice(None)" ] }, { "cell_type": "code", "execution_count": 129, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "slice(1, 4, None)" ] }, "execution_count": 129, "metadata": {}, "output_type": "execute_result" } ], "source": [ "slice(1, 4)" ] }, { "cell_type": "code", "execution_count": 130, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "slice(1, None, 2)" ] }, "execution_count": 130, "metadata": {}, "output_type": "execute_result" } ], "source": [ "slice(1, None, 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Assignment Recap\n", "\n", "We were talking quite a long time about the different forms of assignment statements, here's a quick summary:\n", "\n", "|\"thing on the left\" | example |\n", "|--------------------|---------|\n", "| just an identifier | ``myvar = 42`` |\n", "| attribute reference | ``myobj.attr = 42`` |\n", "| subscript | ``mylist[7] = 42`` |\n", "| slice | ``mylist[2:5] = 42, 43, 44`` |\n", "| several of the above, possibly nested and starred | ``mylist[:2], (a, *b, myobj.attr) = (0, 1), mylist[-5:]`` |" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Augmented Assignment\n", "\n", "Let's assume we have a variable that counts things:" ] }, { "cell_type": "code", "execution_count": 131, "metadata": {}, "outputs": [], "source": [ "counter = 10" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we want to, e.g., decrement this counter by 3, we could write:" ] }, { "cell_type": "code", "execution_count": 132, "metadata": {}, "outputs": [], "source": [ "counter = counter - 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This yields the expected result (it creates a new number and re-binds the variable `counter`) ..." ] }, { "cell_type": "code", "execution_count": 133, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "7" ] }, "execution_count": 133, "metadata": {}, "output_type": "execute_result" } ], "source": [ "counter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... but it's quite annoying that we have to type the variable's name twice, isn't it?\n", "\n", "Luckily, Python has *augmented assignment* which we can use to avoid this hideous duplication:" ] }, { "cell_type": "code", "execution_count": 134, "metadata": {}, "outputs": [], "source": [ "counter -= 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This does exactly the same as before:" ] }, { "cell_type": "code", "execution_count": 135, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 135, "metadata": {}, "output_type": "execute_result" } ], "source": [ "counter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note, however, that this is only true for *immutable* data types (e.g. numbers, strings, tuples).\n", "\n", "When used with a *mutable* object, it will not *re-bind* the identifier to a new object but it will instead change the actual object!\n", "\n", "Let's look at an example with a `list` object (which is mutable).\n", "First, with \"normal\" assignment and re-binding:" ] }, { "cell_type": "code", "execution_count": 136, "metadata": {}, "outputs": [], "source": [ "original_list = [1, 2, 3]\n", "new_list = original_list\n", "new_list = new_list + [4, 5, 6]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The last line creates a new `list` object (as result of the \"+\" operation) and re-binds it to the identifier `new_list`." ] }, { "cell_type": "code", "execution_count": 137, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 4, 5, 6]" ] }, "execution_count": 137, "metadata": {}, "output_type": "execute_result" } ], "source": [ "new_list" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this case there is no difference between mutable and immutable types.\n", "A new object is created and the original object remains untouched:" ] }, { "cell_type": "code", "execution_count": 138, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3]" ] }, "execution_count": 138, "metadata": {}, "output_type": "execute_result" } ], "source": [ "original_list" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's see what happens with augmented assignment:" ] }, { "cell_type": "code", "execution_count": 139, "metadata": {}, "outputs": [], "source": [ "new_list = original_list\n", "new_list += [4, 5, 6]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When we look at the result, we cannot see yet if a new object was created:" ] }, { "cell_type": "code", "execution_count": 140, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 4, 5, 6]" ] }, "execution_count": 140, "metadata": {}, "output_type": "execute_result" } ], "source": [ "new_list" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But notice what happened to the original list object:" ] }, { "cell_type": "code", "execution_count": 141, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 4, 5, 6]" ] }, "execution_count": 141, "metadata": {}, "output_type": "execute_result" } ], "source": [ "original_list" ] }, { "cell_type": "code", "execution_count": 142, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 142, "metadata": {}, "output_type": "execute_result" } ], "source": [ "new_list is original_list" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Obviously, the original `list` object was mutated and no new `list` object was created.\n", "\n", "If we try the exact same augmented assignment with a `tuple` (which is immutable), we observe a different behavior:" ] }, { "cell_type": "code", "execution_count": 143, "metadata": {}, "outputs": [], "source": [ "original_tuple = 1, 2, 3\n", "new_tuple = original_tuple\n", "new_tuple += 4, 5, 6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "At first, it looks the same ..." ] }, { "cell_type": "code", "execution_count": 144, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, 2, 3, 4, 5, 6)" ] }, "execution_count": 144, "metadata": {}, "output_type": "execute_result" } ], "source": [ "new_tuple" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... but the original `tuple` object is unchanged (obviously, because it's *immutable*!):" ] }, { "cell_type": "code", "execution_count": 145, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, 2, 3)" ] }, "execution_count": 145, "metadata": {}, "output_type": "execute_result" } ], "source": [ "original_tuple" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This difference of behavior of the augmented assignment statement for mutable and immutable objects is often the cause for confusion and possibly also for bugs, so be aware!\n", "\n", "Augmented assignment is available for all binary operators:\n", "`+=`,\n", "`-=`,\n", "`*=`,\n", "`/=`,\n", "`//=`,\n", "`%=`,\n", "`**=`,\n", "`>>=`,\n", "`<<=`,\n", "`&=`,\n", "`^=` and\n", "`|=`.\n", "\n", "If you want to know more, have a look at [the docs](https://docs.python.org/3/reference/simple_stmts.html#augmented-assignment-statements)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Garbage Collection\n", "\n", "Remember that Python's variables are not *boxes* where we can put data in, but rather *labels* which we can stick to objects?\n", "\n", "In other words, variables don't reserve a certain area of memory for their values.\n", "The Python interpreter handles all the memory management for us and creates objects for us whenever we ask for them.\n", "When we assign something, we merely stick a *label* to an already existing object which the Python interpreter has created for us.\n", "\n", "This is very convenient because we don't have to bother with the task of reserving the necessary memory for our data and - which is also very important - the freeing of memory which is not needed anymore.\n", "\n", "But how does the Python interpreter know which parts of memory are still needed and which parts can be cleared (and re-used for something else)?\n", "\n", "*The short answer:*\n", "We don't have to care! The Python interpreter just does this automagically! Let's move on to more interesting things!\n", "\n", "*The slightly longer answer:*\n", "Python interpreters typically have some kind of *garbage collector* which is a part of the Python runtime that regularly checks if all objects which occupy memory still have some identifier bound to them.\n", "If not, the object is destroyed and its memory is marked for re-use.\n", "The garbage collector may work significantly differently between different Python interpreters, so you shouldn't count on the details about when and how and if at all garbage collection happens.\n", "The Python reference implementation (CPython) uses *reference counting* to help the garbage collector.\n", "Whenever we bind an object to a variable, the object's reference count is incremented.\n", "If we are re-binding, the reference count of the object the variable was bound to before is decremented.\n", "On each run of the garbage collector it just looks for objects with a reference count of 0 and destroys all those objects." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Dictionaries\n", "\n", "Back to data types!\n", "\n", "We already learned about [numbers](#Numbers), [strings](#Strings), [lists](#Lists), [tuples](#Tuples) and [sets](#Sets).\n", "But Python has several more built-in data types ...\n", "\n", "Another very important one of those is `dict`, which I guess is supposed to be short for \"dictionary\".\n", "A dictionary is a *mapping* from *keys* to *values*.\n", "\n", "To create a `dict`, we write key/value pairs within curly braces.\n", "Keys and values are separated by colons and the whole pairs are separated by commas.\n", "Let's create a dictionary that maps strings to strings:" ] }, { "cell_type": "code", "execution_count": 146, "metadata": {}, "outputs": [], "source": [ "knight = {'name': 'Sir Galahad', 'quest': 'To seek the Grail'}" ] }, { "cell_type": "code", "execution_count": 147, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'name': 'Sir Galahad', 'quest': 'To seek the Grail'}" ] }, "execution_count": 147, "metadata": {}, "output_type": "execute_result" } ], "source": [ "knight" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the displayed order of key/value pairs is not necessarily the same as when creating the `dict`.\n", "The order may even change when key/value pairs are added or removed.\n", "\n", "Let's see if we really created a `dict`:" ] }, { "cell_type": "code", "execution_count": 148, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict" ] }, "execution_count": 148, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(knight)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Yes, it is a `dict` indeed.\n", "\n", "We can use the subscript operator (a.k.a. indexing operator) to query which value is associated with a given key." ] }, { "cell_type": "code", "execution_count": 149, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Sir Galahad'" ] }, "execution_count": 149, "metadata": {}, "output_type": "execute_result" } ], "source": [ "knight['name']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can create a new key/value pair by assigning an object to a new key:" ] }, { "cell_type": "code", "execution_count": 150, "metadata": {}, "outputs": [], "source": [ "knight['favorite color'] = 'Blue'" ] }, { "cell_type": "code", "execution_count": 151, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'name': 'Sir Galahad', 'quest': 'To seek the Grail', 'favorite color': 'Blue'}" ] }, "execution_count": 151, "metadata": {}, "output_type": "execute_result" } ], "source": [ "knight" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also re-bind an existing key to a new object:" ] }, { "cell_type": "code", "execution_count": 152, "metadata": {}, "outputs": [], "source": [ "knight['favorite color'] = 'Yellow'" ] }, { "cell_type": "code", "execution_count": 153, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'name': 'Sir Galahad',\n", " 'quest': 'To seek the Grail',\n", " 'favorite color': 'Yellow'}" ] }, "execution_count": 153, "metadata": {}, "output_type": "execute_result" } ], "source": [ "knight" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can query all the keys in a `dict` ..." ] }, { "cell_type": "code", "execution_count": 154, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict_keys(['name', 'quest', 'favorite color'])" ] }, "execution_count": 154, "metadata": {}, "output_type": "execute_result" } ], "source": [ "knight.keys()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... all the values ..." ] }, { "cell_type": "code", "execution_count": 155, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict_values(['Sir Galahad', 'To seek the Grail', 'Yellow'])" ] }, "execution_count": 155, "metadata": {}, "output_type": "execute_result" } ], "source": [ "knight.values()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... and all key/value pairs:" ] }, { "cell_type": "code", "execution_count": 156, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict_items([('name', 'Sir Galahad'), ('quest', 'To seek the Grail'), ('favorite color', 'Yellow')])" ] }, "execution_count": 156, "metadata": {}, "output_type": "execute_result" } ], "source": [ "knight.items()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use the `in`-operator to check if a certain key is available in a given `dict`:" ] }, { "cell_type": "code", "execution_count": 157, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 157, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'favorite color' in knight" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A `dict` object is *iterable*, but if we iterate over it (e.g. while building a `list`), it only yields the keys (and no values):" ] }, { "cell_type": "code", "execution_count": 158, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['name', 'quest', 'favorite color']" ] }, "execution_count": 158, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(knight)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To add the contents of one dictionary to another dictionary, you can use the `update()` method:" ] }, { "cell_type": "code", "execution_count": 159, "metadata": {}, "outputs": [], "source": [ "knight.update({'nickname': 'The Pure', 'home castle': 'Camelot'})" ] }, { "cell_type": "code", "execution_count": 160, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'name': 'Sir Galahad',\n", " 'quest': 'To seek the Grail',\n", " 'favorite color': 'Yellow',\n", " 'nickname': 'The Pure',\n", " 'home castle': 'Camelot'}" ] }, "execution_count": 160, "metadata": {}, "output_type": "execute_result" } ], "source": [ "knight" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Until now, we only have used strings as keys and values, but both can have arbitrary types (except that keys must not be mutable objects or rather - more correctly speaking - keys have to be *hashable*).\n", "\n", "Here is a strange dictionary with several different types:" ] }, { "cell_type": "code", "execution_count": 161, "metadata": {}, "outputs": [], "source": [ "stuff = {'number': 42, 23: [1, 2, 3], (9, 8, 7): 'tuple'}" ] }, { "cell_type": "code", "execution_count": 162, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "42" ] }, "execution_count": 162, "metadata": {}, "output_type": "execute_result" } ], "source": [ "stuff['number']" ] }, { "cell_type": "code", "execution_count": 163, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3]" ] }, "execution_count": 163, "metadata": {}, "output_type": "execute_result" } ], "source": [ "stuff[23]" ] }, { "cell_type": "code", "execution_count": 164, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'tuple'" ] }, "execution_count": 164, "metadata": {}, "output_type": "execute_result" } ], "source": [ "stuff[9, 8, 7]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To create an empty dictionary, just use empty braces:" ] }, { "cell_type": "code", "execution_count": 165, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{}" ] }, "execution_count": 165, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{}" ] }, { "cell_type": "code", "execution_count": 166, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict" ] }, "execution_count": 166, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type({})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In many cases, a `dict` literal (= the thing with the curly braces) is the easiest way to create a `dict` ..." ] }, { "cell_type": "code", "execution_count": 167, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'name': 'Sir Galahad', 'quest': 'To seek the Grail'}" ] }, "execution_count": 167, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{'name': 'Sir Galahad', 'quest': 'To seek the Grail'}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... but you can also use the `dict()` constructor with an iterable of pairs ..." ] }, { "cell_type": "code", "execution_count": 168, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'name': 'Sir Galahad', 'quest': 'To seek the Grail'}" ] }, "execution_count": 168, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dict([['name', 'Sir Galahad'], ['quest', 'To seek the Grail']])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... or (if your keys are valid Python identifiers) you can use `dict()` with keyword arguments:" ] }, { "cell_type": "code", "execution_count": 169, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'name': 'Sir Galahad', 'quest': 'To seek the Grail'}" ] }, "execution_count": 169, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dict(name='Sir Galahad', quest='To seek the Grail')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want to know more about dictionaries, have a look at [the official docs](https://docs.python.org/3/library/stdtypes.html#mapping-types-dict)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comments" ] }, { "cell_type": "code", "execution_count": 170, "metadata": {}, "outputs": [], "source": [ "# no comment" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Functions" ] }, { "cell_type": "code", "execution_count": 171, "metadata": {}, "outputs": [], "source": [ "# docstrings" ] }, { "cell_type": "code", "execution_count": 172, "metadata": {}, "outputs": [], "source": [ "# built-in functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `if` Statements" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Significant Whitespace" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loops" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ranges" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exceptions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Classes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Modules" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## PEP 8" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Many More Things ...\n", "\n", "* dir(), introspection\n", "* list/set/dict comprehensions\n", "* iterators\n", "* generators\n", "* generator expressions\n", "* `if`/`else` expressions\n", "* anonymous functions (a.k.a. `lambda`s)\n", "* bytes\n", "* `*args`, `**kwargs`\n", "* globals()/locals()\n", "* del\n", "* static methods, class methods\n", "* \"special\" methods, operator overloading\n", "* properties, descriptors\n", "* metaclasses\n", "* ..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

\n", " \n", " \"CC0\"\n", " \n", "
\n", " To the extent possible under law,\n", " the person who associated CC0\n", " with this work has waived all copyright and related or neighboring\n", " rights to this work.\n", "

" ] } ], "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.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }