{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Software Entwicklung \n",
    "\n",
    "## Kapitel 4: Funktionen\n",
    "\n",
    "Bislang wurden lediglich Operationen verwendet, die bereits im Sprachumfang von Python enthalten sind, wie \n",
    "z.B. Built-In Funktionen, Infix-Operatoren oder Funktionen eines gegebenen Datentyps in Dot-Notation. \n",
    "In diesem Kapitel wird vorgestellt, wie eigene Funktionen definiert und genutzt werden können."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### 4.1 Funktionsdefinition und -aufruf\n",
    "Die Definition einer Funktion wird eingeleitet durch das Schlüsselwort <code>def</code> gefolgt vom \n",
    "Namen der Funktion, einer Parameterliste und einem Doppelpunkt. Danach werden die Befehle der Funktion, \n",
    "auch *Funktionsrumpf* genannt, eingerückt angegeben."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "def name_der_funktion():\n",
    "    print(1)\n",
    "    print(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Allein durch die Definition der Funktion wird noch kein Code aus dem Funktionsrumpf ausgeführt. Dies geschieht \n",
    "erst, indem die Funktion aufgerufen wird. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "print(name_der_funktion())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "Man sieht in diesem Beispiel auch, dass die Zellen eines Jupyter-Notebooks nicht voneinander unabhängig sind,\n",
    "sondern sich einen Namensraum teilen. Die in der ersten Zelle definierte Funktion ist nach ihrer Ausführung \n",
    "anschließend in der zweiten Zelle bekannt. Das gilt für alle Vereinbarungen wie z.B. auch Variablen."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### 4.2 Rückgabewerte\n",
    "\n",
    "Wie schon früher einmal ausgeführt liefert jede Operation in Python einen Wert zurück. Bei der oben defnierten\n",
    "Funktion ist dies <code>None</code>, weil keine anderen Anweisungen gegeben wurden.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "print(name_der_funktion())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Soll die Funktion einen Rückgabewert besitzen, so ist dieser mit dem Schlüsselwort <code>return</code> \n",
    "anzugeben."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "def immer_drei():\n",
    "    return 3\n",
    "\n",
    "print(immer_drei())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Die Ausführung des Funktionsrumpfs wird mit einer <code>return</code>-Anweisung beendet. Sollte der Rumpf\n",
    "danach weitere Anweisungen beitzen, werden diese nicht ausgeführt."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "def immer_drei():\n",
    "    if 3 < 4:\n",
    "        return 3\n",
    "    if 4 < 3:\n",
    "        return \"Hallo\"\n",
    "    print(\"Noch in der Funktion\")\n",
    "\n",
    "print(immer_drei())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Anders als in anderen Programmiersprachen ist der Datentyp des Rückgabewertes in Python nicht \n",
    "festgelegt. Es kann also durchaus vorkommen, dass ein Kontrollflusszweig im Methodenrumpf einen\n",
    "*String* zurückgibt, ein anderer einen *Integer*-Wert und wieder ein anderer nichts bzw. <code>None</code>."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Natürlich sind auch komplexere Rückgabetypen wie Listen oder Tupel zulässig. Tupel sind eine verbreitete\n",
    "Möglichkeit, mehr als einen Wert zurückzugeben, was in anderen Programmiersprachen oft schwieriger \n",
    "zu realisieren ist."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "def immer_drei_ohne_fehler():\n",
    "    return (3, False)\n",
    "    \n",
    "    \n",
    "ergebnis, fehler = immer_drei_ohne_fehler()\n",
    "print(ergebnis)\n",
    "print(fehler)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### 4.3 Gültigkeitsbereich von Variablen\n",
    "\n",
    "Variablen \"entstehen\" in Python durch die Zuweisung eines Wertes. Findet diese Zuweisung \n",
    "in einer Funktion statt, so entsteht eine *lokale Variable*, die nur in dieser Funktion bekannt ist.\n",
    "Erfolgt die Zuweisung außerhalb einer Funktion, so ist es eine *globale Variable*, die in \n",
    "allen Funktionen der jeweiligen Programmdatei bekannt ist. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "def test_variablen():\n",
    "    lokale_varibale = 1\n",
    "    print(lokale_varibale)\n",
    "    print(globale_variable)\n",
    "\n",
    "globale_variable = 2\n",
    "test_variablen()\n",
    "print(globale_variable)\n",
    "print(lokale_varibale)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Wird in einer Funktion einer Variablen ein Wert zugewiesen, die bereits als globale Variable \n",
    "initialisiert ist, so entsteht eine zusätzliche lokale Variable, die die globale Variable verdeckt. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "def verdeckte_variablen():\n",
    "    a = 2\n",
    "    print(a)\n",
    "\n",
    "a = 1\n",
    "verdeckte_variablen()\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Eine Variable kann nicht \"verzögert\" zu einer lokalen Variable werden."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "def keine_verzoegerte_lokale_variablen():\n",
    "    print(b)\n",
    "    b = 2\n",
    "    print(b)\n",
    "\n",
    "b = 1\n",
    "keine_verzoegerte_lokale_variablen()\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Soll das Verdecken einer globalen Variable verhindert werden, d.h. die Zuweisung eines\n",
    "Wertes an eine globale Variable erlaubt werden, so muss diese Variable mit dem \n",
    "Schlüsselwort <code>global</code> ausgewiesen werden."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "def keine_verdeckte_variable():\n",
    "    global c\n",
    "    c = 2\n",
    "    print(c)\n",
    "\n",
    "c = 1\n",
    "keine_verdeckte_variable()\n",
    "print(c)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Sollte die mit <code>global</code> ausgewiesene Variable erstmals in der Funktion mit\n",
    "einem Wert versorgt werden, so wird sie als *globale Variable* angelegt."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "def keine_verdeckte_variable():\n",
    "    global d\n",
    "    d = 2\n",
    "    print(d)\n",
    "\n",
    "keine_verdeckte_variable()\n",
    "print(d)"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Slideshow",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
