{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# [CodingX] Lesson 04 - Function\n",
    "## by Kun-Ta Chuang\n",
    "\n",
    " Advanced Network Database Laboratory <br>\n",
    " Dept. of Computer Science and Information Engineering <br>\n",
    " National Cheng Kung University "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Function\n",
    "---\n",
    "1. **Function Basics**\n",
    "2. Scopes\n",
    "3. Arguments"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## 1.1.1 Coding Function: def Statements (1)\n",
    "* keyword: def\n",
    "* fucntion name, argument, return statement"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "![](https://i.imgur.com/cCia0rA.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello World\n"
     ]
    }
   ],
   "source": [
    "# example1\n",
    "def f():\n",
    "    # function body\n",
    "    print(\"Hello World\")\n",
    "\n",
    "f() # function call"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello World\n"
     ]
    }
   ],
   "source": [
    "# example2\n",
    "def f(n):\n",
    "    # function body\n",
    "    print(n)\n",
    "\n",
    "x = \"Hello World\"\n",
    "f(x) # function call"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "120\n"
     ]
    }
   ],
   "source": [
    "# example 3\n",
    "def g(n):\n",
    "    # function body\n",
    "    tmp = 1\n",
    "    for i in range(1, n+1 ,1):\n",
    "        tmp = tmp * i\n",
    "    return tmp\n",
    "\n",
    "x = g(5) # function call, 5*4*3*2*1\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Bill:  154.5\n"
     ]
    }
   ],
   "source": [
    "# example 4\n",
    "# Computes the total cost, including 3% sales tax\n",
    "# on number items at a cost of price each\n",
    "def total_cost(number, price):\n",
    "    # function body\n",
    "    tax_rate = 0.03 # 3% sales tax\n",
    "    cost = number * price\n",
    "    total = cost + (cost*tax_rate)\n",
    "    return total\n",
    "\n",
    "n = 5\n",
    "p = 30\n",
    "bill = total_cost(n, p)\n",
    "print('Bill: ',bill)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### enclosing function\n",
    "---\n",
    "![](https://i.imgur.com/XCS7yHE.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Question\n",
    "如果撰寫程式時,將 return object 的 object 省略,在呼叫 function 的階段會發生什麼事?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# return statement without object\n",
    "def f():\n",
    "    x = 5\n",
    "    return\n",
    "\n",
    "y = f() # function call\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n"
     ]
    }
   ],
   "source": [
    "# answer\n",
    "def f():\n",
    "    x = 5\n",
    "    return\n",
    "\n",
    "y = f() # function call\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n"
     ]
    }
   ],
   "source": [
    "# without return statement\n",
    "def f():\n",
    "    x=5\n",
    "\n",
    "y = f()\n",
    "print(y) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## 1.1.2 Coding Function: def Statements (2)\n",
    "---\n",
    "* **def statement** 是 executable code\n",
    "* keyword **def** 會建立 function object, 將 fucntion object assign 給 function name\n",
    "* keywood **return** 會回傳 object 給 caller\n",
    "* 傳遞 Arguments 的方式,使用 assignment\n",
    "* Arguments, return objects, 和 variables 都不需要事先宣告型別"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## 1.2.1 Why use function\n",
    "* **Maximizing code reuse**\n",
    "* Procedural decompsition"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "result1:  正常\n",
      "result2:  過重\n",
      "result3:  過輕\n",
      "result4:  過重\n"
     ]
    }
   ],
   "source": [
    "# 請計算四個人的 BMI: 1.63m-50kg, 1.8m-88kg, 1.9m-60kg, 1.5m-60kg\n",
    "height = 1.63 # 公尺\n",
    "weight = 50 # 公斤\n",
    "calculate = weight / (height*height)\n",
    "if calculate < 18.5:\n",
    "    result = '過輕'\n",
    "elif 18.5 < calculate and calculate < 24:\n",
    "    result = '正常'\n",
    "else:\n",
    "    result='過重'\n",
    "print(\"result1: \", result)\n",
    "    \n",
    "# person 2 =====================================\n",
    "height = 1.8 # 公尺\n",
    "weight = 88 # 公斤\n",
    "calculate = weight / (height*height)\n",
    "if calculate < 18.5:\n",
    "    result = '過輕'\n",
    "elif 18.5 < calculate and calculate < 24:\n",
    "    result = '正常'\n",
    "else:\n",
    "    result='過重'\n",
    "print(\"result2: \", result)\n",
    "\n",
    "# person 3 =====================================\n",
    "height = 1.9 # 公尺\n",
    "weight = 60 # 公斤\n",
    "calculate = weight / (height*height)\n",
    "if calculate < 18.5:\n",
    "    result = '過輕'\n",
    "elif 18.5 < calculate and calculate < 24:\n",
    "    result = '正常'\n",
    "else:\n",
    "    result='過重'\n",
    "print(\"result3: \", result)\n",
    "\n",
    "# person 4 =====================================\n",
    "height = 1.5 # 公尺\n",
    "weight = 60 # 公斤\n",
    "calculate = weight / (height*height)\n",
    "if calculate < 18.5:\n",
    "    result = '過輕'\n",
    "elif 18.5 < calculate and calculate < 24:\n",
    "    result = '正常'\n",
    "else:\n",
    "    result='過重'\n",
    "print(\"result4: \", result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "scrolled": true,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "result1:  正常\n",
      "result2:  過重\n",
      "result3:  過輕\n",
      "result4:  過重\n"
     ]
    }
   ],
   "source": [
    "# 公式:體重(公斤) / 身高^2(公尺^2)\n",
    "# 過輕:BMI < 18.5; 正常:18.5≦ BMI<24; 過重:24≦BMI\n",
    "def bmi(height, weight):\n",
    "    calculate = weight / (height*height)\n",
    "    if calculate < 18.5:\n",
    "        result = '過輕'\n",
    "        return result\n",
    "    elif 18.5 < calculate and calculate < 24:\n",
    "        result = '正常'\n",
    "        return result\n",
    "    else:\n",
    "        result='過重'\n",
    "        return result\n",
    "    \n",
    "h = 1.63 #公尺\n",
    "w = 50 #公斤\n",
    "r = bmi(h, w)\n",
    "print(\"result1: \", r) # 正常\n",
    "\n",
    "# one line\n",
    "print(\"result2: \", bmi(1.8, 88)) # 過輕\n",
    "print(\"result3: \", bmi(1.9, 60)) # 過輕\n",
    "print(\"result4: \", bmi(1.5, 60)) # 過輕"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## 1.2.2 Why use function\n",
    "* Maximizing code reuse\n",
    "* **Procedural decompsition**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# Procedural decopsition example\n",
    "# pizza-making robot\n",
    "def mixing_the_dough() #和麵\n",
    "def rolling_it_out() #桿麵\n",
    "def adding_toppings() #放料\n",
    "def baking_it() #烤"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### In general, functions are about procedure\n",
    "* how to do something, rather than what you’re doing it to ! "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Example 1: sqrt\n",
    "---\n",
    "寫一個function,用途計算數字的平方根。\n",
    "* example\n",
    "    * 4的平方根為2\n",
    "    * 9的平方根為3\n",
    "    * 2的平方根為1.4142...."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.0\n",
      "1.4142135623730951\n",
      "2.0\n",
      "1.4142135623730951\n"
     ]
    }
   ],
   "source": [
    "x = 4**0.5\n",
    "print(x)\n",
    "\n",
    "y = 2**0.5\n",
    "print(y)\n",
    "\n",
    "def get_sqrt(num):\n",
    "    return num**0.5\n",
    "\n",
    "print(get_sqrt(4))\n",
    "print(get_sqrt(2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Do not reinvent the wheel !! "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.0\n",
      "1.4142135623730951\n"
     ]
    }
   ],
   "source": [
    "import math\n",
    "\n",
    "print(math.sqrt(4))\n",
    "print(math.sqrt(2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Example 2: swap\n",
    "---\n",
    "定義一個function f,可以將 a, b 的值互換後,需回傳值回來。\n",
    "* example: \n",
    "    * a=1, b=2\n",
    "    * (a, b) = f(a, b)\n",
    "    * output: a=2, b=1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2 1\n"
     ]
    }
   ],
   "source": [
    "# sample answer 1\n",
    "def swap(a, b):\n",
    "    c = a\n",
    "    a = b\n",
    "    b = c\n",
    "    return a, b\n",
    "a = 1\n",
    "b = 2\n",
    "a, b = swap(a,b)\n",
    "print(a ,b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2 1\n"
     ]
    }
   ],
   "source": [
    "# sample answer 2\n",
    "def swap(a, b):\n",
    "    return b, a\n",
    "a = 1\n",
    "b = 2\n",
    "a, b = swap(a, b)\n",
    "print(a, b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2 1\n"
     ]
    }
   ],
   "source": [
    "# exsample answer 3\n",
    "# without function\n",
    "a = 1\n",
    "b = 2\n",
    "a, b = b, a\n",
    "print(a, b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Function\n",
    "---\n",
    "1. Function Basics\n",
    "2. **Scopes**\n",
    "3. Arguments"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Nampespace\n",
    "---\n",
    "![](https://i.imgur.com/RRDpUAZ.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Python Scope Basics \n",
    "---\n",
    "1. assign name inside **def**: local to that function\n",
    "2. assign name in **enclosing def**, nonlocal to nested functions\n",
    "3. assign name  outside all **defs**, global to the entire file.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "x = 99 # Global (module) scope x \n",
    "def f(): \n",
    "    x = 88 # Local (function) scope x: a different variable"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## The LEGB Rule\n",
    "---\n",
    "**當我們使用variable, python 在scope中搜尋variable的順序為 L, E, G 最後是 B**\n",
    "* **L:** local scope\n",
    "* **E:** local scopes of any enclosing defs\n",
    "* **G:** global scope \n",
    "* **B:** built-in scope"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## The LEGB Rule\n",
    "---\n",
    "<img src=\"https://i.imgur.com/5am8Cm4.png\" width=450 height=180 />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Scope example\n",
    "---\n",
    "* Global names: x, f\n",
    "* Local names: y, z\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "100"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Global scope\n",
    "x = 99  # X and f assigned in module: global\n",
    "def f(y): # Y and Z assigned in function: locals\n",
    "    # Local scope\n",
    "    z = x + y # X is a global\n",
    "    return z\n",
    "\n",
    "f(1) # function1 in module: result=100"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## The Built-in Scope\n",
    "---\n",
    "* 在 module *builtins* 中定義的name, 都屬於  built-in scope"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['ArithmeticError',\n",
       " 'AssertionError',\n",
       " 'AttributeError',\n",
       " 'BaseException',\n",
       " 'BlockingIOError',\n",
       " 'BrokenPipeError',\n",
       " 'BufferError',\n",
       " 'BytesWarning',\n",
       " 'ChildProcessError',\n",
       " 'ConnectionAbortedError',\n",
       " 'ConnectionError',\n",
       " 'ConnectionRefusedError',\n",
       " 'ConnectionResetError',\n",
       " 'DeprecationWarning',\n",
       " 'EOFError',\n",
       " 'Ellipsis',\n",
       " 'EnvironmentError',\n",
       " 'Exception',\n",
       " 'False',\n",
       " 'FileExistsError',\n",
       " 'FileNotFoundError',\n",
       " 'FloatingPointError',\n",
       " 'FutureWarning',\n",
       " 'GeneratorExit',\n",
       " 'IOError',\n",
       " 'ImportError',\n",
       " 'ImportWarning',\n",
       " 'IndentationError',\n",
       " 'IndexError',\n",
       " 'InterruptedError',\n",
       " 'IsADirectoryError',\n",
       " 'KeyError',\n",
       " 'KeyboardInterrupt',\n",
       " 'LookupError',\n",
       " 'MemoryError',\n",
       " 'ModuleNotFoundError',\n",
       " 'NameError',\n",
       " 'None',\n",
       " 'NotADirectoryError',\n",
       " 'NotImplemented',\n",
       " 'NotImplementedError',\n",
       " 'OSError',\n",
       " 'OverflowError',\n",
       " 'PendingDeprecationWarning',\n",
       " 'PermissionError',\n",
       " 'ProcessLookupError',\n",
       " 'RecursionError',\n",
       " 'ReferenceError',\n",
       " 'ResourceWarning',\n",
       " 'RuntimeError',\n",
       " 'RuntimeWarning',\n",
       " 'StopAsyncIteration',\n",
       " 'StopIteration',\n",
       " 'SyntaxError',\n",
       " 'SyntaxWarning',\n",
       " 'SystemError',\n",
       " 'SystemExit',\n",
       " 'TabError',\n",
       " 'TimeoutError',\n",
       " 'True',\n",
       " 'TypeError',\n",
       " 'UnboundLocalError',\n",
       " 'UnicodeDecodeError',\n",
       " 'UnicodeEncodeError',\n",
       " 'UnicodeError',\n",
       " 'UnicodeTranslateError',\n",
       " 'UnicodeWarning',\n",
       " 'UserWarning',\n",
       " 'ValueError',\n",
       " 'Warning',\n",
       " 'ZeroDivisionError',\n",
       " '__IPYTHON__',\n",
       " '__build_class__',\n",
       " '__debug__',\n",
       " '__doc__',\n",
       " '__import__',\n",
       " '__loader__',\n",
       " '__name__',\n",
       " '__package__',\n",
       " '__spec__',\n",
       " 'abs',\n",
       " 'all',\n",
       " 'any',\n",
       " 'ascii',\n",
       " 'bin',\n",
       " 'bool',\n",
       " 'bytearray',\n",
       " 'bytes',\n",
       " 'callable',\n",
       " 'chr',\n",
       " 'classmethod',\n",
       " 'compile',\n",
       " 'complex',\n",
       " 'copyright',\n",
       " 'credits',\n",
       " 'delattr',\n",
       " 'dict',\n",
       " 'dir',\n",
       " 'display',\n",
       " 'divmod',\n",
       " 'enumerate',\n",
       " 'eval',\n",
       " 'exec',\n",
       " 'filter',\n",
       " 'float',\n",
       " 'format',\n",
       " 'frozenset',\n",
       " 'get_ipython',\n",
       " 'getattr',\n",
       " 'globals',\n",
       " 'hasattr',\n",
       " 'hash',\n",
       " 'help',\n",
       " 'hex',\n",
       " 'id',\n",
       " 'input',\n",
       " 'int',\n",
       " 'isinstance',\n",
       " 'issubclass',\n",
       " 'iter',\n",
       " 'len',\n",
       " 'license',\n",
       " 'list',\n",
       " 'locals',\n",
       " 'map',\n",
       " 'max',\n",
       " 'memoryview',\n",
       " 'min',\n",
       " 'next',\n",
       " 'object',\n",
       " 'oct',\n",
       " 'open',\n",
       " 'ord',\n",
       " 'pow',\n",
       " 'print',\n",
       " 'property',\n",
       " 'range',\n",
       " 'repr',\n",
       " 'reversed',\n",
       " 'round',\n",
       " 'set',\n",
       " 'setattr',\n",
       " 'slice',\n",
       " 'sorted',\n",
       " 'staticmethod',\n",
       " 'str',\n",
       " 'sum',\n",
       " 'super',\n",
       " 'tuple',\n",
       " 'type',\n",
       " 'vars',\n",
       " 'zip']"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import builtins\n",
    "dir(builtins)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Enclosing function scope\n",
    "---\n",
    "* **E:** local scopes of any enclosing defs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Enclosing function example\n",
    "---\n",
    "* **Global names: w, outer**\n",
    "* **Enclosing local names: x, inner**\n",
    "* **Local names: z, y**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "110\n"
     ]
    }
   ],
   "source": [
    "# Global scope\n",
    "w = 21  # W and outer assigned in module: global\n",
    "def outer(x):# X and inner assigned in enclosing function: Enclosing def locals\n",
    "    def inner(y): # Z, Y assigned in function: local\n",
    "        z = w + x + y  # W is a global (21+88+1)\n",
    "        print(z)\n",
    "    inner(1)\n",
    "outer(88)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Example 3: scope"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# example1\n",
    "x = 'Spam'\n",
    "def func():\n",
    "    print(x)\n",
    "    \n",
    "func()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spam\n"
     ]
    }
   ],
   "source": [
    "# answer\n",
    "x = 'Spam'\n",
    "def func():\n",
    "    print(x)\n",
    "    \n",
    "func()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "# example2\n",
    "x = 'Spam'\n",
    "def func():\n",
    "    x = 'HI!'\n",
    "    \n",
    "func()\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spam\n"
     ]
    }
   ],
   "source": [
    "# answer\n",
    "x = 'Spam'\n",
    "def func():\n",
    "    x = 'HI!'\n",
    "    \n",
    "func()\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "# example3\n",
    "x = 'World'\n",
    "def func():\n",
    "    x = 'Hello'\n",
    "    print(x)\n",
    "    \n",
    "func()\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello\n",
      "World\n"
     ]
    }
   ],
   "source": [
    "# answer\n",
    "x = 'World'\n",
    "def func():\n",
    "    x = 'Hello'\n",
    "    print(x)\n",
    "    \n",
    "func()\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "# example 4\n",
    "w = 22\n",
    "def outer():\n",
    "    w = 23\n",
    "    def inner():\n",
    "        w = 24\n",
    "        print('first: ', w)  # first print\n",
    "    inner()\n",
    "    print('second: ', w) # second print\n",
    "    \n",
    "outer()\n",
    "print('third: ', w) # third print"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "first:  24\n",
      "second:  23\n",
      "third:  22\n"
     ]
    }
   ],
   "source": [
    "# answer\n",
    "w = 22\n",
    "def outer():\n",
    "    w = 23\n",
    "    def inner():\n",
    "        w = 24\n",
    "        print('first: ', w)  # first print\n",
    "    inner()\n",
    "    print('second: ', w) # second print\n",
    "    \n",
    "outer()\n",
    "print('third: ', w) # third print"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## The global Statement\n",
    "---\n",
    "* keyword: **global**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "99\n"
     ]
    }
   ],
   "source": [
    "# example\n",
    "x = 88 # Global x\n",
    "def f(): \n",
    "    global x\n",
    "    x = 99 # Global x: outside def\n",
    "\n",
    "f()\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Function\n",
    "---\n",
    "1. Function Basics\n",
    "2. Scopes\n",
    "3. **Arguments**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Review: Object\n",
    "---\n",
    "**Everything in python is an object**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "<img src=\"https://i.imgur.com/qaynkKr.png\" width=450 height=180 />"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10910464 10910464\n"
     ]
    }
   ],
   "source": [
    "a = 3\n",
    "print(id(a), id(3)) # id(a) 表示 a 實際的物件記憶體位址"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Review: immutable object\n",
    "---\n",
    "![](https://i.imgur.com/YCRrRgE.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10910464 10910464\n",
      "10910528 10910464\n"
     ]
    }
   ],
   "source": [
    "a = 3                 # 將 a 指到 一個 immutable object (list)\n",
    "b = a\n",
    "print(id(a), id(b))\n",
    "a += 2                # a 所指的位址已經改變了, 但不影響 b\n",
    "print(id(a), id(b))   # 可看到 a 跟 b 的記憶體位址已經不一樣了"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Review: mutable object\n",
    "---\n",
    "<img src=\"https://i.imgur.com/HWvxQCS.png\" width=450 height=180 />\n",
    "<img src=\"https://i.imgur.com/xGOu8Qs.png\" width=450 height=180 />"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "139663417770952 139663417770952\n",
      "139663417770952 139663417770952\n"
     ]
    }
   ],
   "source": [
    "a = [1,2,3]          # 將 a 指到 一個 mutable object (list)\n",
    "b = a\n",
    "print(id(a), id(b))  # 可看到這時 a 跟 b 的記憶體位址是一樣的\n",
    "a[0] = 's'\n",
    "print(id(a), id(b))  # 可看到這時 a 跟 b 的記憶體位址依舊是一樣的,從頭到尾都沒變化\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "##  3.1.1 Argument-Passing Basics (1)\n",
    "---\n",
    "* **aliasing**\n",
    "    * assignment to an argument name inside a function (e.g., a=99) does not change a variable like b in the scope of the function call."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "88\n"
     ]
    }
   ],
   "source": [
    "def f(a): # a is assigned to (references) the passed object\n",
    "    a = 99 # Changes local variable a only\n",
    "b = 88 \n",
    "\n",
    "f(b) # a and b both reference same 88 initially\n",
    "print(b) # b is not changed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "list_id: 139663066640648\n",
      "before_change b: [1, 2]\n",
      "after_change b: ['spam', 2]\n",
      "after_change b_id: 139663066640648\n",
      "list: ['spam', 2]\n",
      "list_id: 139663066640648\n"
     ]
    }
   ],
   "source": [
    "def change_element(b):            # Arguments assigned references to objects\n",
    "    print('before_change b:', b)\n",
    "    b[0] = 'spam'               # Changes shared object in place\n",
    "    print('after_change b:', b)\n",
    "    print('after_change b_id:', id(b))\n",
    "    \n",
    "test_list = [1, 2]\n",
    "print('list_id:', id(test_list))# original id of test_id\n",
    "\n",
    "change_element(test_list)         # Pass test_list (mutable object)\n",
    "\n",
    "print('list:', test_list)       # elements of test_list is different (changed)\n",
    "print('list_id:', id(test_list))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "##  3.1.2 Argument-Passing Basics (2)\n",
    "---\n",
    "**Avoiding Mutable Argument Changes**: \n",
    "If we don’t want in-place changes within functions to impact objects we pass to them, though, we can simply make explicit copies of mutable objects,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "before change: test_list: [1, 2] ; list_id: 139663067218376\n",
      "before change: copy_list [1, 2] ; copy_list_id: 139663502102344\n",
      "after change: test_list: [1, 2] ; test_list_id: 139663067218376\n",
      "after change: copy_test_list: ['spam', 2] ; copy_test_list_id: 139663502102344\n"
     ]
    }
   ],
   "source": [
    "def change_element(b):           # Arguments assigned references to objects\n",
    "    b[0] = 'spam'                # Changes shared object in place\n",
    "    \n",
    "test_list = [1, 2]\n",
    "copy_list = test_list[:]         # copy a new list\n",
    "\n",
    "print('before change: test_list:', test_list, '; list_id:', id(test_list))\n",
    "print('before change: copy_list', copy_list, '; copy_list_id:', id(copy_list))\n",
    "\n",
    "change_element(copy_list)\n",
    "\n",
    "print('after change: test_list:', test_list, '; test_list_id:', id(test_list))              # the same id\n",
    "print('after change: copy_test_list:', copy_list, '; copy_test_list_id:', id(copy_list))    # the same id"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## 3.1.3 Argument-Passing Basics (3)\n",
    "---\n",
    "* Arguments are passed by automatically assigning objects to local variable names\n",
    "\n",
    "* Assigning to argument names inside a function does not affect the caller\n",
    "\n",
    "* Changing a mutable object argument in a function may impact the caller.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## 3.2.1 Argument Matching Basics (1)\n",
    "---\n",
    "* **Positionals:** matched from left to right"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "scrolled": true,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 2 3\n"
     ]
    }
   ],
   "source": [
    "# positionals example\n",
    "def f(x, y, z):\n",
    "    print(x, y, z)\n",
    "f(1, 2, 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## 3.2.2 Argument Matching Basics (2)\n",
    "---\n",
    "* **Keywords:** matched by argument name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6 5 4\n"
     ]
    }
   ],
   "source": [
    "# keywords example\n",
    "def f(x, y, z):\n",
    "    print(x, y, z)\n",
    "    \n",
    "# In real cases, we should not change the order of the argument names. It is hard for other people to understand your code.\n",
    "f(z=4, y=5, x=6)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## 3.2.3 Argument Matching Basics (3)\n",
    "---\n",
    "* **Defaults:** specify values for optional arguments that aren’t passed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4 5 3\n",
      "4 5 6\n"
     ]
    }
   ],
   "source": [
    "# defaults and postional\n",
    "def f(x, y, z = 3):\n",
    "    print(x, y, z)\n",
    "\n",
    "f(4, 5)\n",
    "f(4, 5, 6)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## 3.2.4 Argument Matching Basics (4)\n",
    "---\n",
    "* **Varargs collecting:** collect arbitrarily many positional or keyword arguments\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1, 2, 3, 4, 5, 6, 8, 'hello')\n",
      "('how', 'do', 'you', 'do')\n",
      "1 2\n",
      "(3, 4, 5, 6, 8, 'hello')\n"
     ]
    }
   ],
   "source": [
    "# varargs collecting, one * for tuple\n",
    "def f1(*args):\n",
    "    print(args)\n",
    "\n",
    "f1(1, 2, 3, 4, 5, 6, 8, 'hello')\n",
    "f1('how', 'do', 'you', 'do')\n",
    "\n",
    "def f2(x, y, *args):\n",
    "    print(x,y)\n",
    "    print(args)\n",
    "f2(1,2,3,4,5,6,8,'hello')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'key1': 1, 'key2': 2, 'key3': 3}\n"
     ]
    }
   ],
   "source": [
    "# varargs collecting, two * for dictionary\n",
    "def f(**kwargs):\n",
    "    print(kwargs)\n",
    "    \n",
    "\n",
    "f(key1=1, key2=2, key3=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 2\n",
      "(3, 4, 5, 6, 8, 'hello')\n",
      "{'key1': 1, 'key2': 2, 'key3': 3}\n"
     ]
    }
   ],
   "source": [
    "# mix varargs collecting\n",
    "def mix(x, y, *args, **kwargs):\n",
    "    print(x,y)\n",
    "    print(args)\n",
    "    print(kwargs)\n",
    "mix(1, 2, 3, 4, 5, 6, 8, 'hello', key1=1, key2=2, key3=3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## 3.2.5 Argument Matching Basics (5)\n",
    "---\n",
    "* **Varargs unpacking:** pass arbitrarily many positional or keyword arguments"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 2 3\n",
      "1 2 3\n"
     ]
    }
   ],
   "source": [
    "# Varargs unpacking \n",
    "def f(x, y, z):\n",
    "    print(x, y, z)\n",
    "    \n",
    "some_args=(1, 2, 3)\n",
    "f(*some_args)\n",
    "\n",
    "some_kwargs = {'x': 1, 'y': 2, 'z': 3}\n",
    "f(**some_kwargs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Example: Argument_Matching"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 2 5\n",
      "1 2 3\n",
      "1 (2, 3)\n",
      "1 {'c': 3, 'b': 2}\n",
      "1 5 6 4\n"
     ]
    }
   ],
   "source": [
    "# example\n",
    "# What is the output of the following code?\n",
    "def f1(a, b=4, c=5):\n",
    "    print(a, b, c)\n",
    "f1(1, 2)\n",
    "\n",
    "def f2(a, b, c=5): \n",
    "    print(a, b, c)\n",
    "f2(1, c=3, b=2)\n",
    "\n",
    "def f3(a, *args):\n",
    "    print(a, args)\n",
    "f3(1, 2, 3)\n",
    "\n",
    "def f4(a, **kargs): \n",
    "    print(a, kargs)\n",
    "f4(a=1, c=3, b=2)\n",
    "\n",
    "def f5(a, b, c=3, d=4): \n",
    "    print(a, b, c, d)\n",
    "f5(1, *(5, 6))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "##  3.3 Function Design Concepts\n",
    "---\n",
    "* use arguments for inputs and return for outputs\n",
    "* use global variables only when truly necessary\n",
    "* don’t change mutable arguments unless the caller expects it.\n",
    "* each function should have a single, unified purpose."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## 3.4 Function Objects\n",
    "---\n",
    "* Python functions\n",
    "    * are full-blown objects, stored in pieces of memory all their own. \n",
    "    * can be freely passed around a program and called indirectly.\n",
    "    * support operations that have little to do with calls at all—attribute storage and annotation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello word!\n",
      "hello word!\n"
     ]
    }
   ],
   "source": [
    "# Function objects example: assigned to name\n",
    "def f(msg):\n",
    "    print(msg)\n",
    "\n",
    "f('hello word!')\n",
    "x = f\n",
    "x('hello word!')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello world!\n"
     ]
    }
   ],
   "source": [
    "# Function objects example: pass to other function\n",
    "def f(msg):\n",
    "    print(msg)\n",
    "    \n",
    "def g(f_obj, arg): \n",
    "    f_obj(arg)\n",
    "\n",
    "g(f, 'Hello world!') # Pass the function to another function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello\n",
      "World!!\n"
     ]
    }
   ],
   "source": [
    "# Function objects example: embedded in data structures\n",
    "def f(msg):\n",
    "    print(msg)\n",
    "    \n",
    "test_list = [(f, 'Hello'), (f, 'World!!')]\n",
    "\n",
    "for (f_obj, arg) in test_list:\n",
    "    f_obj(arg) # Call functions embedded in containers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello:world!\n"
     ]
    }
   ],
   "source": [
    "# Function objects example: return\n",
    "def f(msg):\n",
    "    def g(msg2):\n",
    "        print(msg+':'+msg2)\n",
    "    return g\n",
    "\n",
    "t = f('hello')\n",
    "t('world!')"
   ]
  }
 ],
 "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.6.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}