{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Konzept 3: Funktionen\n", "\n", "Der Grundmechanismus eines jeden imperativen Programmes ist es,\n", "den \"State\" sukkzesive zu verändertn.\n", "Treten hierbei gewissen immer wieder vorkommende Transformationen auf,\n", "so ist es geschickt diese als einzelne Bausteine zu sehen.\n", "\n", "Eine **Funktion** hat hierbei den Sinn, einen Block von Anweisungen auf Abruf verfügbar zu haben.\n", "Es können Objekte als Argumente übergeben werden und ein oder mehrere Objekte als Ausgabe zurückgegeben werden.\n", "Funktionen werden durch nach dem Variablennamen nachgestellte geschwungene Klammern \"`(...)`\" aufgerufen.\n", "Dabei ist zu beachten, dass Funktionen auch auf den globalen Scope zugreifen können!\n", "\n", "Beispiel: `math.sqrt(2)` berechnet die Quadratwurzel aus 2.\n", "\n", "In den Klammern stehen die sogenannten \"Argumente\" dieser Funktion,\n", "welche für die Auswertung übergeben werden -- werden keine Argumente übergeben, so bleiben die Klammern leer.\n", "Zurückgegeben wird das Ergebnis nach Ausführung des Codes in der Funktion." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Definiert werden Funktionen mittels\n", "\n", " def name(argument1, argument2, ...):\n", " \n", "und\n", "\n", " return ...\n", " \n", "gibt an, was zurückgegeben wird:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def meine_funktion(x, b):\n", " y = x + b\n", " z = 2*y + x\n", " return z * y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Die Variable `meine_funktion` beinhaltet das Funktionsobjekt, wobei die Hexadezimalzahl die (wenig informative) Speichadresse ist:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "print(meine_funktion)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nebenbemerkung: Hier wird direkt das Funktionen-Objekt referenziert, welches sich genauso wie jedes andere durch eine Variable referenzierbares Objekt verhält. Insbesondere kann es Teil größerer Datenstrukturen sein oder an andere Funktionen übergeben werden. Daher hat Python auch Aspekte einer funktionale Programmiersprache." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Aufruf einer Funktion mittels Argumenten in runder Klammer:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "542.08" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "meine_funktion(4.4, 11)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "meine_funktion(-1, 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Werden Variablen als Argumente an die Funktion übergeben,\n", "wird das Objekt auf das sie Verweisen übergeben -- das hat nichts mit dem Variablennamen zu tun.\n", "Sprich, `y` ist nun innerhalb der Funktion das `x` und `paul` wird zum `y`.\n", "\n", "Beispiel:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "14" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y = 3\n", "paul = -1\n", "meine_funktion(y, paul)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Eine weitere Art eine Funktion zu definieren ist ein \"Lambda Ausdruck\".\n", "Dies ist ein Einzeiler und erspart eine \"ganze\" Funktion schreiben zu müssen.\n", "Häufig werden diese Lambdaausdrücke an Funktion übergeben.\n", "\n", "Beispiel:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [], "source": [ "f2 = lambda k : k**2 + 5" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f2(2)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "105" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f2(-10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Zwischenbemerkung:**\n", "\n", "Ganz allemein gilt für Python,\n", "dass jedes `Objekt`, welches aufgerufen werden kann,\n", "durch die an den Variablennamen nachgestellten geschwungenen Klammern \"`(...)`\" aufgerufen wird.\n", "Der Überbegriff all dieser Objekte ist \"aufrufbar\" (engl. \"**callable**\"), und solche Funktionen sind prominente Vertreter davon. Später mehr ;-)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Die **Rückgabe** einer Funktion kann auch **mehrstellig** sein.\n", "Dies wird dann verwendet, um die Ergebnisse mehr als nur einer Berechnung zurückzugeben." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def mehrstellig(x):\n", " k = 2 * x - 1\n", " l = 90 - x\n", " return k, l" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(7, 86)" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mehrstellig(4)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "19\n", "80\n" ] } ], "source": [ "a, b = mehrstellig(10)\n", "print(a)\n", "print(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Bem.: Die Variablen k und l innerhalb der Funktion werden a und b außerhalb der Funktion zugewiesen." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Aufrufsyntax (call syntax)\n", "\n", "Im Detail gibt es verschiedene Arten wie diese aufrufbaren Objekte (Funktionen, ...) aufgerufen werden können.\n", "Dabei unterscheidet man \n", "\n", "* **positionsabhängige Argumente**: die Übergabe an die Funktion erfolgt anhand der Position, und\n", "* **Schlüsselwortargumente**: die Variablen in der Funktionsdefinition werden explizite Werte übergeben.\n", "\n", "Des weiteren gibt es optional Werte für Schlüsselwortargumente,\n", "die einen Standardwert für das jeweilige Argument (engl. \"default value\") vorgeben.\n", "Dieser wird dann angenommen, wenn beim Aufruf dieses Argument nicht übergeben wird.\n", "\n", "Im folgenden Beispiel wird eine Funktion mit den Argumenten \"x\", \"y\", \"name\" und \"color\" defininiert\n", "und anschließend auf unterschiedliche Arten aufgerufen." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def func(x, y, name, color=\"red\"):\n", " print(\"%s's position is %d.%d with color %s\" % (name, x, y, color))" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "julia's position is 9.0 with color pink\n" ] } ], "source": [ "# 4-tes Argument ist die Farbe (position)\n", "func(9, 0, \"julia\", \"pink\")" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "joe's position is 4.5 with color red\n" ] } ], "source": [ "# default color = red\n", "func(4, 5, \"joe\")" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "jane's position is 1.7 with color yellow\n" ] } ], "source": [ "func(1, 7, \"jane\", color=\"yellow\")" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "jim's position is 3.11 with color grey\n" ] } ], "source": [ "# gemischte Reihenfolge\n", "func(y = 11, color=\"grey\", x = 3, name=\"jim\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Indirekte Wertübergabe\n", "\n", "Darüber hinaus gibt es die Möglichkeit, die Argumente vorher in einer Liste oder Map abzuspeichern.\n", "Diese Objekte werden erst später im Kapitel über Datenstrukturen behandelt,\n", "werden aber zur Vollständigkeit hier erwähnt.\n", "\n", "Es werden Variablen definiert, die die Werte für den Funktionsaufruf beinhalten.\n", "Dann gibt der Stern \"`*`\" bzw. Doppelstern \"`**`\" an,\n", "die Werte der jeweiligen Variablen als Argumente im Funktionsaufruf einzubauen.\n", "Der einfache Stern steht für Positionsargumente (Listen) und der Doppelstern für Schlüsselwörter." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "jack's position is 5.9 with color red\n" ] } ], "source": [ "argumentliste = [5, 9, \"jack\"]\n", "func(*argumentliste)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "jenny's position is 9.2 with color black\n" ] } ], "source": [ "schluesselwoerter = {\"name\" : \"jenny\", \"color\" : \"black\" }\n", "func(9, 2, **schluesselwoerter)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**ACHTUNG:** es muss alles eindeutig bleiben" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "ename": "TypeError", "evalue": "func() got multiple values for argument 'name'", "output_type": "error", "traceback": [ "\u001b[1;31m\u001b[0m", "\u001b[1;31mTypeError\u001b[0mTraceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mfunc\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margumentliste\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mschluesselwoerter\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mTypeError\u001b[0m: func() got multiple values for argument 'name'" ] } ], "source": [ "func(*argumentliste, **schluesselwoerter)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "jenny's position is 5.9 with color black\n" ] } ], "source": [ "# KORREKTUR: weglassen des letzten Arguments in der liste \"argumentliste\"\n", "func(*argumentliste[:-1], **schluesselwoerter)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Diese Varianten des Funktionsaufrufs mögen eventuell etwas verwirren,\n", "sind jedoch dann sehr nützlich, wenn Argumente von Funktionen weitergereicht oder (leicht abgewandelt) wiederverwendet werden." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Bonus: Verschachtelte Funktionen\n", "\n", "Funktionen können an Funktionen übergeben werden." ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def f_inner(x):\n", " k = 2 * x\n", " return k + 1\n", "\n", "def f_outer(func, v):\n", " p = func(v + 1) - v\n", " return p - 5" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "8" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f_outer(f_inner, 10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Bonus: Decorator\n", "\n", "Ein *Decorator* ist eine Funktion, die eine Funktion auf eine Funktion abbildet.\n", "Er wird verwendet, um das Verhalten mehrerer Funktionen uniform zu beeinflussen\n", "indem er auf diese Funktionen angewendet wird.\n", "\n", "Folgendes Beispiel definiert einen Decorator,\n", "welcher neben dem Ergebnis der Funktion auch die Argumente und den Typ der Rückgabe ausgibt." ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def verbose(func):\n", " def inner(*args, **kwargs):\n", " print(\"args: %s\" % str(args))\n", " print(\"kwargs: %s\" % str(kwargs))\n", " result = func(*args, **kwargs)\n", " print(\"return: %s\" % type(result))\n", " return result\n", " return inner" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false }, "outputs": [], "source": [ "@verbose\n", "def f1(a, b):\n", " return a + b\n", "\n", "@verbose\n", "def f2(word):\n", " return word[::-1]" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "args: (5, 11)\n", "kwargs: {}\n", "return: \n", "16\n" ] } ], "source": [ "print(f1(5, 11))" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "args: ('hello',)\n", "kwargs: {}\n", "return: \n", "olleh\n" ] } ], "source": [ "print(f2(\"hello\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Functools/Itertools\n", "\n", "Die [Functools](https://docs.python.org/2/library/functools.html)\n", "([Py3 functools](https://docs.python.org/3/library/functools.html))\n", "und [Itertools](https://docs.python.org/2/library/itertools.html)\n", "([Py3 itertools](https://docs.python.org/3/library/itertools.html))\n", "Bibliotheken beinhaltet mehrere Funktionen,\n", "um mit Funktionen arbeiten zu können bzw.\n", "um Operationen höherer Ordnung auf Funktionen anwenden zu können.\n", "\n", "Praktisch erweisen sich hier auch all diejenigen Funktionen,\n", "welche helfen iterative Berechnungen durch Funktionsaufrufe erledigen zu können.\n", "Dies ist an die Konzepte aus der [funktionalen Programmierung](http://en.wikipedia.org/wiki/Functional_programming) angelehnt.\n", "Vertreter sind auch die Schlüsselwörter `filter`, `reduce` (bei Py3 in Itertools), `zip`, ..." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import itertools as it\n", "sumdivby7 = lambda x : sum(x) % 7 == 0\n", "f = filter(sumdivby7, zip(it.cycle([2, 3, 5, 7, 13, 17]), range(70)))\n", "f" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Seit Python 3 werden fast durchgängig \"Generatoren\" zurückgegeben.\n", "Diese haben den Vorteil, dass nicht die gesamte abzuarbeitende Liste (oder input-Generator) abgearbeitet wird,\n", "sondern nur jeweils das nächste Element.\n", "Das hält den Speicherverbrauch in grenzen und beschleunigt die Ausführung!\n", "\n", "Um dennoch einen Generator vollständig abzuarbeiten und als Liste vor sich zu haben,\n", "gibt es die eingebaute Funktion `list`:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[(5, 2),\n", " (17, 11),\n", " (2, 12),\n", " (7, 21),\n", " (13, 22),\n", " (3, 25),\n", " (5, 44),\n", " (17, 53),\n", " (2, 54),\n", " (7, 63),\n", " (13, 64),\n", " (3, 67)]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(f)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Anaconda (Python 3)", "language": "python", "name": "anaconda3" }, "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.2" } }, "nbformat": 4, "nbformat_minor": 0 }