{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Python course\n", "\n", "Hannes Ovrén\n", "\n", "Computer Vision Laboratory
\n", "Linköping University\n", "\n", "[hannes.ovren@liu.se](hannes.ovren@liu.se)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# What is Python?\n", "\n", "Wikipedia has this to say:\n", "\n", "> Python is a widely used general-purpose, high-level programming language. Its design philosophy emphasizes code readability, and its syntax allows programmers to express concepts in fewer lines of code than would be possible in languages such as C++ or Java. The language provides constructs intended to enable clear programs on both a small and large scale." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Python History\n", "\n", "- Roots in the late 80's (Guido van Rossum) \n", "- 1994: Version 1.0\n", "- 2000: Version 2.0\n", "- 2008: Version 3.0\n", "- 2010: Version 2.7 (last 2.x release)\n", "- 2015: Version 3.5 (current stable)\n", "\n", "**We will use 3.4+**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# The language at a glance\n", "\n", "- Multiple paradigms\n", " - Object orientated\n", " - Functional\n", " - Procedural\n", " - ...\n", "- Dynamic typing\n", "- Automatic memory management\n", "- Large standard library" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Python as a script\n", "\n", "- Python 3.x: `$ python3 myscript.py`\n", "- Python 2.x: `$ python myscript.py`
or `$ python2 myscript.py`\n", "- `python` *should* point to 2.x (but might not)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "### Hashbang\n", "Add one of the following to the top of the script\n", "\n", "- `#!/usr/bin/env python3`\n", "- `#!/usr/bin/python3`\n", "\n", "Run as\n", "\n", "`$ ./myscript.py`" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Python REPL\n", "\n", "- **R**ead-**E**val-**P**rint-**L**oop\n", "- Interactive work\n", "- Direct Interpreter (`$ python3`)\n", "- IPython\n", " - history\n", " - tab-complete\n", " - ...\n", "- Jupyter/IPython notebooks\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Hello World!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [], "source": [ "print('Hello World!')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Small example" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "for i in range(5):\n", " if i % 2 == 0:\n", " print(i, 'is even')\n", " else:\n", " print(i, 'is odd')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Whitespace controls scope!\n", "\n", "```python\n", "for i in range(5):\n", " if i % 2 == 0:\n", " print(i, 'is even')\n", " else:\n", " print(i, 'is odd')\n", "```\n", "\n", "- **Always** use **4 spaces** for indentation (check your editor settings)\n", "- Mixing tabs and spaces can lead to problems!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Data types\n", "\n", "Most simple data types are built in\n", "- integers\n", "- floats\n", "- strings (unicode)\n", "- booleans (`True` and `False`)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "x = 1\n", "y = 2.0\n", "s = \"Strings are unicode, so we can write in 日本語\"\n", "b = True\n", "\n", "z = int(y)\n", "z, type(z)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Operators\n", "- Like usual: +, -, *, %, /\n", "- Power: **" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "5 ** 2" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "### Logical operators\n", "- `and`, `or`, `not`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "5 > 3 and not 5 > 7" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Bitwise operators exist as well" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Range checks" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "x = 5\n", "3 < x < 7" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Container types\n", "\n", "- `list`\n", "- `tuple`\n", "- `dict`\n", "- `set`" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## `list`\n", "\n", "- Random access (0-indexed!)\n", "- Negative numbers count backwards" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "a = [1, 2, 3, 4]\n", "print(a[0], a[3], a[-1])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- Items can be added or removed" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "a.append(100)\n", "a.remove(2)\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "- Mix *item types* freely!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "b = [1, 2.0, 'banana', [30, 40]]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- Check if item is in the list using `in`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "'banana' in b" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## `tuple`\n", "\n", "- A \"frozen\" list: No `append`, `remove` or altering values\n", "- Hashable (unlike `list`)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "a = [1, 2, 3, 4]\n", "t = (1, 2, 3, 4) # tuple\n", "a[2] = 88 # OK\n", "\n", "t[2] = 88" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Iterating over things (naive way)\n", "\n", "By using \n", "- `len(seq)` - number of items in `seq`\n", "- `range(N)` - generate sequence of integers in half-open interval `[0, N)`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fruits = ['apple', 'banana', 'kiwi']\n", "for i in range(len(fruits)):\n", " print(fruits[i])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "### Please avoid this!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Iterating over things (better way!)\n", "We use `for item in sequence` to grab items from sequences like `list` or `tuple`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fruits = ['apple', 'banana', 'kiwi']\n", "for fruit in fruits:\n", " print(fruit)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Slicing\n", "\n", "`seq[a:b]` gives the part of the sequence in the *half-open* range `[a, b)`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "fruits = ['oranges', 'apple', 'banana', 'kiwi', 'raspberry']" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "fruits[:2]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "fruits[2:]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "fruits[-3:]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We can also specify the step length (which can be negative!)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fruits[1::2]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "fruits[-1::-2]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Sequence unpacking\n", "\n", "Any sequence can be unpacked into separate variables" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "person = ('Hannes', 31, 'CVL')\n", "name, age, workplace = person\n", "print(name, 'is', age, 'years old and works at', workplace)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We can also just get some of the values" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "name, _, workplace = person\n", "print(name, workplace)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "name, *rest = person\n", "print(name, rest)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Unpacking in loops" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "eating_habits = [('monkey', 'bananas'), \n", " ('horse', 'grass'), \n", " ('human', 'hamburgers')]\n", "\n", "for animal, food in eating_habits:\n", " print('The', animal, 'eats', food)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "This is equivalent to the less pretty" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "for item in eating_habits:\n", " print('The', item[0], 'eats', item[1])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## `set`\n", "- Accepts mixtures of any kind of *hashable* object\n", "- Is **unordered**" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "things = {5, 2, 1, 1, 1, 1, 'monkey', (1, 3)}\n", "print(things)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- Check for set membership using `in`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "5 in things" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We can add and remove things from sets" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "things.add(7)\n", "things.remove('monkey')\n", "things" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "- Set operations like intersection, union, etc. all exist" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "A = {1, 2, 3, 4, 5}\n", "B = {1, 4, 10, 20}\n", "print('Intersection:', A.intersection(B))\n", "print('Union:', A.union(B))\n", "print('Difference:', A - B)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Only *hashable types* work. E.g. not `list` objects" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "A.add([1, 2])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Key-value map: `dict`\n", "- Access items by **key**\n", "- Key can be any hashable object (i.e. `tuple` is ok, but not `list`!)\n", "- Keys in the same dict can have different types" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "country_area = {\n", " 'Sweden' : 449964,\n", " 'Italy' : 301338, }\n", "print('The area of Sweden is', country_area['Sweden'], 'km²')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "New values/keys can be inserted after creation" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "country_area['Germany'] = 357168\n", "print(country_area)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "- Extract keys and values using methods `dict.keys()` and `dict.values()`\n", "- Note that `dict` is an *unordered* container" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "print(country_area.keys())\n", "print(country_area.values())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Check for key existance with `in`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "'Sweden' in country_area" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Get key-value pairs using `dict.items()`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "for country, area in country_area.items():\n", " print('The area of', country, 'is', area, 'km²')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## `dict` as ad-hoc \"classes\" for structured data" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "movies = [\n", " {'name' : 'Star Wars',\n", " 'year' : 1977,\n", " 'actors' : ['Mark Hamill', 'Harrison Ford']},\n", " \n", " {'name' : 'Alien',\n", " 'year' : 1979,\n", " 'actors' : ['Sigourney Weaver',]}\n", "]\n", "\n", "for movie in movies:\n", " print(movie['name'], 'was released in', movie['year'])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Functions" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def square(x):\n", " return x ** 2\n", "\n", "square(4)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Functions are like any object, and can be used as input to other functions" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def apply_func(func, x):\n", " return func(x)\n", "\n", "f = square\n", "apply_func(f, 3)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "A function can return multiple values" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def square_and_cube(x):\n", " return x ** 2, x ** 3\n", "\n", "square, cube = square_and_cube(4)\n", "print(square, cube)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "This is just creating and unpacking a tuple!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "y = square_and_cube(5)\n", "print(y, type(y))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Function arguments\n", "- **keyword** arguments are optional arguments with a default value" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def greet(name, greeting='Hello'):\n", " print(greeting, name)\n", "\n", "greet('Hannes')\n", "greet('Hannes', greeting='Hi')\n", "greet('Hannes', 'Hi')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Variable number of arguments\n", "- For variable number of **positional** arguments\n", "- `args` will be a tuple of values" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def add(*args):\n", " result = 0\n", " for x in args: # Not *args!\n", " result += x\n", " return result\n", "\n", "add(1, 2, 5, 9)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "- Variable number of **keyword arguments** is also supported\n", "- `kwargs` will be a dictionary" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def print_thing_length(**kwargs):\n", " for name, length in kwargs.items(): # Not **kwargs\n", " print(name, 'is', length, 'tall')\n", "\n", "print_thing_length(hannes='182 cm', smurf='two apples')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "When is this useful?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Variable number of arguments (cont.)\n", "- Combining works as expected\n", "- Ordering of positional, keyword args, and their variable versions is important" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def sum_all_the_things(a, b, *args, foo=5, bar=10, **kwargs):\n", " result = a + b + foo + bar\n", " for x in args:\n", " result += x\n", " for x in kwargs.values():\n", " result += x\n", " return result\n", "\n", "sum_all_the_things(1, 0, 0, 0, 0, 0, monkey=100)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## String formatting using `%`\n", "- `printf`-like format specifiers: \n", " - %s\n", " - %d\n", " - %f\n", " - ..." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "'%s (%d) has an IMDB score of %.1f' % ('Alien', 1979, 8.5)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- Think of this as *deprecated*. Better ways exist!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## String formatting using `str.format()`\n", "- Very rich formatting language\n", "- Recommended way to format strings" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "'{movie} ({year}) has an IMDB score of {imdb:.2f}'.format(movie='Alien',\n", " year=1979, \n", " imdb=8.5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "'{} ({}) has an IMDB score of {:.1f}'.format('Alien', 1979, 8.5)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- Supports things like:\n", " - 0-padding numbers\n", " - float precision\n", " - left/right justification" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Mini-assignment\n", "\n", "Write a function that takes a list of movies and returns the name and score of the movie with the highest IMDB score.\n", "\n", "### Data\n", "http://users.isy.liu.se/cvl/hanov56/pycourse/" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "movies = [\n", " {\n", " 'name' : 'Star Wars',\n", " 'year' : 1977,\n", " 'imdb' : 8.7\n", " },\n", " \n", " {\n", " 'name' : 'Alien',\n", " 'year' : 1979,\n", " 'imdb' : 8.5\n", " },\n", " \n", " {\n", " 'name' : 'The Terminator',\n", " 'year' : 1984,\n", " 'imdb' : 8.1\n", " },\n", " \n", " {\n", " 'name' : 'House of the Dead',\n", " 'year' : 2002,\n", " 'imdb' : 2.0\n", " },\n", "] " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## My solution\n", "Batteries included!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "def best_movie(movielist):\n", " best = max(movielist, key=lambda movie: movie['imdb'])\n", " return best['name'], best['imdb']\n", "\n", "movie, score = best_movie(movies)\n", "print(\"The best movie is '{}' with a score of {:.1f}\".format(movie, score))" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "slideshow": { "slide_type": "slide" } }, "source": [ "## Classes" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from math import pi\n", "\n", "class Circle:\n", " name = 'Circle'\n", " def __init__(self, radius):\n", " self.radius = radius\n", " \n", " def area(self):\n", " return pi * self.radius ** 2\n", "\n", "c = Circle(2.0)\n", "print('A circle with radius {} has area {:.2f}'.format(c.radius,\n", " c.area()))\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- `__init__` is called when the object is initialized (a \"constructor\")\n", "- `self` $\\approx$ `this` but is **explicit**\n", "- class members can be declared outside of `__init__`, but don't!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Class inheritance\n", "- Simply list parent classes\n", "- `object` is the top level object (can be omitted like previous example)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "class Shape(object):\n", " def print_info(self):\n", " print('I am a {} with area {:.2f}'.format(self.shape_type,\n", " self.area()))\n", "\n", "class Circle(Shape):\n", " def __init__(self, radius):\n", " self.radius = radius\n", " self.shape_type = 'Circle'\n", " \n", " def area(self):\n", " return pi * self.radius ** 2\n", "\n", "c = Circle(2.0)\n", "c.print_info()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Where are my `public` and `private`??!\n", "\n", "- Nowhere: all attributes are \"public\"!\n", "- \"getters\" and \"setters\" are unneccessary (and *unpythonic*)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "### How about underscores?\n", "- `'_'` or `'__'` can be used to signal \"privateness\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "class A:\n", " def __init__(self):\n", " self._my_private = 10\n", "a = A()\n", "a._my_private # Hmm??" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "scrolled": true, "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "class A:\n", " def __init__(self):\n", " self.__really_private = 10\n", "\n", "a = A()\n", "a.__really_private" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "a._A__really_private" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We can **never make something private**. But we can give hints." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Calling parents methods: `super()`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "class CircleWithSquareHole(Circle):\n", " def __init__(self, radius, hole_side):\n", " super().__init__(radius) # calls Circle.__init__(self, radius)\n", " self.side = hole_side\n", " \n", " def area(self):\n", " circle_area = super().area() # calls Circle.area(self)\n", " return circle_area - self.side ** 2\n", " \n", "cwsh = CircleWithSquareHole(2, 1)\n", "cwsh.area()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Exceptions: handling errors\n", "\n", "- Python coding involves a lot of *exception handling*\n", "- `try` - `except` - `finally` blocks" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "try:\n", " y = 5 / 0\n", "except ZeroDivisionError:\n", " print('Oh no! Divide by zero!')\n", " y = 0\n", "finally:\n", " print('This always executes')\n", "print('y =', y)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Easier to ask forgiveness than to ask for permission\n", "Python prefers exception handling over condition checking\n", "\n", "#### Example: set value from dict, or to default value" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "DEFAULT_VALUE = 1\n", "d = {'a' : 10, 'b' : 20}\n", "\n", "if 'c' in d:\n", " x = 5\n", "else:\n", " x = DEFAULT_VALUE\n", "print(x)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" } }, "source": [ "is equivalent to" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "try:\n", " x = d['c']\n", "except KeyError:\n", " x = DEFAULT_VALUE\n", "print(x)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## File open example" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "try:\n", " f = open('/tmp/thisfilereallydoesnotexist', 'r')\n", " data = f.read()\n", "except IOError:\n", " print('Failed to open and read data from file')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Compare to these pre-checks\n", "- Does the file exist?\n", "- Do I have the right permissions?\n", "- Is there some other error?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Exceptions (cont.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Catch multiple exceptions\n", "\n", "```python\n", "try:\n", " x = some_calculation()\n", "except (ZeroDivisionError, ValueError):\n", " x = 0\n", "```\n", "\n", "Catch everything (**avoid if possible**). Why?\n", "\n", "```python\n", "try:\n", " x = some_calculation()\n", "except:\n", " x = 0\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## `lambda` functions\n", "\n", "Short *single statement* anonymous functions" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "add = lambda a, b: a + b\n", "add(3, 4)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "### Example: sort by norm" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "alist = [(1, 2), (2,0), (0, 10)]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "sorted(alist, key=lambda x: x[0] ** 2 + x[1] ** 2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## List-comprehensions" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "squares = [x ** 2 for x in range(10)]\n", "print(squares)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "vehicles = [('SAAB 9-5', 'car'),\n", " ('Titanic', 'boat'),\n", " ('Tesla model S', 'car'),\n", " ('Atlantis', 'spaceship')]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "cars = [name for name, vtype in vehicles if vtype == 'car']\n", "print(cars)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## List comprehensions (cont.)\n", "\n", "```python\n", "result = [expr(item) for item in sequence \n", " if condition(item)]\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Example: Loading images\n", "\n", "- Assume `files` is a list of filenames in a directory (not only images!)\n", "- The image files all start with `image_` (e.g. `image_000.png`)\n", "- We want to convert the images to grayscale\n", "\n", "\n", "```python\n", "images = [cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\n", " for image in \n", " [cv2.imread(fn) for fn in files \n", " if fn.startswith('image_')\n", " ]\n", " ]\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Nesting too many can hurt readability!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## List comprehensions: `dict`\n", "We can do the same for `dict`s" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "square_lookup = {x : x ** 2 for x in range(10)}\n", "square_lookup[7]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Reading files\n", "- Use `open()` to create a `File` object.\n", "- Modes: r, w, a, rb, wb, ..." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "f = open('/etc/redhat-release', 'r') # Read-only\n", "data = f.read()\n", "print('File contents:')\n", "print(data)\n", "f.close()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## `File` objects\n", "- `read()`, `write()`\n", "- `readlines()`, `writelines()`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "f = open('/etc/passwd', 'r')\n", "lines = f.readlines()\n", "for l in lines[:3]:\n", " print(l)\n", "f.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Why the extra linebreaks?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Reading files (cont.)\n", "Forgot to call `f.close()`?\n", "\n", "Either never create the `File` object `f` at all" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "data = open('/etc/redhat-release', 'r').read()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "or use a *context manager*, using `with`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "with open('/etc/redhat-release', 'r') as f:\n", " data = f.read()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The file is automatically closed after the `with` finishes" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## String manipulation\n", "Some useful string methods\n", "- `.split()`\n", "- `.strip()`\n", "- `.lower()` / `.upper()`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "s = 'The quick brown fox jumps over the lazy dog'\n", "words = s.split()\n", "words[3]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "s.upper()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "' extra whitespace '.strip()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## From list to string\n", "A list of strings can be turned to a string with `str.join()`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "print('My favourite fruits are', ', '.join(fruits[:3]))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Python modules and packages\n", "- *package* is a collection of *modules*\n", "- modules are used via `import`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import time\n", "print(time)\n", "print('Current POSIX time:', time.time())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We can also import only specific names from a module using `from ... import ...`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from calendar import isleap, leapdays\n", "isleap(1984)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Assignment: \n", "## IMDB movie ratings\n", "\n", "See assignment web page for details" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## Some useful things\n", "\n", "- `help(obj)` launches a help section for some object \"obj\", which can be an object instance, a class, a module, function, ...\n", "- `dir(obj)` lists all attributes of an object\n", "- `repr(obj)` returns the represenation string for an object" ] } ], "metadata": { "celltoolbar": "Slideshow", "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.5.0" } }, "nbformat": 4, "nbformat_minor": 0 }