{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "![](images/python_with_Birds.gif)\n" ] }, { "cell_type": "markdown", "metadata": { "id": "waZDna5nPCfT" }, "source": [ "\n", "# Python Modules - การอิมพอร์ต\n", "\n", "**10** minutes\n", "\n", " **วัตถุประสงค์**\n", "\n", " หลังจากทำทำแล็บ นศ.จะสามารถ \n", "\n", "* นำเข้าโมดูลด้วยรูปแบบต่างๆ ได้\n", "\n", "**Ref:**\n", "* https://docs.python.org/3/reference/import.html\n", "* https://docs.python.org/3/tutorial/modules.html\n", "* https://docs.python.org/3/library/math.html\n", "* https://realpython.com/lessons/scripts-modules-packages-and-libraries/" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "\n", "## การ Import Module\n", "\n", "โดยทั่วไป การเขียนโปรแกรมที่สามารถนำใช้ประโยชน์ได้อย่างจริงจัง โปรแกรมจะมีขนาดใหญ่โดยอัตโนมัติ ดังนั้นจึงมีความจำเป็นต้องแยกโปรแกรมออกเป็นส่วนๆ (หลายๆ ไฟล์) เพื่อให้สามารถจัดการ แก้ไขโปรแกรม จนถึงพัฒนาต่อยอดโปรแกรม ทำได้ง่ายขึ้น\n", "\n", "ในทางปฏิบัติเราจะแยกออกโปรแกรมแต่ละส่วนๆ ออกเป็นไฟล์ (Extension .py) ซึ่งแต่ละไฟล์จะเรียกว่า **โมดูล (module)** เมื่อโปรแกรมถูกแยกออกมาเป็นโมดูลแล้ว โปรแกรมหลัก (Main program) ก็จะต้องนำเข้าข้อมูลหรือออบเจ็กต์ (ซึ่งรวมถึง คำสั่ง คลาส ฟังก์ชัน หรือตัวแปรต่างๆ) ที่อยู่ภายในไฟล์ของโมดูลนั้นๆ เข้ามาด้วยคำสั่ง **import** \n", "\n", "ในภาษาไพธอน เราใช้คำสั่ง **import** นำเข้ามูลหรือออบเจ็กต์ที่อยู่ภายในโมดูลเข้ามายังโปรแกรม\n", "\n", "\n", "```Python\n", "import \n", "```\n", "\n", "ยกตัวอย่างเช่น โมดูล `math` ที่มีฟังก์ชันและค่าคงที่ทางคณิตศาตร์ที่พร้อมที่จะถูกใช้งานอยู่ หากต้องการใช้งานออบเจ็กต์ (ฟังก์ชัน) ต่างๆ ในโมดูล `math` ก็ต้อง**อิมพอร์ต**เข้ามาในโปรแกรมด้วยคำสั่ง `import` หลังจากนั้นก็จะสามารถเรียกใช้ออบเจ็กต์ (ฟังก์ชัน) ในรูปแบบ `math.function_name` `math.object_name`ได้\n", "\n", "(ในการอิมพอร์ตโมดูลเข้ามาในโปรแกรมนั้น Python (interpreter) จะทำการค้นหาโมดูลภายที่มีชื่อดังกล่าวใน Built-in module ก่อนเป็นอันดับแรก ถ้าไม่พบ จะทำการค้นหาไฟล์ module_name.py ในลิสต์ Directory ที่ถูกกำหนดโดยตัวแปร sys.path (ตัวแปร Path เก็บเส้นทางไดเร็กทอรีในรูปแบบของรายการสตริง) โดยจะเริ่มค้นหาใน Directory ที่กำลังใช้งานอยู่ในขณะนั้น และใน Directory ที่กำหนดในตัวแปร PYTHONPATH (Environment variable) ตามลำดับ (https://docs.python.org/3/tutorial/modules.html#the-module-search-path))" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['/Users/tube.sc/Data_KMITL/Courses_onMac/2021_Python/PyBook_v02_4std', '/Users/tube.sc/.pyenv/versions/3.8.13/lib/python38.zip', '/Users/tube.sc/.pyenv/versions/3.8.13/lib/python3.8', '/Users/tube.sc/.pyenv/versions/3.8.13/lib/python3.8/lib-dynload', '', '/Users/tube.sc/.pyenv/versions/3.8.13/lib/python3.8/site-packages']\n" ] } ], "source": [ "# sys.path เป็นตัวแปร Path เก็บเส้นทางไดเร็กทอรี (Directory) ในรูปแบบของลิสต์ของสตริง (List of String) \n", "\n", "import sys\n", "print(sys.path)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "☀︎**โมดูล (Module) หรือ แพคเกจ (Package) หรือ ไลบรารี่ (Library)** เปรียบเสมือนโปรแกรมสำเร็จรูป (อาจจะมีแค่หนึ่งไฟล์หรือสิบไฟล์หรือมากถึงร้อยไฟล์ก็ได้) ไว้เก็บฟังก์ชัน คลาส ตัวแปรและค่าพิเศษต่างๆ เฉพาะทางไว้ \n", "\n", "โมดูลของไพธอนมีทั้งที่ถูกพัฒนาโดยผู้พัฒนาหลัก (Core Developer) และผู้ใช้งานทั่วไป โดยจะถูกอัพโหลดขึ้นไปเก็บไว้ในเซอร์เวอร์ [Python Package Index (เรียกย่อๆว่า \"PyPI\"; the official 3rd-party software repository!)](https://pypi.org/) หรือไม่ก็เซอร์เวอร์ของ [Anaconda Cloud](https://anaconda.org/anaconda-server) \n", "ประโยชน์ของโมดูล คือผู้ใช้งานไม่จำเป็นที่จะต้องสร้างโมดูล (ฟังก์ชันหรือคลาส) ขึ้นมาใหม่เองทั้งหมด แต่สามารถนำโมดูลที่ถูกพัฒนาไว้อยู่แล้วมาใช้งานได้เลย\n", "\n", "* โมดูลที่เป็น 3rd-party สามารถติดตั้ง (Install) ได้เองโดยใช้คำสั่งต่อไปนี้\n", " - pip install \\ สำหรับคนที่ใช้ไพธอนของ Python.org\n", " - conda install \\ สำหรับคนที่ใช้ไพธอนของ Anaconda\n", " \n", "(ในการยกเลิกการติดตั้ง (Unininstall) ก็สามารถทำได้โดยใช้คำสั่ง uninstall )\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**ตัวอย่างของโมดูลยอดนิยมที่ผู้เขียนไพธอนทั่วไปนิยมใช้ (แยกตามประเภทของการใช้งาน) มีดังต่อไปนี้**\n", " \n", "* **การจัดการข้อมูลและวิเคราะห์ข้อมูล (รูปแบบตาราง) (Data Manipulation):** Pandas \n", "* **การดึงข้อมูลจาก web (Web Scraping):** Requests, Selenium, Beautiful Soup, lxml\n", "* **การคำนวณทางคณิตศาสตร์และสถิติ (Mathematics and Statistics):** NumPy (คำนวน Vector และ Matrix), SciPy\n", "* **การสร้างแบบจำลองทางคณิตศาตร์สำหรับเรียนรู้ของเครื่องจักร (Machine Learning Framework):** Scikit-Learn\n", "* **การสร้างแบบจำลองสำหรับการเรียนรู้เชิงลึก(Deep learning):** TensorFlow, Keras (High-level interface of TensorFlow), PyTorch\n", "* **การแสดงผลข้อมูล/พล็อตกราฟ (Data Visualization):** Matplotlib, Seaborn, ggplot\n", "* **การสร้าง GUI (Graphical User Interface/Front-ends/User interface):** TKinter (TKinter + ttk), Streamlit (Web Application)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.4142135623730951\n", "3.141592653589793\n", "0.7071067811865475\n", "1.0\n" ] } ], "source": [ "import math # import ก่อนเรียกใช้เสมอ\n", "print(math.sqrt(2)) # sqrt ฟังก์ชัน square root\n", "print(math.pi) # ค่าของ π\n", "print(math.sin(math.pi/4)) # ฟังก์ชัน sin\n", "print(math.cos(0)) # ฟังก์ชัน cos\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "หากต้องการอิมพอร์ตหลายๆ โมดูลให้อยู่ในบรรทัดเดียวก็สามารถทำได้โดยใช้เครื่องหมายคอมมา `,` คั่น เช่น" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "import math, sys" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `from`\n", "\n", "การใช้งานคำสั่ง `import` จะเป็นการนำทั้งโมดูลเข้ามายังโปรแกรม และการใช้งานข้อมูล (ออบเจ็กต์, ฟังก์ชัน) ในโมดูลจะต้องนำหน้าด้วยชื่อของโมดูลเสมอ ในภาษา Python มีคำสั่ง **`from`** import สำหรับนำข้อมูลบางส่วนภายในโมดูลเข้ามา และสามารถใช้งานฟังก์ชันหรือออบเจ็กต์ต่างๆได้โดยตรงโดยไม่ต้องมีชื่อของโมดูลนำหน้า มาดูตัวอย่างการใช้งานกัน\n", "\n", "\n", "```Python\n", "from import \n", "```\n", "\n", "\n", "ยกตัวอย่างเช่น" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.4142135623730951\n", "3.141592653589793\n", "0.7071067811865475\n", "1.0\n" ] } ], "source": [ "from math import sqrt\n", "print(sqrt(2)) # sqrt ฟังก์ชัน square root\n", "from math import pi\n", "print(pi) # ค่าของ π\n", "from math import sin\n", "print(sin(math.pi/4)) # ฟังก์ชัน sin\n", "from math import cos\n", "print(cos(0)) # ฟังก์ชัน cos " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "หากต้องการอิมพอร์ตหลายๆ ออบเจ็กต์ (ฟังก์ชัน) ที่อยู่โมดูลเดียวกันก็สามารถทำได้โดยใช้เครื่องหมายคอมมา `,` เป็นตัวคั่น " ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-1.2246467991473532e-16" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from math import cos, sin, pi\n", "\n", "sin(pi)/cos(pi)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "หรือนำเข้าทั้งหมดโดยการใช้เครื่องหมายสตาร์ **`*`** (หรือเครื่องหมายดอกจันทร์ (asterisk)) เหมือนในตัวอย่างต่อไปนี้\n", "\n", "\n", "```Python\n", "from import *\n", "```\n", "\n", "\n", "สัญลักษณ์ * จะใช้แทนตัวอักษรใด ๆ ก็ได้ กี่ตัวก็ได้ (wildcards) ของชื่อที่มีในโมดูลนั้นๆ (ไม่ว่าจะเป็นคำสั่ง คลาส ฟังก์ชัน ค่าคงที่ หรือตัวแปรต่างๆ) ยกเว้นชื่อที่ขึ้นต้นด้วยขีดล่าง `_` ดังนั้นการนำเข้าด้วยวิธีนี้จึงไม่ต้องระบุชื่อตอนที่จะเรียกใช้" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "120\n", "2\n", "2.718281828459045\n" ] } ], "source": [ "from math import *\n", "print(factorial(5)) # แฟกทอเรียลของ 5 # ในกรณีที่ import math จะเขียนโค้ดเป็น math.factorial(5)\n", "print(floor(2.31)) # ปัดเศษ 2.31 ลงเป็นจำนวนเต็มที่ใกล้ที่สุด # ในกรณีที่ import math จะเขียนโค้ดเป็น math.floor(2.31)\n", "print(e) # Napier's constant # ในกรณีที่ import math จะเขียนโค้ดเป็น math.e" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "แต่อย่างไรก็ตาม ในการใช้เขียนโปรแกรมจริงๆ ควรหลีกเลี่ยงวิธีนี้ เนื่องจากวิธีดังกล่าวเป็นการนำเข้าออบเจ็กต์ทุกอย่าง (ตัวแปร ฟังก์ชัน คลาส ฯลฯ) ที่มีอยู่ในโมดูลเข้ามาในโปรแกรมหลัก ซึ่ง อาจจะมีชื่อของออบเจ็กต์ที่เราไม่รู้ว่ามีอยู่ในโมดูล และชื่อนั้นซ้ำกับชื่อในโปรแกรมหลัก ทำให้เกิดความขัดแย้งกัน (Name conflict/collision) \n", "\n", "ตัวอย่างเช่น\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "พาย\n", "3.141592653589793\n" ] } ], "source": [ "pi = 'พาย' # กำหนดตัวแปร pi ให้เป็นสตริง \"พาย\"\n", "print(pi) \n", "from math import *\n", "print(pi) # ถูกแทนที่ด้วยค่า pi ของโมดูล math (ชื่อซ้ำกัน ขัดแย้งกัน ชนกัน) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ดังนั้นการเรียกใช้งานในรูปแบบของ ``.`` จึงเป็นวิธีฝึกปฏิบัติที่ดีสำหรับการ import โมดูลเข้ามาในโปรแกรม" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `as`\n", "\n", "เราสามารถนำเข้าโมดูลและตั้งชื่อให้เป็นแบบย่อได้โดยใช้สั่ง **`as`** เมื่อมีการเรียกใช้โมดูลจะเรียกชื่อย่อแทน (Alternative name)\n", "\n", "ยกตัวอย่างเช่น ไลบรารี่ `numpy` มักจะถูกตั้งชื่อย่อเป็น `np`, `pandas` เป็น `pd` และ `matplotlib.pyplot` เป็น `plt` เป็นต้น \n", "\n", "\n", "```python\n", "import as \n", "\n", "from import as \n", "```" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]\n", "[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]\n" ] } ], "source": [ "import numpy\n", "print(numpy.arange(0, 1.0, 0.1)) # สร้างชุดตัวเลขตั้งแต่ 0, 0.1, 0.2, ..., 0.9\n", "import numpy as np\n", "print(np.arange(0, 1.0, 0.1)) # ใช้ชื่อย่อ np แทน" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "นอกจากนี้ ยังสามารถตั้งชื่อให้แต่ละฟังก์ชันได้อีกด้วย" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "120\n", "120\n" ] } ], "source": [ "import math\n", "print(math.factorial(5)) # แฟกทอเรียลของ 5 \n", "from math import factorial as fact # ใช้ชื่อย่อ fact แทน math.factorial\n", "print(fact(5))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [Exercise]\n", "\n", "จงเขียนโค้ดต่อไปนี้ใหม่ ให้สามารถเรียกใช้งานได้โดยที่ไม่ต้องมีชื่อของโมดูล\n", "\n", "\n", "```Python\n", "import math\n", "print(math.sqrt(2))\n", "print(math.sin(math.pi))\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [], "source": [ "# Write your code below and press Shift+Enter to execute\n", "import ...\n", "...\n", "\n", "print(sqrt(2))\n", "print(sin(pi))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": { "id": "77G0KQCTPCfv" }, "source": [ "## Author\n", "\n", "S.C.\n", "\n", "### Change Log\n", "\n", " \n", "| Date | Version | Change Description |\n", "|---|---|---|\n", "| 25-12-2021 | 0.1 | First edition |\n", "| | | |\n", "| | | |\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel(3.8.13))", "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.13" }, "latex_envs": { "LaTeX_envs_menu_present": true, "autoclose": false, "autocomplete": true, "bibliofile": "biblio.bib", "cite_by": "apalike", "current_citInitial": 1, "eqLabelWithNumbers": true, "eqNumInitial": 1, "hotkeys": { "equation": "Ctrl-E", "itemize": "Ctrl-I" }, "labels_anchors": false, "latex_user_defs": false, "report_style_numbering": false, "user_envs_cfg": false }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }