Skip to content
Snippets Groups Projects
lecture.ipynb 15.3 KiB
Newer Older
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Agenda\n",
    "\n",
    "* Adding structure to Python code\n",
    "* Functions\n",
    "* Namespaces\n",
    "* Modules"
   ]
  },
nyfelix's avatar
nyfelix committed
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Code Structure"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Adding structure to Python code\n",
    "\n",
    "* There are many good reasons why we want to organize our code and add structure to it\n",
    "  * Reuse : We don't want to do things twice\n",
    "  * Readability : structured code can be read like a language\n",
    "  * Maintainability : If we don't have a good structure in code, we can spend a lot time with searching\n",
    "* In Python we have different concepts to give structure to our code:\n",
    "  * Functions\n",
    "  * Namespaces\n",
    "  * Modules\n",
    "  * Classes (we will come back to this great concept at the end of this course)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Functions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Usage of Functions\n",
    "\n",
Felix Nyffenegger's avatar
Felix Nyffenegger committed
    "* Functions allow us to define a block of code that can be called from anywhere\n",
    "* Functions accept *parameters* (arguments) as input into the code block\n",
    "* Optionally, functions can *return* a value\n",
    "* As soon as you repeat the same or similar sequence of code, consider writing a function\n",
    "* Functions are called with the function name, followed by ()\n",
    "  * If the function accepts parameters, they are listed inside (), separated with comma\n",
