{ "cells": [ { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "## Error Handling / Exceptions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In Python errors are managed with a special language construct called \"Exceptions\". When errors occur exceptions can be raised, which interrupts the normal program flow and fallback to somewhere else in the code where the closest try-except statement is defined." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Handling bad user input\n", "\n", "The following code crashes when the user does not input a number:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With ``try except`` the code can gracefully handle the problem and prompt the user again.\n", "\n", "The syntax for these statements is:\n", "\n", "```python\n", "try:\n", " # normal code goes here\n", "except:\n", " # code for error handling goes here\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Functional programming\n", "\n", "There are two ways of doing programming: Imperative and functional.\n", "\n", "Imperative means that you have a code-flow where you write conditions, loops and invoke functions. This is what we did by now. Many operations, especially in context of mathematics, are nicer to implement when using a functional approach.\n", "\n", "In functional programming you transform the input instead with suitable operations and continue with the out. It is like writing a pipeline.\n", "\n", "Python is a multi-paradigm language, this means you can use both approaches in Python.\n", "\n", "Today we will focus on functional programming. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Imperative: Operations on lists using ``for`` loops (Revision)\n", "\n", "Typical operations on lists are:\n", "\n", "* Transforming list elements\n", "* Filtering list elements\n", "\n", "This is possible, for example, with a ``for`` loop. However, using a ``for`` loop for this is not typical in Python. We will look at how to do it in a better way later." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example (Function ``count_num``)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def count_num(lst, num):\n", " \"\"\"\n", " Counts how often num is in lst\n", " \"\"\"\n", " count = 0\n", " for x in lst:\n", " if x == num:\n", " # Equal to count = count + 1\n", " count += 1\n", " # count++ unavailable in Python\n", " return count\n", "\n", "count_num([1, 1, 3, 2], 1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "[1, 1, 3, 2].count(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example (Function ``count_even``)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def is_even(x):\n", " return x % 2 == 0\n", "\n", "def count_even(lst):\n", " \"\"\"\n", " Counts how many elements are even\n", " \"\"\"\n", " count = 0\n", " for x in lst:\n", " if is_even(x):\n", " count += 1\n", " return count\n", "\n", "count_even([2, 3, 4, 5])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example (Function ``inc_one``)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def inc_one(lst):\n", " \"\"\"\n", " Increments all list element by 1\n", " \"\"\"\n", " for i in range(len(lst)):\n", " lst[i] += 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Function calling:\n", "- \"Primitive\" types are passed by value (copied). numbers and strings\n", "- Objects are passed by reference (list, Fraction, Decimal)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ll = [1, 5, 10]\n", "\n", "inc_one(ll)\n", "\n", "print(ll)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Functional programming" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Lambda functions\n", "\n", "Lambda functions are \"anonymous functions\", i.e. functions without a function name. The term lambda has historical reasons: Lambda functions were first used in computer science in the so-called lambda calculus.\n", "\n", "In Python, ``lambda`` corresponds to a function that can contain one statement and the return is implicit." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example (Function ``add``)\n", "\n", "The function ``add`` accepts two arguments and returns there sum.\n", "\n", "Shown are a function and a lambda function. Both are equivalent." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Though this is not really useful. They really shine when using them with functions such as ``map``, ``filter`` and ``reduce``." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Transforming lists in a pythonic way\n", "\n", "The common ways to operate on lists in Python are:\n", "\n", "* List Comprehensions\n", "* Function ``map``\n", "* Function ``filter``\n", "\n", "List Comprehensions are directly evaluated. No call to ``list`` is necessary.\n", "\n", "``map`` and ``filter`` however return a generator which can only be used in a loop (or evaluation into a list with ``list()``)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Comprehensions and ``map``\n", "\n", "``map`` accepts two arguments:\n", "\n", "* A (lambda) function which accepts one parameter: The particular list element is passed here.\n", "* The list (and of course generators etc.).\n", "\n", "The function returns the new list." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lst = [\"Hello\", \"Python\", \"World\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Equivalent to this are List Comprehensions. The inventor of Python finds this the correct way to work with lists.\n", "\n", "It was planned to remove the ``map`` function (and also ``filter``) from Python but there was too much protest from other developers.\n", "\n", "The syntax is:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[ Output expression  for item in list ]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Filtering lists with comprehensions and ``filter``\n", "\n", "``filter`` accepts two arguments:\n", "\n", "* A (lambda) function which accepts one parameter: The respective list element is passed here.\n", "* The list (and of course generators etc.).\n", "\n", "If the lambda function returns a truth value (``True``), the element is part of the new list, otherwise it is removed.\n", "\n", "But first how to filter lists with ``for`` and ``if``. This is rather cumbersome (imperative approach):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def is_even(x):\n", " return x % 2 == 0\n", "\n", "nums = range(10)\n", "even_nums = []\n", "\n", "for x in nums:\n", " if is_even(x):\n", " even_nums.append(x)\n", "\n", "nums = even_nums\n", "print(nums)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Much more elegant is the ``filter``:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "numbers = range(10)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or the pythonic way: An ``if`` statement in a list comprehension." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[ Output expression  for item in list  if condition ]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "numbers = range(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Bonus: The filtering comprehension can be transformed directly. This is not possible with ``filter`` directly. A call to ``map`` is required afterwards." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### More useful built-in functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### ``any`` and ``all``\n", "\n", "These two functions are only useful in combination with a comprehensions that yields bools (``True`` and ``False``)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "``any`` returns true when _any_ element in an iterable is true." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "numbers = range(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "``all`` returns true when _any_ element in an iterable is true." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "numbers = range(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### ``max`` and ``min``\n", "\n", "These two functions return the largest or the smallest element in an iterable (an iterable is something that is usable in a for-loop)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "min([1, 4, 3, -10, 0])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "max([1, 4, 3, -10, 0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The function ``zip``\n", "\n", "``zip(list1, list2, ..., list_n)`` returns a new _generator_ consisting of the 1st element of each list, then the 2nd element of each list, and so on." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "numbers = [1, 2, 3]\n", "letters = [\"a\", \"b\", \"c\"]\n", "text = [\"The\", \"function\", \"zip\"]\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can use it to do vector operations." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = [1, 2, 3]\n", "b = [4, 5, 6]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The function ``functools.reduce``\n", "\n", "``reduce`` reduces the values in a list to a single value by consecutively applying the same operator to all values.\n", "\n", "$$((((x_1 \\circ x_2) \\circ x_3) \\circ x_4) \\ldots ) $$\n", "\n", "Imperative:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lst = [1, 2, 3, 4, 5]\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Functional:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lst = [1, 2, 3, 4, 5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the case of addition this is equal to sum." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Dot product\n", "\n", "By combining ``zip`` and ``sum`` you can e.g. calculate the _dot product_ of two vectors." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$$ \\vec{a} \\circ \\vec{b} = \\begin{pmatrix} a_1 \\\\ a_2 \\\\ a_3 \\end{pmatrix} \\circ \\begin{pmatrix} b_1 \\\\ b_2 \\\\ b_3 \\end{pmatrix} = a_1 \\cdot b_1 + a_2 \\cdot b_2 + a_3 \\cdot b_3 $$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = [4, 5, -3]\n", "b = [-2, 2, -2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Imperative:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Functional:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Itertools\n", "\n", "The module ``itertools`` has many useful functions when you want to operate on iterators.\n", "\n", "https://docs.python.org/3/library/itertools.html\n", "\n", "For illustrative purposes I will use the functions ``accumulate``, ``product`` and ``permutations``.\n", "\n", "``accumulate`` is like ``reduce`` but it also returns the intermediate values." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from itertools import accumulate\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "``product`` calculates the cartesian product.\n", "\n", "$$A \\times B:= \\left\\{ (a, b) \\mid a \\in A, b \\in B \\right\\}$$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from itertools import product\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "``permutations`` returns all permutations (without repetition)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from itertools import permutations\n", "\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.9.3" } }, "nbformat": 4, "nbformat_minor": 4 }