{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "<p style=\"text-align:center\">\n", " <a href=\"https://nbviewer.jupyter.org/github/twMr7/Python-Machine-Learning/blob/master/10-Coding_Project.ipynb\">\n", " Open In Jupyter nbviewer\n", " <img style=\"float: center;\" src=\"https://nbviewer.jupyter.org/static/img/nav_logo.svg\" width=\"120\" />\n", " </a>\n", "</p>" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[](https://colab.research.google.com/github/twMr7/Python-Machine-Learning/blob/master/10-Coding_Project.ipynb)\n", "\n", "# 10. 程式開發專案 Coding Project\n", "\n", "使用互動式的 Jupyter QtConsole 或 Notebook 介面,只適合用來作先期的實驗測試,離開這些介面後原有的函式、變數都不會被保留,當然也沒辦法被其他程式重複使用。 因此,有需要重複執行的功能就通常會把測試過有用的程式碼集合起來,寫成一個副檔名是 **“.py”** 的 **script** 檔案。\n", "\n", "當 script 越寫越長,會開始需要將程式碼有結構化的組織起來。 除了常用的功能可以定義成函式以外,不同性質的函式可以分類拆成多個不同的 script 檔案。 而根據經驗,將函式的功能定義得越簡單,程式碼越不容易出錯,所以時常可以看到稍大型一點的專案會把一個檔案就只放一個函式。\n", "\n", "+ [**10.1 模組(Modules)**](#modules)\n", "+ [**10.2 套件(Packages)**](#packages)\n", "+ [**10.3 迷你專案(An Example Mini-Project)**](#mini-project)\n", "+ [**10.4 擴充專案功能練習(Expanding Project Features)**](#expanding-project)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "<a id=\"modules\"></a>\n", "\n", "## 10.1 模組 Modules\n", "\n", "在 Python 環境裡,一個 script 檔案就是一個模組,模組的名稱就是檔案的名稱(不包括 .py 的副檔名),模組裡面所有定義的函式及變數都需要透過 `import` 才能被另外一個 script 檔案使用。 Python 要 import 一個模組時,會先從內建模組開始搜尋起,找不到的話則依序尋找以下位置:\n", "\n", "1. 叫用 `import` 的 script 檔案的相同目錄。\n", "2. 系統環境變數 `PYTHONPATH` 的搜尋路徑清單。\n", "3. 標準函式庫的目錄。\n", "4. 副檔名為 `.pth` 的路徑設定檔。\n", "5. 其他函式庫套件 `Lib/site-packages` 路徑。\n", "\n", "並不是只有副檔名是 .py 的 script 檔才能 `import`,由名稱選取的套件(package)或模組(module),可以是以下幾種格式:\n", "+ 副檔名是 **.py** 的程式碼文字檔。\n", "+ 副檔名是 **.pyc** 的編譯過的 byte code 檔案。\n", "+ 目錄名稱符合,而且存在套件必要的 `__init__.py` 檔。\n", "+ 由 C++ 程式編譯來的,副檔名是 **.pyd** 的動態連結延伸模組\n", "+ 副檔名是 **.zip** 的壓縮檔,**import** 時會自動解壓縮。\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "兩種輸入模組的語法可以使用 `import ...` 以及 `from ... import ...`,差別在於是否需要透過模組名稱來存取模組內的函式或變數名字。\n", "\n", "### § `import` 陳述\n", "```\n", "import module1\n", "import module2, module3\n", "import module4 as m4\n", "```\n", "使用 `import` 的陳述,因為是整個模組物件直接輸入,必需透過模組名稱來存取模組內的函式或變數名字。 如:`module1.func1()`,`m4.func4()`,`module2.var2`。\n", "\n", "### § `from` 陳述\n", "```\n", "from module1 import func1\n", "from module2 import func2, var2\n", "from module3 import *\n", "from package import module4 as m4\n", "```\n", "使用 `from` 的陳述,因為指定了要從模組輸入的函式或變數名字,因此不需要再透過模組名稱來存取。 如: `func1()`,`func2()`,`var2`。\n", "\n", "### § 模組 `import` 只會發生一次\n", "由於一個模組的 `import` 是相當昂貴的操作,因此 `import` 只會在程式的執行生命週期內發生一次,輸入的模組只會有一份。\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### § 模組的使用模式: `__name__` 以及 `__main__`\n", "\n", "所有的模組都有一個內建的 `__name__` 屬性,在 Python 建立該模組時就會自動指定。\n", "+ 如果 script 檔是被執行成最上層的程式,`__name__` 屬性會被指定為 `'__main__'`,例如:\n", " 1. 在命令列下指令 `python somescript.py`,或\n", " 2. 在命令列下指令 `python -m somescript.py`,或\n", " 3. 在 *ipython* 或 *jupyter notebook* 執行 `%run somescript.py`。\n", "+ 如果 script 檔是被 `import` 方式載入的,`__name__` 屬性會被指定為模組的名字。\n", "\n", "除了原本就是設計為程式進入點的 script 以外,也時常可以看到純函式的模組包含這樣的檢查:\n", "```\n", "if __name__ == '__main__':\n", " main()\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "<a id=\"packages\"></a>\n", "\n", "## 10.2 套件 Packages\n", "\n", "套件是利用檔案系統來結構化組織模組的方式。 以設計一個音訊處理的 `sound` 套件為例(以下範例來自 [Python官方文件](https://docs.python.org/3/tutorial/modules.html#packages) ),不同聲音檔案格式的讀寫,適合有各自獨立的模組來處理,然後集合成一個 `formats` 的子套件。 然後音訊資料又可以套用許多不同的特效及濾波,以下是一個可能的套件結構。\n", "\n", "```\n", "sound/ 套件最上層目錄\n", " __init__.py 初始化 sound 套件\n", " formats/ 子套件: 檔案格式轉換\n", " __init__.py\n", " wavread.py\n", " wavwrite.py\n", " mp3read.py\n", " mp3write.py\n", " ...\n", " effects/ 子套件: 特效\n", " __init__.py\n", " echo.py\n", " surround.py\n", " reverse.py\n", " ...\n", " filters/ 子套件: 濾波\n", " __init__.py\n", " equalizer.py\n", " vocoder.py\n", " karaoke.py\n", " ...\n", "\n", "```\n", "\n", "+ 屬於 Python 套件的目錄下,必須要存在一個 `__init__.py` 的檔案,內容可以是空的。\n", "+ `import` 的階層按照目錄的階層安排,如 `from sound.effects import echo`。\n", "+ 如果要提供 `from sound.effects import *` 的功能,在 \"sound/effects/__init__.py\" 檔案裡要有一行 `__all__ = ['echo', 'surround', 'reverse']`,否則只會有 `sound.effects` 被 import。\n", "+ 子套件之間需要交互 import 時,可以使用絕對或相對路徑兩種方式:\n", " - **絕對方式** - 例如 `sound.filters.karaoke` 需要使用 `echo` 模組的功能,可以用 `from sound.effects import echo`。\n", " - **相對路徑** - 例如在 `surround` 模組裡,可以這樣用 `from . import echo`,`from .. import formats`,或 `from ..filters import equalizer`。\n", "+ 套件如果要執行成上層應用程式,必須透過 `python -m somepackage` 的方式,且套件裡要存在 `__main__.py` 的模組作為程式的主要進入點。\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "<a id=\"mini-project\"></a>\n", "\n", "## 10.3 迷你專案(An Example Mini-Project)\n", "\n", "編輯一個 script 儲存成 \"***rotatepoint.py***\" ,內容如以下 cell 中的程式碼。 第一行使用了 `%%writefile` magic 命令,執行該 cell 時就會將 cell 裡的程式碼存成檔案,手動複製程式碼到編輯器的話,可以忽略第一行。\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing rotatepoint.py\n" ] } ], "source": [ "%%writefile rotatepoint.py\n", "from typing import Tuple\n", "from math import cos, sin, radians\n", "\n", "point2d = Tuple[float, float]\n", "\n", "def rotate2d(point: point2d, degree: float) -> point2d:\n", " \"\"\"rotate 2D point by specific degree\n", " \"\"\"\n", " x, y = point[0], point[1]\n", " theta = radians(degree)\n", " new_x = x * cos(theta) - y * sin(theta)\n", " new_y = x * sin(theta) + y * cos(theta)\n", " return (new_x, new_y)\n", "\n", "\n", "if __name__ == \"__main__\":\n", " import argparse\n", " # setup options\n", " parser = argparse.ArgumentParser(prog='rotatepoint', description='''\n", " rotatepoint read a 2D point and angle from command line arguments.\n", " The output is a point transformed by rotating specific degree.\n", " ''')\n", " parser.add_argument('-p', '--point', nargs=2, type=float,\n", " metavar=('X','Y'), required=True,\n", " help='''Specify a (x, y) coordinate poin.''')\n", " parser.add_argument('-a', '--angle', type=float, required=True,\n", " help='''Specify rotating angle in degree.''')\n", " \n", " # parse command line arguments\n", " args = parser.parse_args()\n", "\n", " new_point = rotate2d(args.point, args.angle)\n", " print(new_point)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### § 以 Script 方式執行\n", "\n", "檔案生成後,可以在 notebook 使用 `%run` 來執行。\n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "usage: rotatepoint [-h] -p X Y -a ANGLE\n", "\n", "rotatepoint read a 2D point and angle from command line arguments. The output is a point transformed by rotating specific degree.\n", "\n", "optional arguments:\n", " -h, --help show this help message and exit\n", " -p X Y, --point X Y Specify a (x, y) coordinate poin.\n", " -a ANGLE, --angle ANGLE\n", " Specify rotating angle in degree.\n" ] } ], "source": [ "%run rotatepoint -h" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(-5.0, 3.0000000000000004)\n" ] } ], "source": [ "%run rotatepoint -p 3 5 -a 90" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### § 把模組當成函式庫 `import`\n", "\n", "只需要該模組裡面的某些函式,`import` 進來不會去執行 `__name__ == \"__main__\"` 區段的程式碼。\n" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(-5.0, 3.0000000000000004)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from rotatepoint import rotate2d\n", "\n", "# 呼叫函式\n", "rotate2d((3, 5), 90)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "<a id=\"expanding-project\"></a>\n", "\n", "## 10.4 擴充專案功能練習(Expanding Project Features)\n", "\n", "學習以下範例使用 `csv` 及 `argparse` 物件的方法,必要時查閱 Python 官網文件,以完成指定的功能。\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### § CSV\n", "\n", "+ [**`csv`**](https://docs.python.org/3/library/csv.html) 模組,Python 官網文件 (https://docs.python.org/3/library/csv.html)\n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# 隨機產生 N 個點資料,輸出成CSV格式\n", "import csv\n", "from random import randrange, random, sample\n", "\n", "# csv 物件會自己處理換行,固定要加參數 newline=''\n", "with open('points.csv', 'w', newline='') as csvfile:\n", " field_names = ['x', 'y']\n", " # 注意: 沒有 QUOTE_NONNUMERIC 的話,預設輸出文字沒有引號\n", " writer = csv.writer(csvfile, quoting=csv.QUOTE_NONNUMERIC)\n", " # write header\n", " writer.writerow(field_names)\n", " # random sample N points (N == 5)\n", " for _ in range(5):\n", " x, y = randrange(-100,100)+random(), randrange(-100,100)+random()\n", " writer.writerow([x, y])" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['x', 'y']\n", "[82.93172791107892, 48.90225839878033]\n", "[-16.14561496387222, -42.060573887619334]\n", "[-83.28140163536176, -65.0394205200153]\n", "[-32.43098549252423, 80.10788082697725]\n", "[84.96345212346213, 78.05944524112805]\n" ] } ], "source": [ "# 讀入CSV格式檔案,使用csv物件解析每一筆資料\n", "with open('points.csv', 'r', newline='') as csvfile:\n", " reader = csv.reader(csvfile, quoting=csv.QUOTE_NONNUMERIC)\n", " for row in reader:\n", " print(row)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[82.93172791107892, -16.14561496387222, -83.28140163536176, -32.43098549252423, 84.96345212346213]\n", "[48.90225839878033, -42.060573887619334, -65.0394205200153, 80.10788082697725, 78.05944524112805]\n" ] } ], "source": [ "# 在一次讀入CSV格式檔案,這次使用DictReader物件解析\n", "# 將點資料 x, y 分別存成 list\n", "X, Y = [], []\n", "with open('points.csv', 'r', newline='') as csvfile:\n", " reader = csv.DictReader(csvfile, quoting=csv.QUOTE_NONNUMERIC)\n", " for row in reader:\n", " X.append(row['x'])\n", " Y.append(row['y'])\n", "\n", "print(X)\n", "print(Y)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "# 載入繪圖工具\n", "%matplotlib inline\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[<matplotlib.lines.Line2D at 0x2191ab6a910>]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXkAAAD4CAYAAAAJmJb0AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAAAScUlEQVR4nO3dbYxc133f8e+vJK2u7RqUIUrmg1jSKcVUttPQ3ahuDRtoJZtyaoisAQc0YINwXLAO5NTuA2PRetEggBDXTNIWSJuAjVUQqBJFdWiKMOJQD3kA+kKSKVENTdGMGMuRuGQkOi7rtFlIIvPvi70rDaWhuMuZ3dk9/H4AYeaec+89f1zN/ubwzJ3dVBWSpDb9jVEXIEmaO4a8JDXMkJekhhnyktQwQ16SGrZ01AX0uuaaa2rdunWjLkOSFpXHH3/8+1W1ol/fggr5devWcejQoVGXIUmLSpI/u1ifyzWS1DBDXpIaZshLUsMMeUlqmCEvSQ0byt01Sf4V8M+BAo4AnwbeDPw2sA74HvBTVfW/hzGeRmv/4Ql2HzzOqbOTrFo+xs7NG9m6afWoy5LUx8Az+SSrgX8JjFfVu4ElwDbgDuDhqtoAPNxta5Hbf3iCXfuOMHF2kgImzk6ya98R9h+eGHVpkvoY1nLNUmAsyVKmZvCngC3A3q5/L7B1SGNphHYfPM7ky+cvaJt8+Ty7Dx4fUUWS3sjAyzVVNZHkl4BngUnggap6IMl1VXW62+d0kmv7HZ9kB7ADYO3atYOWozl26uzkrNolvbG5Xv4cxnLN1UzN2tcDq4C3JPnkTI+vqj1VNV5V4ytW9P1WrhaQVcvHZtUu6eLmY/lzGMs1twDPVNWZqnoZ2Af8I+D5JCsBuscXhjCWRmzn5o2MLVtyQdvYsiXs3LxxRBVJi9d8LH8OI+SfBd6X5M1JAtwMHAMOANu7fbYD9w9hLI3Y1k2r+cWPvYfVy8cIsHr5GL/4sfd4d410GeZj+XMYa/KPJvka8ARwDjgM7AHeCtyX5DNMvRF8fNCxtDBs3bTaUJeGYNXyMSb6BPowlz+HcndNVf27qvrRqnp3VX2qql6sqr+oqpurakP3+INhjCVJrZiP5c8F9auGJelKMv0v4rm8u8aQl6QRmuvlT393jSQ1zJCXpIYZ8pLUMENekhpmyEtSwwx5SWqYIS9JDTPkJalhhrwkNcyQl6SGGfKS1DBDXpIaZshLUsMMeUlqmCEvSQ0z5CWpYUMJ+STLk3wtyXeSHEvyD5O8PcmDSZ7uHq8exliSpJkb1kz+PwG/V1U/Cvw94BhwB/BwVW0AHu62JUnzaOCQT/I24IPAVwGq6qWqOgtsAfZ2u+0Ftg46liRpdoYxk38ncAb4b0kOJ/mNJG8Brquq0wDd47VDGEuSNAvDCPmlwHuBX6uqTcD/YxZLM0l2JDmU5NCZM2eGUI4kadowQv4kcLKqHu22v8ZU6D+fZCVA9/hCv4Orak9VjVfV+IoVK4ZQjiRp2sAhX1V/DjyXZGPXdDPwFHAA2N61bQfuH3QsSdLsLB3SeX4WuCfJm4DvAp9m6g3kviSfAZ4FPj6ksSRJMzSUkK+qJ4HxPl03D+P8kqTL4zdeJalhhrwkNcyQl6SGGfKS1DBDXpIaZshLUsMMeUlq2LC+DCVJmoH9hyfYffA4p85Osmr5GDs3b2TrptVzNp4hL0nzZP/hCXbtO8Lky+cBmDg7ya59RwDmLOhdrpGkebL74PFXAn7a5Mvn2X3w+JyNachL0jw5dXZyVu3DYMhL0jxZtXxsVu3DYMhL0jzZuXkjY8uWXNA2tmwJOzdvvMgRg/ODV0maJ9Mfrnp3jSQ1auum1XMa6q/lco0kNcyQl6SGGfKS1DBDXpIaNrSQT7IkyeEk3+i2357kwSRPd49XD2ssSdLMDHMm/3ngWM/2HcDDVbUBeLjbliTNo6GEfJI1wD8FfqOneQuwt3u+F9g6jLEkSTM3rJn8fwR+Dvjrnrbrquo0QPd4bb8Dk+xIcijJoTNnzgypHEkSDCHkk3wUeKGqHr+c46tqT1WNV9X4ihUrBi1HktRjGN94fT9wW5KfBP4m8LYk/x14PsnKqjqdZCXwwhDGkiTNwsAz+araVVVrqmodsA34/ar6JHAA2N7tth24f9CxJEmzM5f3yX8Z+FCSp4EPdduSpHk01F9QVlV/CPxh9/wvgJuHeX5J0uz4jVdJapghL0kNM+QlqWGGvCQ1zJCXpIYZ8pLUMENekhpmyEtSwwx5SWqYIS9JDTPkJalhhrwkNcyQl6SGGfKS1DBDXpIaZshLUsMMeUlqmCEvSQ0bOOSTXJ/kD5IcS3I0yee79rcneTDJ093j1YOXK0majWHM5M8B/6aq/i7wPuD2JDcCdwAPV9UG4OFuW5I0jwYO+ao6XVVPdM//EjgGrAa2AHu73fYCWwcdS5I0O0Ndk0+yDtgEPApcV1WnYeqNALj2IsfsSHIoyaEzZ84MsxxJuuINLeSTvBX4HeALVfXDmR5XVXuqaryqxlesWDGsciRJDCnkkyxjKuDvqap9XfPzSVZ2/SuBF4YxliRp5oZxd02ArwLHqupXeroOANu759uB+wcdS5I0O0uHcI73A58CjiR5smv7EvBl4L4knwGeBT4+hLEkSbMwcMhX1f8EcpHumwc9vyTp8vmNV0lqmCEvSQ0z5CWpYYa8JDXMkJekhhnyktQwQ16SGmbIS1LDDHlJapghL0kNM+QlqWGGvCQ1zJCXpIYZ8pLUMENekhpmyEtSwwx5SWqYIS9JDZvzkE9ya5LjSU4kuWOux5MkvWpOQz7JEuA/Ax8BbgQ+keTGuRxTkvSquZ7J3wScqKrvVtVLwL3AljkeU5LUmeuQXw0817N9smt7RZIdSQ4lOXTmzJk5LkeSrixzHfLp01YXbFTtqarxqhpfsWLFHJcjSVeWuQ75k8D1PdtrgFNzPKYkqTPXIf8tYEOS9UneBGwDDszxmJKkztK5PHlVnUvyOeAgsAS4u6qOzuWYkqRXzWnIA1TV7wK/O9fjSJJez2+8SlLDDHlJapghL0kNM+QlqWGGvCQ1zJCXpIYZ8pLUMENekhpmyEtSwwx5SWqYIS9JDTPkJalhhrwkNcyQl6SGGfKS1DBDXpIaZshLUsMMeUlq2EAhn2R3ku8k+eMkX0+yvKdvV5ITSY4n2TxwpZKkWRt0Jv8g8O6q+jHgT4BdAEluBLYB7wJuBf5LkiUDjiVJmqWBQr6qHqiqc93mI8Ca7vkW4N6qerGqngFOADcNMpYkafaGuSb/08A3u+erged6+k52bZKkebT0UjskeQh4R5+uO6vq/m6fO4FzwD3Th/XZvy5y/h3ADoC1a9fOoGRJ0kxdMuSr6pY36k+yHfgocHNVTQf5SeD6nt3WAKcucv49wB6A8fHxvm8EkqTLM+jdNbcCXwRuq6q/6uk6AGxLclWS9cAG4LFBxpIkzd4lZ/KX8KvAVcCDSQAeqarPVtXRJPcBTzG1jHN7VZ0fcCxJ0iwNFPJV9XfeoO8u4K5Bzi9JGozfeJWkhhnyktQwQ16SGmbIS1LDDHlJapghL0kNM+QlqWGGvCQ1zJCXpIYZ8pLUMENekhpmyEtSwwx5SWqYIS9JDTPkJalhhrwkNcyQl6SGGfKS1DBDXpIaNpSQT/Jvk1SSa3radiU5keR4ks3DGEeSNDsD/SFvgCTXAx8Cnu1puxHYBrwLWAU8lOSGqjo/6HiSpJkbxkz+PwA/B1RP2xbg3qp6saqeAU4ANw1hLEnSLAw0k09yGzBRVf8rSW/XauCRnu2TXVu/c+wAdgCsXbt2kHLUsP2HJ9h98Dinzk6yavkYOzdvZOumvi8pST0uGfJJHgLe0afrTuBLwIf7Hdanrfq0UVV7gD0A4+PjfffRlW3/4Ql27TvC5MtTq30TZyfZte8IgEEvXcIlQ76qbunXnuQ9wHpgeha/BngiyU1Mzdyv79l9DXBq4Gp1Rdp98PgrAT9t8uXz7D543JCXLuGy1+Sr6khVXVtV66pqHVPB/t6q+nPgALAtyVVJ1gMbgMeGUrGuOKfOTs6qXdKrBr67pp+qOprkPuAp4Bxwu3fW6HKtWj7GRJ9AX7V8bATVSIvL0L4M1c3ov9+zfVdV/UhVbayqbw5rHF15dm7eyNiyJRe0jS1bws7NG0dUkbR4zMlMXhqm6XV3766RZs+Q16KwddNqQ126DP7uGklqmCEvSQ0z5CWpYYa8JDXMkJekhhnyktQwQ16SGmbIS1LDDHlJapghL0kNM+QlqWGGvCQ1zJCXpIYZ8pLUMENekhpmyEtSwwYO+SQ/m+R4kqNJvtLTvivJia5v86DjSJJmb6C/DJXkHwNbgB+rqheTXNu13whsA94FrAIeSnKDf8xbkubXoDP5nwG+XFUvAlTVC137FuDeqnqxqp4BTgA3DTiWJGmWBg35G4APJHk0yR8l+YmufTXwXM9+J7u210myI8mhJIfOnDkzYDmSpF6XXK5J8hDwjj5dd3bHXw28D/gJ4L4k7wTSZ//qd/6q2gPsARgfH++7jyTp8lwy5Kvqlov1JfkZYF9VFfBYkr8GrmFq5n59z65rgFMD1ipJmqVBl2v2A/8EIMkNwJuA7wMHgG1JrkqyHtgAPDbgWJKkWRro7hrgbuDuJN8GXgK2d7P6o0nuA54CzgG3z+WdNfsPT7D74HFOnZ1k1fIxdm7eyNZNfT8CkKQrykAhX1UvAZ+8SN9dwF2DnH8m9h+eYNe+I0y+PPUeMnF2kl37jgAY9JKueIv+G6+7Dx5/JeCnTb58nt0Hj4+oIklaOBZ9yJ86Ozmrdkm6kiz6kF+1fGxW7ZJ0JVn0Ib9z80bGli25oG1s2RJ2bt44oookaeEY9O6akZv+cNW7ayTp9RZ9yMNU0BvqkvR6i365RpJ0cYa8JDXMkJekhhnyktQwQ16SGpap3ye2MCQ5A/zZiIa/hqnfoLmYWPP8sOb5sxjrXgg1/+2qWtGvY0GF/CglOVRV46OuYzaseX5Y8/xZjHUv9JpdrpGkhhnyktQwQ/5Ve0ZdwGWw5vlhzfNnMda9oGt2TV6SGuZMXpIaZshLUsOu6JBP8ttJnuz++16SJ7v2dUkme/p+fcSlviLJzyeZ6KntJ3v6diU5keR4ks2jrPO1kuxO8p0kf5zk60mWd+0L9loDJLm1u54nktwx6nr6SXJ9kj9IcizJ0SSf79ov+lpZCLqfuSNdbYe6trcneTDJ093j1aOuc1qSjT3X8skkP0zyhQV/nV2Tn5Lkl4H/U1W/kGQd8I2qeveIy3qdJD8P/N+q+qXXtN8I/BZwE7AKeAi4oarOv+4kI5Dkw8DvV9W5JP8eoKq+uMCv9RLgT4APASeBbwGfqKqnRlrYayRZCaysqieS/C3gcWAr8FP0ea0sFEm+B4xX1fd72r4C/KCqvty9qV5dVV8cVY0X0702JoB/AHyaBXydr+iZ/LQkYeoH4rdGXcsAtgD3VtWLVfUMcIKpwF8QquqBqjrXbT4CrBllPTN0E3Ciqr5bVS8B9zJ1nReUqjpdVU90z/8SOAYs1j+wsAXY2z3fy9Sb1UJ0M/CnVTWqb+jPmCE/5QPA81X1dE/b+iSHk/xRkg+MqrCL+Fy37HF3zz9nVwPP9exzkoX7g/7TwDd7thfqtV5M1xSYWv4CNgGPdk39XisLRQEPJHk8yY6u7bqqOg1Tb17AtSOr7o1t48JJ4YK9zs2HfJKHkny7z3+9M7JPcOH/sNPA2qraBPxr4DeTvG2B1PxrwI8AP97V+cvTh/U51byuxc3kWie5EzgH3NM1jfRaX8LIr+lsJHkr8DvAF6rqh1z8tbJQvL+q3gt8BLg9yQdHXdBMJHkTcBvwP7qmBX2dm/jzf2+kqm55o/4kS4GPAX+/55gXgRe7548n+VPgBuDQHJb6ikvVPC3JfwW+0W2eBK7v6V4DnBpyaW9oBtd6O/BR4ObqPgwa9bW+hJFf05lKsoypgL+nqvYBVNXzPf29r5UFoapOdY8vJPk6U8tjzydZWVWnu88aXhhpkf19BHhi+vou9Ovc/Ex+Bm4BvlNVJ6cbkqzoPlghyTuBDcB3R1TfBboX/rR/Bny7e34A2JbkqiTrmar5sfmu72KS3Ap8Ebitqv6qp33BXmumPmjdkGR9N3vbxtR1XlC6z5S+Chyrql/pab/Ya2Xkkryl+5CYJG8BPsxUfQeA7d1u24H7R1PhG7rgX/4L+TrDFTCTn4HXrq0BfBD4hSTngPPAZ6vqB/NeWX9fSfLjTC0bfA/4FwBVdTTJfcBTTC2H3L5Q7qzp/CpwFfDgVCbxSFV9lgV8rbs7gT4HHASWAHdX1dERl9XP+4FPAUfS3QYMfAn4RL/XygJxHfD17rWwFPjNqvq9JN8C7kvyGeBZ4OMjrPF1kryZqbuteq9l35/JhcJbKCWpYS7XSFLDDHlJapghL0kNM+QlqWGGvCQ1zJCXpIYZ8pLUsP8Pg0KTR4+0xqsAAAAASUVORK5CYII=\n", "text/plain": [ "<Figure size 432x288 with 1 Axes>" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plt.plot(X, Y, 'o')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### § ArgParse\n", "\n", "+ [**`argparse`**](https://docs.python.org/3/library/argparse.html) 模組,Python 官網文件 (https://docs.python.org/3/library/argparse.html)\n", "\n", "使用引數(參數)解譯物件,固定步驟是:\n", "1. `parser = argparse.ArgumentParser()` - 建構物件。\n", "2. `parser.add_argument()` - 加入程式想要提供的引數選項。\n", "3. `args = parser.parse_args()` - 解譯後的引數都在 args 屬性裡。\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### § 作業練習\n", "\n", "1. 使用 IDE(如 VSCode)開發,並學習如何使用 IDE 的除錯功能。\n", "2. 【功能一】: 可接受參數指定 (1)產生 N 個隨機座標點及 (2)輸出檔名,但所有的點必須可連成凸多邊形(提示: 使用旋轉轉換),將隨機未排序的點輸出成CSV格式的指定檔名。\n", "3. 【功能二】: 可接受參數指定 (1)輸入CSV檔檔名 (2)是否顯示座標及多邊形的繪圖,座標點讀取後計算多邊形的周長並在畫面輸出結果。\n", "4. 【功能三】: 可接受參數指定讀入JSON檔案,其他所有參數都套用JSON檔案所設定的內容。" ] } ], "metadata": { "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.8.5" } }, "nbformat": 4, "nbformat_minor": 2 }