== สารบัญ ==
๛ รู้จักกับมอดูลให้มากขึ้นอีกสักหน่อย
๛ การเตรียมไฟล์สำหรับทำเป็นมอดูล
๛ การสร้างตัวแปรและฟังก์ชันภายในมอดูล
๛ ข้อยกเว้นในการใช้ from import *
๛ การสร้างคลาสภายในมอดูล
๛ ไฟล์ .pyc
๛ การโหลดมอดูลใหม่
๛ การรันไฟล์โดยไม่ต้องทำเป็นมอดูล
๛ สรุปเนื้อหา
ใน
บทที่ ๑๕ ได้พูดถึงเรื่องการเรียกใช้มอดูลไปแล้ว ได้พูดถึงไปว่ามอดูลคืออะไร ทำงานยังไง ประกอบไปด้วยอะไร
หลังจากที่ได้เรียนรู้การใช้มอดูลที่ติดตัวโปรแกรมมารวมถึงมอดูลที่คนอื่นสร้างขึ้นไปแล้ว สำหรับในบทนี้ได้เวลาที่จะเริ่มลองสร้างมอดูลขึ้นมาเองบ้าง
รู้จักกับมอดูลให้มากขึ้นอีกสักหน่อย介 ดังที่ได้กล่าวไปแล้วว่ามอดูลนั้นมีทั้งมอดูลพื้นฐานที่มีติดตัวอยู่แล้วแต่แรก เช่น
math
,
sys
,
os
,
random
และอีกชนิดคือมอดูลเพิ่มเติมที่ถูกสร้างโดยคนที่ไม่ได้เกี่ยวข้องกับกลุ่ม ที่พัฒนาภาษาไพธอนโดยตรง
มอดูลเสริมเพิ่มเติมที่นิยมกันมากเช่น
numpy
,
scipy
,
matplotlib
เป็นต้น โดยทั่วไปแล้วมีโครงสร้างที่ซับซ้อน ถูกสร้างขึ้นโดยกลุ่มคนหรืออาจเป็นบริษัทใหญ่ซึ่งมีความเชี่ยวชาญเฉพาะทาง เป็นอย่างดี
อย่างไรก็ตาม ความจริงแล้วมอดูลเป็นสิ่งที่สร้างขึ้นได้อย่างง่ายๆ แค่คนเดียวก็สามารถสร้างขึ้นเองได้ เพราะที่จริงแค่เขียนโปรแกรมด้วยภาษาไพธอนสร้างไฟล์
.py ขึ้นมาอันหนึ่ง เพียงเท่านี้ก็สามารถกลายเป็นมอดูลได้แล้ว
เพียงแต่ว่าโดยทั่วไปเวลาที่เราเขียนโปรแกรมขึ้นมาเราจะให้มันทำงานโดยสั่งรันธรรมดา แบบนั้นจะไม่เรียกว่าเป็นมอดูล แต่เป็นโปรแกรมธรรมดา
แต่ไฟล์โปรแกรมธรรมดานี้จะกลายมาเป็นมอดูลเมื่อมันถูกเรียกให้ทำงานโดยใช้คำสั่ง
import
เข้ามาในโปรแกรมอื่น
เพียงแต่ว่ามอดูลมีวิธีการสร้างอยู่หลากหลาย อาจถูกเขียนขึ้นด้วยภาษาไพธอนเอง หรือใช้ภาษาอื่นเช่นภาษาซี หรือมีโปรแกรมอื่นมาประกอบด้วยก็เป็นได้
ในที่นี้จะกล่าวถึงเฉพาะการสร้างมอดูลอย่างง่าย คือการสร้างมอดูลโดยเขียนโค้ดภาษาไพธอนด้วยความรู้แค่เท่าที่ได้กล่าวไปในบทที่ผ่านๆมา
หากไปดูในโฟลเดอร์ที่เก็บไฟล์มอดูลต่างๆจะเห็นว่าประกอบไปด้วยไฟล์ต่างๆมากมาย ซึ่งส่วนใหญ่ก็เป็น
.py ที่เราคุ้นเคยนั่นเอง และอาจประกอบด้วยไฟล์ชนิดอื่นๆปนอยู่บ้าง
มอดูลที่ประกอบขึ้นจากหลายๆไฟล์มารวมอยู่ในโฟลเดอร์หนึ่ง (และอาจมีโฟลเดอร์ย่อยในนั้นอีก) จะเรียกว่าเป็นแพ็กเกจ (package)
อย่างไรก็ตามมอดูลอย่างง่ายที่สุดนั้นอาจประกอบขึ้นจากไฟล์
.py เพียงไฟล์เดียวก็ได้ ในที่นี้จะขอเริ่มจากมอดูลจากไฟล์
.py ไฟล์เดียว แล้วในบทต่อมาจึงพูดถึงการนำหลายไฟล์มารวมกันเป็นแพ็กเกจ
การเตรียมไฟล์สำหรับทำเป็นมอดูล介 ไฟล์ที่ต้องการจะใช้เป็นมอดูลนั้นไม่ใช่ว่าวางไว้ที่ไหนในเครื่องก็สามารถเรียกใช้ได้ทันที เพราะจำเป็นจะต้องถูกวางไว้ในโฟลเดอร์ที่อยู่ในพาธ (path) ที่ถูกกำหนดไว้
พาธที่วางมอดูลได้นั้นมีอยู่หลายแห่ง สามารถดูได้โดยจะอยู่ในตัวแปรที่ชื่อว่า
path
ของมอดูล
sys
ผลที่ได้ก็คือลิสต์ของพาธทั้งหมดที่เก็บมอดูล
หากเรานำไฟล์โปรแกรมที่เราเขียนไว้ไปวางตามโฟลเดอร์ไหนสักแห่งที่อยู่ในลิสต์นั้นไฟล์นั้นก็จะสามารถถูกเรียกใช้ในฐานะมอดูลได้
อย่างไรก็ตามมีวิธีที่ง่ายกว่านั้น เพราะลิสต์
sys.path
สามารถเพิ่มสมาชิกเข้าไปได้ หมายความว่าถ้าเราใส่พาธของโฟลเดอร์ที่ต้องการจะใช้ลงไป โฟลเดอร์นั้นก็จะกลายเป็นพาธสำหรับใส่มอดูลได้
การเพิ่มสมาชิกในลิสต์ก็เหมือนลิสต์ทั่วไป สามารถใช้เมธอด
.append
เช่น
เท่านี้โฟลเดอร์
nana ก็จะสามารถเก็บไฟล์ที่จะใช้เป็นมอดูลได้แล้ว
หรือความจริงแล้วมีวิธีที่ง่ายกว่านั้นอีก ซึ่งจะทำให้ไม่ต้องไปวุ่นวายกับเรื่องพาธเลย นั่นก็คือการใส่มอดูลเอาไว้ในโฟลเดอร์เดียวกับโปรแกรมหลักที่ต้องการรัน ไฟล์นั้นจะสามารถใช้เป็นมอดูลได้ทันที
ตัวอย่างเช่น ลองสร้างไฟล์
momo.py แล้วพิมพ์โค้ดสั้นๆตามนี้ลงไปแล้วเซฟ
เท่านี้ก็จะได้มอดูลที่ชื่อว่า
momo
ชื่อของโมดูลก็จะตรงกับชื่อของไฟล์ (โดยไม่รวม
.py) ซึ่งชื่อนี้เป็นชื่อที่จะต้องใช้เวลาที่
import
ในโปรแกรมอื่น
จากนั้นเขียนอีกไฟล์ชื่ออะไรก็ได้แล้วเซฟไว้ในโฟลเดอร์เดียวกัน
จากนั้นก็รันไฟล์นี้ ผลลัพธ์ที่ได้ก็คือมีข้อความขึ้นว่า
จะเห็นว่าพอสั่ง
import
คำสั่งที่ถูกเขียนไว้ในไฟล์ที่เป็นมอดูลก็จะทำงานทันที เปรียบเสมือนว่าเราไปดึงโค้ดจากมอดูลมาทำงานในโปรแกรมโดยตรงเลยนั่นเอง
ขั้นตอนการสร้างมอดูลไปจนถึงการเรียกใช้อย่างง่ายสุดนั้นก็มีเพียงเท่านี้ อย่างไรก็ตาม ดังที่เราจะเห็นตัวอย่างได้จากมอดูลทั่วๆไปที่มีอยู่แล้วที่คุ้นเคยกันดี การใช้งานมอดูลมักจะใช้เพื่อประกาศฟังก์ชันหรือตัวแปรหรือคลาสเพื่อจะมา เรียกใช้
เช่นเวลาเราสั่ง
import math
จะพบว่าไม่มีอะไรเกิดขึ้น แต่หลังจากนั้นเราก็สามารถใช้ฟังก์ชันและตัวแปรต่างๆในมอดูลนี้ได้ทันที เช่นตัวแปร
math.pi
ฟังก์ชัน
math.sin()
นั่นเป็นเพราะว่าภายในมอดูลนี้ได้มีการนิยามตัวแปรและฟังก์ชันไว้นั่นเอง
การสร้างตัวแปรและฟังก์ชันภายในมอดูล介 เราสามารถประกาศตัวแปรขึ้นมาภายในมอดูลได้โดยใช้วิธีเหมือนการประกาศตัวแปรทั่วไป
ฟังก์ชันก็สามารถประกาศได้เช่นเดียวกับฟังก์ชันทั่วไป นั่นคือใช้
def
ตัวอย่าง ลองพิมพ์ใน
momo.py ว่า
จากนั้นพิมพ์ตามนี้ในอีกไฟล์ที่อยู่ในโฟลเดอร์เดียวกันแล้วรัน
ก็จะได้
จะเห็นว่าเวลาที่เรียกใช้ตัวแปรหรือฟังก์ชันที่มาจากมอดูลจะต้องมีชื่อมอดูลนั้นนำแล้วตามด้วยจุดแล้วค่อยต่อด้วยชื่อตัวแปรหรือฟังก์ชันนั้น ซึ่งก็เป็นในทำนองเดียวกับที่เราต้องพิมพ์
math.pi
และ
math.sin
เพื่อเรียกใช้
pi
และ
sin
ที่อยู่ในมอดูล
math
นั่นเอง
และในทำนองเดียวกันก็สามารถใช้
from
เพื่อที่จะใช้ตัวแปรและฟังก์ชันจากมอดูลนั้นได้โดยไม่ต้องนำด้วยชื่อมอดูล
ข้อยกเว้นในการใช้ from import *介 กฎการตั้งชื่อมอดูลและฟังก์ชันในมอดูลนั้นก็คล้ายกับการตั้งชื่อตัวแปรหรือ ฟังก์ชันหรือคลาสทั่วไป คือจะใช้อักษรภาษาอะไรก็ได้แต่ห้ามขึ้นต้นด้วยตัวเลขหรือใช้สัญลักษณ์พิเศษ นอกเหนือจากขีดล่าง
_
อย่างไรก็ตามการตั้งชื่อตัวแปรหรือฟังก์ชันให้ ขึ้นต้นด้วยขีดล่าง
_
นั้นมีนัยสำคัญบางอย่าง ซึ่งจะเกิดขึ้นเมื่อใช้
from
และดอกจัน
*
เพื่อเรียกใช้มอดูล
โดยทั่วไปหากใช้
from
และดอกจัน
*
แบบนี้จะเป็นการนำเข้าตัวแปรและฟังก์ชันทั้งหมดที่ประกาศในมอดูลนั้น
แต่มีข้อยกเว้นอยู่เล็กน้อย นั่นคือชื่อตัวแปรและฟังก์ชันที่ขึ้นต้นด้วย
_
จะไม่ถูกอ่าน
ลองแก้ใน
momo.py เป็น
แล้วลองรัน
ก็จะได้ว่า
การตั้งชื่อให้ขึ้นต้นด้วย
_
นั้นจึงมีนัยสำคัญในกรณีนี้ จะเป็นชื่อฟังก์ชันหรือชื่อคลาสก็มีผลเหมือนกัน
แต่หากเปลี่ยนเป็นพิมพ์ชื่อของตัวแปรลงไปแทนที่จะใช้ดอกจัน
*
หรือ
แบบนี้ก็จะสามารถใช้ตัวแปรนี้ได้ตามปกติ
อนึ่ง แม้ว่าตัวแปรที่ชึ้นต้นด้วย
_
จะไม่ถูกอ่านเมื่อถูกดึงเข้ามาในมอดูล แต่ก็สามารถเรียกใช้ผ่านฟังก์ชันภายในมอดูลนั้นได้ตามปกติ
เช่นแก้ใน
momo.py เป็น
จากนั้นรัน
ฟังก์ชัน
phim_akson_thai
ก็จะไปเรียกใช้ตัวแปร
_akson_thai
มาแสดงผลได้ตามปกติ เพราะมอดูลก็เหมือนเป็นโปรแกรมหนึ่ง การทำงานภายในตัวมอดูลนั้นไม่ต่างจากการทำงานโดยการรันโดยตรง ชื่อตัวแปรในนั้นก็ต้องไม่เติมชื่อมอดูลนำหน้าด้วย
การสร้างคลาสภายในมอดูล介 คลาสก็เช่นเดียวกับตัวแปรและฟังก์ชัน สามารถสร้างขึ้นมาใช้ได้
ตัวอย่าง ลองสร้างไฟล์ชื่อ
dudu.py ขึ้นมาพิมพ์ว่า
จากนั้นก็สร้างไฟล์ที่อยู่ในโฟลเดอร์เดียวกัน พิมพ์ตามนี้แล้วรัน
ผลที่ได้
ไฟล์ .pyc介 หลังจากที่ไฟล์
.py ถูกเรียกใช้ในฐานะมอดูลไปแล้วก็จะมีการสร้างไฟล์
.pyc ปรากฏขึ้นมาในโฟลเดอร์เดียวกันกับไฟล์
.py ที่ถูกรัน หรืออาจมีการสร้างโฟล์เดอร์ขึ้นใหม่แล้วมีไฟล์
.pyc ชื่อไฟล์จะต่างกันไปตามโปรแกรมและเวอร์ชันของโปรแกรมที่เราใช้คอมไพล์
ภาพนี้เป็นกรณีที่ใช้ไพธอน 3.11 เมื่อไฟล์ชื่อ
momo.py ถูกเรียกใช้ในฐานะมอดูล จะเกิดโฟล์เดอร์
__pycache__ ขึ้นและมีไฟล์ชื่อ
momo.cpython-311.pyc อยู่ในนั้น
ไฟล์
.pyc นี้เป็นไฟล์
.py ที่ผ่านการคอมไพล์แล้ว ที่มันถูกสร้างขึ้นมาก็เพื่อว่าเวลาที่มีการเรียกใช้ใหม่อีกครั้งจะไม่ต้อง มีการคอมไพล์ใหม่แต่เรียกใช้ไฟล์
.pyc นี้โดยตรงเลย ซึ่งจะทำให้เรียกใช้ได้เร็วขึ้น
ขอเน้นว่าที่ว่าเร็วขึ้นในที่นี้ไม่ได้หมายถึงทำให้คำสั่งในมอดูลทำงานเร็วขึ้น เพียงแต่จะทำให้เร็วในตอนที่โหลดมอดูลใช้เท่านั้น แต่เมื่อโหลดมาแล้วการใช้ฟังก์ชันหรือคลาสต่างๆจากมอดูลนั้นก็ไม่ได้เร็วขึ้น
ตราบใดที่ไม่มีการแก้ไขไฟล์
.py ไป เวลาที่มอดูลนั้นถูกเรียกใช้ก็จะไม่มีการอ่านไฟล์
.py ซ้ำแต่จะไปอ่าน
.pyc โดยตรง แต่หากมีการแก้ไฟล์
.py เมื่อไหร่จึงจะมีการอ่านไฟล์
.py ซ้ำเพื่อคอมไพล์และสร้าง
.pyc ขึ้นมาใหม่
การโหลดมอดูลใหม่介 หากเราเรียกใช้มอดูลผ่านเชลโต้ตอบโดยไม่ได้เรียกใช้จากไฟล์โดยตรง (คือใช้อินเทอร์พรีเตอร์ แทนที่จะใช้อีดิเตอร์เขียนแล้วสั่งรันไฟล์) กรณีแบบนี้หากมีการ
import
มอดูลอะไรไปครั้งหนึ่งแล้ว มอดูลนั้นจะไม่สามารถ
import
ซ้ำได้อีก
นั่นหมายความว่าต่อให้มีการแก้ไขไฟล์มอดูลนั้นไปแล้วกด
import
ซ้ำ ความเปลี่ยนแปลงนั้นก็จะไม่แสดงผลให้เห็น
หากต้องการให้มีการ
reload
จะต้องใช้ฟังก์ชัน
reload
ซึ่งอยู่ในมอดูล
importlib
มอดูล
importlib
นั้นเป็นมอดูลที่เก็บฟังก์ชันต่างๆที่เกี่ยวกับการเรียกใช้มอดูล ยังมีฟังก์ชันอีกหลายอันที่ใช้ประโยชน์ได้
การ
reload
นั้นจำเป็นต้องใช้แค่ในกรณีที่
import
ด้วยเชลเท่านั้น ดังนั้นการแก้ปัญหาอาจทำได้ด้วยการ
import
จากการรันไฟล์
การรันไฟล์โดยไม่ต้องทำเป็นมอดูล介 ในส่วนท้ายนี้ขอเสริมเนื้อหาที่อาจจะไม่ใช่เรื่องของมอดูล แต่มีความเกี่ยวข้องกัน
การนำโค้ดจากไฟล์อื่นมาใช้งานนอกจากการทำให้ไฟล์นั้นเป็นมอดูลแล้วยังมีอีกวิธีหนึ่ง นั่นคือใช้ฟังก์ชัน
exec
อ่านไฟล์
exec
เป็นฟังก์ชันที่นำสายอักขระมาอ่านประมวลผลเป็นโค้ด
จะได้
ซึ่งผลเหมือนกับการที่เรารันโค้ด
ดังนั้นเราสามารถใช้
open
เพื่อเปิดไฟล์ แล้วก็ใช้
exec
เพื่อประมวลผลข้อความในไฟล์นั้นในฐานะโค้ด
เพียงเท่านี้ก็จะได้ผลเหมือนเราคัดลอกโค้ดจากไฟล์
momo.py มาแปะวางโดยที่ไม่ต้องทำให้
momo.py เป็นมอดูล
นอกจากฟังก์ชัน
exec
แล้วหากโค้ดมีแค่บรรทัดเดียวเราอาจใช้ฟังก์ชัน
eval
ได้ด้วย
eval
จะทำงานเหมือนกับ
exec
เพียงแต่ว่าจะอ่านโค้ดได้แค่บรรทัดเดียว การใช้มีข้อจำกัดกว่า
exec
มาก
ตัวอย่าง
สรุปเนื้อหา介 ในบทนี้ได้พูดถึงการใช้ไฟล์มาสร้างเป็นมอดูลแล้ว ซึ่งสามารถทำได้ไม่ยาก ตรงไปตรงมา
แต่มอดูลโดยมากมักไม่ได้สร้างจากไฟล์เดียวแต่ประกอบขึ้นจากไฟล์เป็นจำนวนมาก ซึ่งเรียกว่าการรวมเป็นแพ็กเกจ เนื้อหาตรงนี้จะพูดถึงต่อในบทหน้า
อ้างอิง