{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# A Short 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 [IPython](http://ipython.org/), which is described on a [separate page](intro-ipython.ipynb).\n", "\n", "Actually, this very page you're just reading is a so-called [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 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.\n", "You can step through all the cells by pressing Shift+Enter repeatedly." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Python 2 vs. 3\n", "\n", "TODO\n", "\n", "Bottom line: use Python 3!\n", "The appropriate commands may be called `python3` and `ipython3` on your computer." ] }, { "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": { "collapsed": false }, "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.\n", "\n", "But now for 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": 2, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "42" ] }, "execution_count": 2, "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": 3, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3.1415" ] }, "execution_count": 3, "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": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "int" ] }, "execution_count": 4, "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": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "float" ] }, "execution_count": 5, "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": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "42.0" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "float(42)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "TODO: infinite precision `int` (or `long`?), 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": 7, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(2.4+3.1j)" ] }, "execution_count": 7, "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": 8, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "complex" ] }, "execution_count": 8, "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)." ] }, { "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": 9, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2 + 3" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5.0" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2.0 + 3.0" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "7.5" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "5 + 2.5" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2 * 3" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "-16.5" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "-4 * (3 + 1) - 0.5" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2.5" ] }, "execution_count": 14, "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": 15, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 15, "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.\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 logical *xor*. Don't confuse the two!" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 16, "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": 17, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "13 % 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Besides the these *arithmetic operators*, there are also *comparison operators* which return *boolean* values." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3 > 4" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3 <= 4" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3 + 1 == 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Strings\n", "\n", "As we saw above, strings can be written using double quotes:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'Hello, world!'" ] }, "execution_count": 21, "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": 22, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'Hello, world!'" ] }, "execution_count": 22, "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", "\n", "Both variants have the type `str`:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "str" ] }, "execution_count": 23, "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": 24, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'42'" ] }, "execution_count": 24, "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": 25, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'One,\\ntwo,\\nthree lines'" ] }, "execution_count": 25, "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": 26, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'Hello, world!'" ] }, "execution_count": 26, "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": 27, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'###############################################################################'" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"#\" * 79" ] }, { "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": 28, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "32" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ord(\" \")" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'A'" ] }, "execution_count": 29, "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": 30, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'The value of 𝜋 is about 3.14'" ] }, "execution_count": 30, "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": 31, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'The value of 𝜋 is about 3.14'" ] }, "execution_count": 31, "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": 32, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[42, 3.1415, 'Ni!']" ] }, "execution_count": 32, "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": 33, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 33, "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": 34, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[7]" ] }, "execution_count": 34, "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": 35, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 4, 5, 6]" ] }, "execution_count": 35, "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": 36, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[1, 2, 3] * 5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Like everything else, lists are also objects, and they have a type:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "list" ] }, "execution_count": 37, "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": 38, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "['H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!']" ] }, "execution_count": 38, "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": 39, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "['eggs', 'bacon', 'spam']" ] }, "execution_count": 39, "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": 40, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'eggs + bacon + spam'" ] }, "execution_count": 40, "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 ..." ] }, { "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": 41, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(42, 3.1415, 'Ni!')" ] }, "execution_count": 41, "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)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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": 42, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(1, (2, 3), 4)" ] }, "execution_count": 42, "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": 43, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "()" ] }, "execution_count": 43, "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": 44, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "7" ] }, "execution_count": 44, "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": 45, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "42" ] }, "execution_count": 45, "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": 46, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(7,)" ] }, "execution_count": 46, "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": 47, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(1, 2, 3, 3, 3, 3, 3)" ] }, "execution_count": 47, "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", "It should come as no surprise that tuples also have a type:" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "tuple" ] }, "execution_count": 48, "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)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Expressions, Statements, Side Effects\n", "\n", "When you write Python code, you write a sequence of *statements*.\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*.\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 an 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": 49, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "42" ] }, "execution_count": 49, "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": 50, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, world!\n" ] }, { "data": { "text/plain": [ "42" ] }, "execution_count": 50, "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 an 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": 51, "metadata": { "collapsed": false }, "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 return (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": 52, "metadata": { "collapsed": false }, "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": 53, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, world!\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 53, "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": 54, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "semicolons are rare in Python code\n" ] }, { "data": { "text/plain": [ "4" ] }, "execution_count": 54, "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": 55, "metadata": { "collapsed": false }, "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 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": 56, "metadata": { "collapsed": false }, "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": 57, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 57, "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`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now what happens in the following statement?" ] }, { "cell_type": "code", "execution_count": 58, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "int" ] }, "execution_count": 58, "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 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*.\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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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", "\n", "But what happens if we assign to a name that has already been used?" ] }, { "cell_type": "code", "execution_count": 59, "metadata": { "collapsed": false }, "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": 60, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "str" ] }, "execution_count": 60, "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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": 61, "metadata": { "collapsed": false }, "outputs": [], "source": [ "greeting = answer + \", nice to meet you!\"" ] }, { "cell_type": "code", "execution_count": 62, "metadata": { "collapsed": false }, "outputs": [], "source": [ "greeting = \"My name is \" + greeting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since assignment is a statement which doesn't return a value, 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": 63, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'My name is Sir Lancelot of Camelot, nice to meet you!'" ] }, "execution_count": 63, "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": 64, "metadata": { "collapsed": false }, "outputs": [], "source": [ "the_same_greeting = greeting" ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'My name is Sir Lancelot of Camelot, nice to meet you!'" ] }, "execution_count": 65, "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": 66, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 66, "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": 67, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "140480868235344" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "id(greeting)" ] }, { "cell_type": "code", "execution_count": 68, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "140480868235344" ] }, "execution_count": 68, "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": 69, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 69, "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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": 70, "metadata": { "collapsed": false }, "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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": 71, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 71, "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": 72, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "10383456" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "number = 0\n", "id(number)" ] }, { "cell_type": "code", "execution_count": 73, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "10383488" ] }, "execution_count": 73, "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 have to 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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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*." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Multiple Identifiers\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*." ] }, { "cell_type": "code", "execution_count": 74, "metadata": { "collapsed": false }, "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": 75, "metadata": { "collapsed": false }, "outputs": [], "source": [ "b, c = c, b" ] }, { "cell_type": "code", "execution_count": 76, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'Ni!'" ] }, "execution_count": 76, "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": 77, "metadata": { "collapsed": false }, "outputs": [], "source": [ "first, *middle, last = \"hello\"" ] }, { "cell_type": "code", "execution_count": 78, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "['e', 'l', 'l']" ] }, "execution_count": 78, "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*.\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": 79, "metadata": { "collapsed": false }, "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": 80, "metadata": { "collapsed": false }, "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": 81, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "['one', 'two', 'three']" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that when assinging 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": 82, "metadata": { "collapsed": false }, "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": 83, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "['three', 'two', 'three']" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... but the `is`-operator tells us that those are just references to a single object:" ] }, { "cell_type": "code", "execution_count": 84, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 84, "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": 85, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "['three', 'two', 'one']" ] }, "execution_count": 85, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist[-1] = 'one'\n", "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 case 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": 86, "metadata": { "collapsed": false }, "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": 87, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "['one', 2, 3, 4, 'five']" ] }, "execution_count": 87, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist[1:4] = 2, 3, 4\n", "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `start` and `stop` values are optional.\n", "If omitted, the slice starts at the beginning of the sequence or reaches until the end, respectively." ] }, { "cell_type": "code", "execution_count": 88, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "['1', '2', '3', 4, 'five']" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist[:3] = \"123\"\n", "mylist" ] }, { "cell_type": "code", "execution_count": 89, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "['1', '2', '3', 'IV', 'V', 'VI']" ] }, "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist[3:] = \"IV\", \"V\", \"VI\"\n", "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": 90, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[0, 1, 2, 3, 4, 5, 6, 7]" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist[:] = 0, 1, 2, 3, 4, 5, 6, 7\n", "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": 91, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[0, 1, 2, '3', 4, '5', 6, '7']" ] }, "execution_count": 91, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist[3::2] = \"357\"\n", "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": 92, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[0, 'one', 2, 'three', 4, 'five', 6, 'seven']" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mylist[::-2] = \"seven\", \"five\", \"three\", \"one\"\n", "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": 93, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "slice(None, 4, None)" ] }, "execution_count": 93, "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": 94, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "slice(None, None, None)" ] }, "execution_count": 94, "metadata": {}, "output_type": "execute_result" } ], "source": [ "slice(None)" ] }, { "cell_type": "code", "execution_count": 95, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "slice(1, 4, None)" ] }, "execution_count": 95, "metadata": {}, "output_type": "execute_result" } ], "source": [ "slice(1, 4)" ] }, { "cell_type": "code", "execution_count": 96, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "slice(1, None, 2)" ] }, "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ "slice(1, None, 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Augmented Assignment\n", "\n", "https://docs.python.org/3/reference/simple_stmts.html#augmented-assignment-statements" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "TODO: mutable vs. immutable" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Garbage Collection" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comments" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Functions" ] }, { "cell_type": "code", "execution_count": 97, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# docstrings" ] }, { "cell_type": "code", "execution_count": 98, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# built-in functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Boolean Values" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## More Operators\n", "\n", "TODO: logic (boolean) operators, in, not in, bit-wise operators" ] }, { "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": [ "## Dictionaries" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ranges" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## None" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exceptions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Modules" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Classes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## PEP 8" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Many More Things ...\n", "\n", "* dir()/help()\n", "* string formatting\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", "* 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", " \n", " Matthias Geier\n", " has waived all copyright and related or neighboring rights to\n", " 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.4.3+" } }, "nbformat": 4, "nbformat_minor": 0 }