{ "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": [ "" ] }, { "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", "" ] }, { "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", "" ] }, { "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", "" ] }, { "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 }