{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# [X-Village] Lesson 05 - Exception Basics\n", "\n", "by 洪培軒" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Outline\n", "\n", "* 看懂 error message\n", "* 了解什麼是 exception\n", "* 為什麼需要 Exception Handling\n", "* 基本的語法\n", "* 自定義 exception\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#
如何看懂 error message
\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 1. scope -- `in xxx`\n", "\n", "告訴你那些問題在哪個 scope 被發現的" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" } }, "source": [ "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 2. Traceback\n", "告訴你程式經歷了哪些大風大浪才死去" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# traceback.py\n", "def take(key):\n", " print(dic[key])\n", "\n", "def generate_key(code):\n", " key = str(code)+'A'\n", " take(key)\n", "\n", "def generate_code(data):\n", " code = data%4\n", " generate_key(code)\n", "\n", "def walk_in(data):\n", " generate_code(data)\n", "\n", "dic = {'0A': 'plate', '1A': 'spoon'}\n", "walk_in(11)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 3. exception 的名字 -- `IndexError`\n", "錯誤的『名稱』,還有錯誤的『說明』" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "# wrong.py\n", "a = [123, 345, 789]\n", "print(a[3]) # line 2" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" } }, "source": [ "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 練習 1 (ex1)\n", "\n", "下面程式碼希望能夠印出 num 裏面的所有數字,但是程式跑到一半會出錯。\n", "\n", "執行後解釋出現的錯誤訊息,並說出程式在哪裡出了問題。\n", "\n", "TIPS: 如果不知道出現的 exception 代表什麼意思,可以參考 [python 內建的 exception](https://docs.python.org/3.6/library/exceptions.html)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def div(dividend, divisor):\n", " print(\"The answer is {}\".format(dividend/divisor))\n", "\n", "for i in range(5, -1, -1):\n", " for j in range(5, -1, -1):\n", " div(i, j)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" } }, "source": [ "\n", "## 練習 2 (ex2.py)\n", "\n", "更改上面程式碼讓程式可以正常運作" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#
exception 是什麼
\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "##
exception 就是炸彈
\n", "\n", "* try\n", "* except\n", "* finally\n", "* raise\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "\n", "1. 做好會隨時拿到炸彈的『準備』\n", "2. 『拿到炸彈』就自己『拆掉』,不然就『丟給別人』拆\n", "3. 丟炸彈要看時機(想『炸敵人』還是『炸同伴』)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* 隊友太雷就炸隊友 -> 提醒隊友不要粗心\n", "* 敵人太強也炸敵人 -> 讓 bug 比較容易被發現\n", "------------\n", "* 做準備 -> try\n", "* 拆炸彈 -> except\n", "* 丟炸彈 -> raise\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "##
有不同的 exception
\n", "
就像炸彈也有不同的種類
\n", "\n", "* 地雷\n", "* 手榴彈\n", "* 原子彈\n", "* ...." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "##
常見的 exception
\n", "* ValueError\n", "* NameError\n", "* SyntaxError\n", "* IndentationError" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* ValueError: 正確的型態,不正確的值" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "print(int(\"a\"))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "print(int(\"1\"))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* NameError: 使用到沒有定義過的 name" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "ggg_abc()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "\n", "def ggg_abc():\n", " print(\"in ggg_abc()\")\n", "gggg_abc()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* SyntaxError: 語法錯誤\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "print('hello world\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" } }, "source": [ "EOL: End of Line" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "print('hello world!')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* IndentationError: 縮排錯誤" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "if True:\n", "print(\"ok!\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "if True:\n", " print(\"ok!\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#
為什麼我們需要 Exception Handling
\n", "\n", "## 用途\n", "1. 易讀性,減少累贅的判斷式\n", "\n", "2. 避免使用回傳值作為判斷依據(有時候會忘記)\n", "\n", "3. 預期中會產生的錯誤,但是不希望程式中止\n", "\n", " \n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "\n", "[圖片取自網路](https://www.fabiaoqing.com/biaoqing/detail/id/53371.html)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 小明買醬油的故事" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "1. 直接回家跟媽媽講沒醬油了 -> 沒有買東西 -> 晚餐沒有味道" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "2. 打電話回家,不買到東西不離開 -> 可以買鹽來代替 -> 晚餐有味道" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 用宿網打 game" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "\n", "\n", "[圖片來源](https://zhidao.baidu.com/question/629629479260473044.html)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "## 小明買醬油的故事\n", "\n", "媽媽叫小明去買醬油。\n", "\n", "小明去了超市後發現沒有醬油,就直接回家了。\n", "\n", "晚餐時間大家在吃飯發現飯菜都沒有味道。\n", "\n", "---------------------\n", "\n", "如果我們有 exception 呢?\n", "\n", "小明會在超市打電話問媽媽說沒醬油了,媽媽讓他買其他東西來代替醬油。\n", "\n", "如果沒有買到醬油的替代品,小明就不會離開超市。\n", "\n", "---------------------\n", "\n", "差別:\n", "\n", "沒有 exception 的話,晚餐可能不會是我們想要的 --> 程式可以執行,但是有 bug而且不知道在哪裡發生的\n", "\n", "有 exception 的話,小明會**提醒**媽媽沒有醬油,是不是要買其他東西 --> 程式有問題,在解決之前沒辦法執行(或是執行到一半會死掉)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "## 用宿網打 game\n", "\n", "開開心心打遊戲,大家在會戰的突然掉線了。\n", "\n", "原來是宿網斷線了啊!但是遊戲程式有因為網路斷線而出現錯誤嗎?\n", "\n", "沒有!頂多告訴你你已經斷線了,請嘗試重新連線。\n", "\n", "為什麼程式不會中斷?因為我們用 exception 把他抓住了,並且在後面寫下如果遇到網路斷線時應該要做什麼。\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#
遇到 Exception 之後...
\n", "\n", "* try....except...else\n", "* try....except as e\n", "* finally\n", "* raise" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## try...except...[else]\n", "最基本的語法" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "try:\n", " # do something\n", "except Exception:\n", " # handle the exception\n", "else:\n", " # optional, if no exception happens" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "try:\n", " print(\"In try block\")\n", "except Exception:\n", " print(\"In Exception block\")\n", "else:\n", " print(\"No exception\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 練習(不計分)\n", "\n", "寫出一個會產生 exception 的程式,並用 try...except...else 接起來" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## try...except...as e\n", "e 會是抓到的那個 exception 的 instance object\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "# run me!\n", "try:\n", " num = x\n", "except NameError as e:\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 練習(不計分)\n", "\n", "* 試著用 `type(e)` 看 e 是什麼型別的\n", "* 試著用 `instance.args` 看看這個 object 的 attribute 有哪些\n", "* 試著產生其他的 exception 再把他印出來看看\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 多個 exception" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "# run me!\n", "a = [1, 2, 3]\n", "try:\n", " print(a[100])\n", " num = x\n", "except NameError as e:\n", " print(\"I'm in NameError! \")\n", " print(e)\n", "except IndexError as e:\n", " print(\"I'm in IndexError!\" )\n", " print(e)\n", "else:\n", " print(\"I'm in else!\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 另一種寫法\n", "(把 print(a[100]) 和 num = x 互換看看)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "# run me!\n", "a = [1,2,3]\n", "try:\n", " print(a[100])\n", " num = x\n", "except (NameError, IndexError) as e:\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## finally\n", "不論是否產生 exception, 『最後』一定會被執行到的區塊" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "try:\n", " print(\"hello!\")\n", " x = gggggg\n", "except Exception as e:\n", " print(e)\n", "else:\n", " print(\"In else\")\n", "\n", "print(\"I'm in finally!\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 練習(不計分)\n", "如果把 finally 刪掉會怎樣呢?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 為什麼需要 finally?\n", "\n", "比較這兩種程式碼:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def func():\n", " try:\n", " print(\"hello\")\n", " except Exception:\n", " print(\"in exception\")\n", " return\n", " # do something\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "def func():\n", " try:\n", " print(\"hello\")\n", " except Exception:\n", " print(\"in exception\")\n", " return\n", " finally:\n", " # do something" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 實際上來操作一次" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# run me!\n", "def func():\n", " try:\n", " print(\"I'm in try block!\")\n", " a = bggggggg\n", " except Exception:\n", " print(\"I'm in except block!\")\n", " return\n", " finally:\n", " print(\"do something\")\n", " \n", "func()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" } }, "source": [ "### 練習(不計分)\n", "把 finally 去掉再試試看,會發生什麼事?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## raise\n", "丟出一個 exception 給別人接" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# run me!\n", "def div(a, b):\n", " if b == 0:\n", " raise ValueError(\"divisor cannot be zero!\")\n", " else: return a/b\n", "\n", "num = div(1,0)\n", "print(num)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 練習 3 (ex3.py)\n", "\n", "寫一個 function,function 需要 raise exception\n", "\n", "呼叫 function 的時候需要用 try...except 包起來\n", " \n", "**挑戰題 1 (ex5.py)**\n", "\n", "實做 **小明買醬油** 的故事" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 挑戰題的範例(把 TODO 解掉)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "import random\n", "item_in_shop = {\"soybean_sauce\": 0, \"milk\": 4, \"salt\": 10, \"soybean_milk\": 3}\n", "items = [item for item in item_in_shop.keys()]\n", "cnt = 5\n", "\n", "def buy(item):\n", " # TODO: 補上程式碼和完成邏輯\n", " # tips: 如果東西數量是 0 需要 raise Exception,否則就把物品的數量減 1 \n", " print(\"Mommy! I've bought {} for you!\".format(item))\n", "\n", "# 買五個隨機的東西\n", "while cnt:\n", " cnt -= 1\n", " index = random.randint(0,3)\n", " item = items[index]\n", " \n", " # 想要買的東西是 item,利用 buy() 來買東西\n", " # TODO: 補上程式碼\n", " # tips: 記得用 try...except 包起來\n", " " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "##
為什麼我們需要 Exception Handling
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "
以 python 的語法來實際比較看看
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "1. 易讀性,減少累贅的判斷式\n", "\n", " **沒有使用 exception 的時候**" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def calc_percentage(dividend, divisor):\n", " if divisor == 0:\n", " return -1\n", " else:\n", " return 100.0*dividend/divisor\n", "\n", "a1 = calc_percentage(25.0, 100.0) \n", "a2 = calc_percentage(30.0, 56.0) \n", "a3 = calc_percentage(16.0, 49.0)\n", "\n", "if a1 == -1:\n", " print(\"Not vaild divisor\")\n", "else:\n", " print(\"The answer is \" + str(a1)+\"%\")\n", "\n", "if a2 == -1:\n", " print(\"Not vaild divisor\")\n", "else:\n", " print(\"The answer is \" + str(a2)+\"%\")\n", "\n", "if a3 == -1:\n", " print(\"Not vaild divisor\")\n", "else:\n", " print(\"The answer is \" + str(a3)+\"%\")\n", " " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "1. 易讀性,減少累贅的判斷式\n", "\n", " **使用 exception 的時候**" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def calc_percentage(dividend, divisor):\n", " if divisor == 0:\n", " raise ZeroDivisionError(\"Divisor cannot be zero!\")\n", " else:\n", " return 100.0*dividend/divisor\n", "\n", "a1 = calc_percentage(25.0, 100.0)\n", "a2 = calc_percentage(30.0, 56.0)\n", "a3 = calc_percentage(16.0, 49.0)\n", "print(\"The answer is \" + str(a1)+\"%\")\n", "print(\"The answer is \" + str(a2)+\"%\")\n", "print(\"The answer is \" + str(a3)+\"%\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "2. 避免使用回傳值作為判斷的依據(有時候會忘記,尤其是如果 function 不是自己寫的時候)\n", "\n", " **沒有使用 exception 的時候**" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "def calc_percentage(dividend, divisor):\n", " if divisor == 0:\n", " return -1\n", " else:\n", " return 100.0*dividend/divisor\n", "\n", "answer = calc_percentage(25.0, 0.0)\n", "print(\"The answer is \" + str(answer)+\"%\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "2. 避免使用回傳值作為判斷的依據(有時候會忘記,尤其是如果 function 不是自己寫的時候)\n", "\n", " **使用 exception 的時候**" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "def calc_percentage(dividend, divisor):\n", " if divisor == 0:\n", " raise ZeroDivisionError(\"Divisor cannot be zero!\")\n", " else:\n", " return 100.0*dividend/divisor\n", "\n", "answer = calc_percentage(25.0, 0.0)\n", "print(\"The answer is \" + str(answer)+\"%\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 練習 (不計分)\n", "\n", "使用已經寫好的 function,**隨機**取出 list 裏面的資料,請找出程式的問題。\n", "\n", "TIPS:多執行幾次看看\n", "\n", "註: get_index_random(m, n) 可以得到一個隨機的 index,可以多執行幾次看看問題出在那邊" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "import random\n", "def get_index_random(m, n):\n", " # Does not expect m to be 1, return -1\n", " if m==1:\n", " return -1\n", " return (n+m+random.randint(0,4))%4\n", "\n", "my_list = ['apple', 'banana', 'cherry', 'dog']\n", "\n", "for i in range(10):\n", " for j in range(10):\n", " index = get_index_random(i, j)\n", " print(my_list[index])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 解答" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "import random\n", "def get_index_random(m, n):\n", " # Does not expect m to be 1, return error code\n", " if m==1:\n", " return -1\n", " return (n+m+random.randint(0,4))%4\n", "\n", "my_list = ['apple', 'banana', 'cherry', 'dog']\n", "\n", "for i in range(10):\n", " for j in range(10):\n", " index = get_index_random(i, j)\n", " # ------加上判斷式------\n", " if index==-1:\n", " print(\"m cannot be 1, try another m value\");\n", " # -------------------\n", " else: print(my_list[index])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#
自定義 exception
\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "##
為什麼我們需要自己定義 exception?
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "##
如何自己定義 exception
\n", "\n", "定義一個新的 class\n", "* 繼承 Exception\n", "* 定義一些 special method\n", " 1. `__init__(self[,...])`\n", " 用來初始化\n", " 2. `__str__(self)`\n", " 用來印出內容\n", " \n", " [延伸閱讀](https://docs.python.org/3/reference/datamodel.html#special-method-names)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 做一次看看吧!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "# run me!\n", "class MyException(Exception):\n", " def __init__(self, err_msg):\n", " self.msg = err_msg\n", " def __str__(self):\n", " return \"abc\" + self.msg\n", "\n", "try:\n", " raise MyException(\"I'm an exception message!\")\n", "except MyException as e:\n", " print(\"---encountered MyEception---\")\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 練習 4 (ex4.py)\n", "\n", "自己定義一個 exception 叫作 RelationException\n", "\n", "在 raise 的時候需要能夠接受 2 個字串,像是這樣 `raise RelationException(\"Mommy\", \"Daddy\")`\n", "\n", "輸出的時候需要以下列格式印出 (P1 和 P2 是 raise exception 時傳入的參數)\n", "\n", "`Are you sure that P1 and P2 are in love with each other?`" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 補齊程式碼 (把有 TODO 的地方都改掉)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "'''\n", "TODO: define a exception class\n", "'''\n", "relation = {'Jason':'Mary', 'Mary':'Jason', 'Jennifer':'Ken', 'Ken':'Jennifer', 'Tina':'Kim', 'Kim':'Tina'}\n", "def check(pa, pb):\n", " if relation[pa] != pb:\n", " # TODO: raise exception\n", " # TIPS: 這個地方會需要 raise 兩種 exception\n", " \n", "try:\n", " p1 = input(\"Please enter the first person: \")\n", " p2 = input(\"Please enter the second person: \")\n", " check(p1, p2)\n", " print(\"{} and {} are in love with each other!\".format(p1, p2))\n", " \n", "except '''what exception?''' as e:\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 測資\n", "\n", "輸入:\n", "\n", " Jason\n", " \n", " Mary\n", " \n", "輸出:\n", "\n", " Jason and Mary are in love with each other!\n", " \n", "-----\n", "輸入:\n", "\n", " Jen\n", " \n", " Ducky\n", " \n", "輸出:\n", "\n", " No relation found\n", " Are you sure that Jen and Ducky are in love with each other?\n", " \n", "-----\n", "輸入:\n", "\n", " Jason\n", " \n", " Jennifer\n", " \n", "輸出:\n", "\n", " Are you sure that Jason and Jennifer are in love with each other?\n", " \n", "-----" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 挑戰題2 (ex6.py)\n", "\n", "### 解釋\n", "\n", "* 三個數值:飢餓度,口渴度,開心度\n", "\n", "* 有三個動作,分別會消耗一些數值\n", " * play\n", " * eat\n", " * drink " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ " \n", "* 需要三個 exception,分別是 \n", " * HungryException\n", " * ThirstyException\n", " * BoredException" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 目標\n", "1. 定義出這三種不同的 exception\n", "2. 決定哪時候應該要 raise 哪個 exception\n", "3. 決定遇到 exception 時的處理方式,並且印出字串\n", " * `I'm _____ (status: xxx), need to ......`\n", " * `___`和`xxx`和`...`因為不同狀況會是不同字串" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 補齊程式碼" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "import random\n", "\n", "'''\n", "TODO: define exception classes\n", "'''\n", "\n", "def check(man):\n", " # TODO: in what condition need to raise exception?\n", " \n", "def play(man):\n", " print(\"playing...\")\n", " man[\"hunger\"] -= 15\n", " man[\"water\"] -= 15\n", " man[\"mood\"] += 5\n", " check(man)\n", "def eat(man):\n", " print(\"eating...\")\n", " man[\"hunger\"] += 5\n", " check(man)\n", "def drink(man):\n", " print(\"drinking...\")\n", " man[\"water\"] += 5\n", " check(man)\n", " \n", "actionList = [play, eat, drink]\n", " \n", "child = {\"hunger\": 20, \"water\": 20, \"mood\": 20}\n", "\n", "while True:\n", " cnt -= 1\n", " rand = random.randint(0,2)\n", " \n", " # TODO: 把隨機的動作用 try...except 包起來 \n", " actionList[rand](child)\n", " # TIPS: 記得只要抓到 exception 之後就要 break 了,不然會造成無窮迴圈 " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 可能會出現的結果" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" } }, "source": [ "playing...\n", "\n", "drinking...\n", "\n", "drinking...\n", "\n", "drinking...\n", "\n", "playing...\n", "\n", "I'm hungry (status: -10), need to eat!\n", "\n", "eating..." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 挑戰題 (ex7.py)\n", "\n", "參考墜樓的故事,把故事敘述用程式碼表達\n", " " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "小明在 106 樓看風景,不小心腳一滑從 106 樓掉下去。\n", "\n", "這時候會觸發大樓的安全機關(FallDownException),但是因為小明太胖了所以第一層安全機關會被突破。\n", "\n", "好險大樓還有第二層安全機關(FallDownStrongerException),最後終於把小明接住了!\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "定義兩個 exception,分別是\n", "* FallDownException(Exception)\n", "* FallDownStrongerException(Exception)\n", "\n", "定義一個函式\n", "* slip(floor)\n", " * 小明必須要在第 80 樓觸發 FallDownException, 在第 5 樓觸發 FallDownStrongerException\n", " * 觸發時記得要印出: 在 xx 樓被接住了!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 輸出\n", "\n", "現在在 105 樓\n", "\n", "現在在 104 樓\n", "\n", "....(略)\n", "\n", "在 80 樓被接住了!\n", "\n", "突破機關!\n", "\n", "....(略)\n", "\n", "現在在 5 樓\n", "\n", "在 5 樓被接住了!\n", "\n", "安全!\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 補齊程式碼" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# TODO: 按照敘述定義出兩個 Exception\n", " \n", "def slip(floor):\n", " try:\n", " while floor:\n", " floor -= 1\n", " print(\"現在在 {} 樓\".format(floor))\n", "\n", " if floor == 80:\n", " # TODO: 要 raise 一個 exception\n", " \n", " except '''TODO: 要用一個 exception 接''' as e:\n", " print(e)\n", " print(\"突破機關!\")\n", " while floor:\n", " floor -= 1\n", " print(\"現在在 {} 樓\".format(floor))\n", " \n", " if floor == 5:\n", " # TODO: 要 raise 一個 exception\n", " \n", "# TODO: 用 try...except 把 slip(106) 包起來\n", "slip(106)" ] } ], "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.5" } }, "nbformat": 4, "nbformat_minor": 2 }