Felix Nyffenegger's avatar
Felix Nyffenegger committed
    "  * If the function returns a value, it can be assigned to a variable\n",
    "\n",
    "  \n",
    "Here is an example:"
   ]
  },
  {
   "cell_type": "code",
Felix Nyffenegger's avatar
Felix Nyffenegger committed
   "execution_count": 1,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n"
     ]
    }
   ],
   "source": [
    "my_number = max(3, 4, 2) # calling the function with 3 arguments and assigning the result to a variable\n",
    "print(my_number)         # also print is a function"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Definition of Functions\n",
    "\n",
Felix Nyffenegger's avatar
Felix Nyffenegger committed
    "* To define a function, we use the `def`keyord, followed by the function name\n",
    "* After the function name we declare in () which parameters are allowed\n",
Felix Nyffenegger's avatar
Felix Nyffenegger committed
    "* If we want to return a value, we can do this anywhere with the `return` statement, followed by the return value(s)"
   ]
  },
  {
   "cell_type": "code",
Felix Nyffenegger's avatar
Felix Nyffenegger committed
   "execution_count": 2,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n"
     ]
    }
   ],
   "source": [
Felix Nyffenegger's avatar
Felix Nyffenegger committed
    "# Define a function that takes two arguments and returns the bigger one\n",
    "def bigger_of_two(a, b):\n",
    "    if a > b:\n",
    "        return a\n",
    "    else:\n",
    "       return b\n",
Felix Nyffenegger's avatar
Felix Nyffenegger committed
    "\n",
    "# Call the function with two arguments and print the result\n",
    "print(bigger_of_two(4, 3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
Felix Nyffenegger's avatar
Felix Nyffenegger committed
    "## Scope of Variables\n",
    "\n",
Felix Nyffenegger's avatar
Felix Nyffenegger committed
    "* Variables that are first used in a function are only known inside this function\n",
    "* However functions can access variables of the outer scope (e.g. global variables)\n",
    "* Variables in the most outer scope are called \"global variables\"\n",
    "* Variables in a closed inner scope are called \"local variables\""
   ]
  },
  {
   "cell_type": "code",
Felix Nyffenegger's avatar
Felix Nyffenegger committed
   "execution_count": 3,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
Felix Nyffenegger's avatar
Felix Nyffenegger committed
      "Value from outer scope: 8\n",
      "Value from same scope: 3\n"
     ]
    },
    {
     "ename": "NameError",
     "evalue": "name 'y' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[3], line 8\u001b[0m\n\u001b[1;32m      5\u001b[0m     \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mValue from same scope:\u001b[39m\u001b[38;5;124m\"\u001b[39m, y) \u001b[38;5;66;03m# y is not accessible from the outer scope\u001b[39;00m\n\u001b[1;32m      7\u001b[0m some_function()\n\u001b[0;32m----> 8\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mValue from inner scope:\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[43my\u001b[49m)\n",
      "\u001b[0;31mNameError\u001b[0m: name 'y' is not defined"
Felix Nyffenegger's avatar
Felix Nyffenegger committed
   "source": [
    "x = 8\n",
    "def some_function():\n",
    "    print(\"Value from outer scope:\", x) # x is accessible from the inner scope\n",
    "    y = 3\n",
    "    print(\"Value from same scope:\", y) # y is not accessible from the outer scope\n",
    "\n",
    "some_function()ß\n",
    "print(\"Value from inner scope:\", y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Assigning multiple values\n",
    "\n",
    "* in Python we can assign multiple values to multiple variables in one line\n",
    "* Accordingly, we can write functions that return multiple values, which can be very handy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "def get_min_max(list):\n",
    "    minimum = min(list)\n",
    "    maximum = max(list)\n",
    "    return minimum, maximum # returning multiple values\n",
    "\n",
    "list_min, list_max = get_min_max([1, 2, 3, 4, 5]) # multiple assignment (first value goes to a, second to b)\n",
    "\n",
    "print(list_min)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## More About Funtions in Python\n",
    "\n",
    "* Default Parameter Value : You can define default values, in case the function is called without parameter"
   ]
  },
  {
   "cell_type": "code",
Felix Nyffenegger's avatar
Felix Nyffenegger committed
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
Felix Nyffenegger's avatar
Felix Nyffenegger committed
   "outputs": [],
   "source": [
    "def default_argument(a, b, c=3): # default value for c\n",
    "    return a + b + c\n",
    "print(default_argument(1, 2)) # c will be 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "* Arbitrary Arguments, *args : If you do not know how many arguments that will be passed into your function, add a * before the argument name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "def arbitrary_argument(*args): # variable number of arguments\n",
    "    sum = 0\n",
    "    for a in args:\n",
    "        sum += a\n",
    "    return sum\n",
    "\n",
    "print(arbitrary_argument(1, 2, 4, 6))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "* There is more we can do with functions, but this is a good start."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
Felix Nyffenegger's avatar
Felix Nyffenegger committed
    "# Modules"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
Felix Nyffenegger's avatar
Felix Nyffenegger committed
    "## Using Modules I\n",
    "\n",
    "* One of the biggest advantages of Python is the incredible number of modules that are available\n",
    "* Modules are pieces of code that exist somewhere else (typically in another file)\n",
    "* Modules can be imported with the `` import module_name `` statement\n",
    "* The module name can be any installed python module, \n",
    "* or the name of file somewhere in your project (name without the '.py' ending)\n",
    "* Functions of a module are accessible with the module name and the `` . `` operator"
Felix Nyffenegger's avatar
Felix Nyffenegger committed
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
Felix Nyffenegger's avatar
Felix Nyffenegger committed
    "import math # importing a module\n",
    "\n",
    "math.sqrt(16) # using a function from the module"
   ]
  },
  {
   "cell_type": "markdown",
Felix Nyffenegger's avatar
Felix Nyffenegger committed
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
Felix Nyffenegger's avatar
Felix Nyffenegger committed
    "## Using Modules II\n",
    "\n",
Felix Nyffenegger's avatar
Felix Nyffenegger committed
    "* If a module can be organized in submodules by placing them in a folder or subfolder of your project\n",
    "* The module name will then be `` module.submodule `` (according to the fodler structure)\n",
    "* To access a function you will have to write something like `` module.submodule.function() ``\n",
    "* In this case we want to create a shortcut.\n",
    "* In Python this can be done with as `` as `` order: ``import folder.module as mod ``"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
Felix Nyffenegger's avatar
Felix Nyffenegger committed
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
Felix Nyffenegger's avatar
Felix Nyffenegger committed
   "source": [
    "import pandas.plotting as pdp # importing a submodule\n",
    "\n",
    "pdp.lag_plot() # using a function from the submodule"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Installing Modules\n",
    "\n",
    "* As mentioned earlier, Python has a vast variety of modules (currently about 570k registered packages)\n",
    "* You can find the official registry here: https://pypi.org/\n",
    "* Luckily we don't have to search and copy them from the internet\n",
    "* Python has package management tool, called pip that helps us to install modules\n",
    "\n",
    "```\n",
    "pip install <module name>\n",
    "pip install pandas \n",
    "```\n",
    "\n",
    "if you have several Python versions you may have to use the specifice pip command\n",
    "\n",
    "```\n",
    "pip3 install <module name>\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Crating a Module\n",
    "\n",
    "* At some point your code will get bigger\n",
    "* And also you might want to reuse your own code in other projects\n",
    "* In this case it is a good idea to start organizing your code in modules\n",
    "* Creating a modules is as easy as creating a new .py file \n",
    "* Let's code a simple example."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Namespaces"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Namespace Rules\n",
    "\n",
    "<img style=\"float: right; padding-right: 50pt;\" src=\"https://files.realpython.com/media/t.fd7bd78bbb47.png\" width=\"300pt\">\n",
    "\n",
    "* Now that we know functions and modules, it's time to have a closer look at namespaces\n",
    "* A namespaces the scope in which a name (variable, function, class, ...) is valid\n",
    "* Names must be unique in their namespaces\n",
    "* Python knows3 types of namespaces with the following rules:\n",
    "  1. Local: If you refer to x inside a function, then the interpreter first searches for it in the innermost scope that’s local to that function.\n",
    "  2. Enclosing: If x isn’t in the local scope but appears in a function that resides inside another function, then the interpreter searches in the enclosing function’s scope.\n",
    "  3. Global: If neither of the above searches is fruitful, then the interpreter looks in the global scope next.\n",
    "  4. Built-in: If it can’t find x anywhere else, then the interpreter tries the built-in scope."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Working with Namespaces\n",
    "\n",
    "* In Python functions, modules (and classes) act as enclosing and local namespaces\n",
    "* You might have realized: modules automatically act as a namespace\n",
    "* Their structure determine the scope of names\n",
    "* Considering memory: \n",
    "  * Global variables remain in the RAM all time\n",
    "  * Local variables only use memory while the object defining the namespace exists"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9\n",
      "1\n",
      "2\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "x = 1\n",
    "def namespaces():\n",
    "    def subspaces():\n",
    "        z = 3\n",
    "        print(pow(3,2)) # access namespaces from the built-in scope\n",
    "        print(x) # access x from the global scope\n",
    "        print(y) # access y from the enclosing scope\n",
    "        print(z) # access z from the local scope\n",
    "\n",
    "    y = 2\n",
    "    subspaces()\n",
    "    print(y) # access y from the local scope\n",
    "    print(z) # z is not accessible from the outer scope (NameError)\n",
    "\n",
    "namespaces()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## For the Geeks\n",
    "\n",
    "* Careful about redeclaration!\n",
    "* While an enclosing variable x can be read in an inner namespaces, a new variable will be created at the moment you assign a value to this variable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "def namespaces():\n",
    "    def subspaces():\n",
    "        x = 2 # x is now a local variable\n",
    "        print(x)\n",
    "\n",
    "    x = 1 # x is a local variable of namespaces\n",
    "    subspaces()\n",
    "    print(x)\n",
    "\n",
    "namespaces()"
   ]
  }
 ],
 "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",
Felix Nyffenegger's avatar
Felix Nyffenegger committed
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}