ข้ามไปยังเนื้อหาหลัก

ฟังก์ชันใน Python: วิธีเรียกใช้และเขียนฟังก์ชัน

ค้นพบวิธีเขียนฟังก์ชัน Python ที่นำกลับมาใช้ซ้ำและมีประสิทธิภาพ เชี่ยวชาญพารามิเตอร์ คำสั่ง return และหัวข้อขั้นสูงอย่างฟังก์ชันแลมบ์ดา จัดโค้ดให้เป็นระเบียบยิ่งขึ้นด้วย main() และแนวปฏิบัติที่ดีอื่น ๆ
อัปเดตแล้ว 18 พ.ค. 2569  · 14 นาที อ่าน
แบนเนอร์ทักษะ Python เพื่อสร้างอาชีพกับ DataCamp

ฟังก์ชันเป็นส่วนสำคัญของภาษาโปรแกรม Python: อาจเคยพบและใช้งานฟังก์ชันมากมายที่มีมาให้ในภาษา Python หรือที่มาพร้อมระบบนิเวศไลบรารี อย่างไรก็ตาม ในฐานะนักวิทยาศาสตร์ข้อมูล จะต้องเขียนฟังก์ชันของตนเองอยู่เสมอเพื่อแก้ปัญหาที่เกิดจากข้อมูลของคุณ 

บทช่วยสอนนี้ใช้ไวยากรณ์ Python 3 ตัวอย่างทั้งหมดทำงานบน Python 3.10+ และได้รับการอัปเดตให้สะท้อนแนวปฏิบัติสมัยใหม่แล้ว (f-strings, type hints, พารามิเตอร์แบบ positional-only และ keyword-only) เวอร์ชันเสถียรปัจจุบันคือ Python 3.14

หากต้องการรันโค้ดตัวอย่างทั้งหมดในบทช่วยสอนนี้ได้อย่างง่ายดาย สามารถสร้างสมุดงาน DataLab ได้ฟรี ที่ติดตั้ง Python ไว้ล่วงหน้าและมีโค้ดตัวอย่างทั้งหมด สำหรับการฝึกเขียนฟังก์ชัน Python เพิ่มเติม ลองดูแบบฝึกหัดเชิงปฏิบัติของ DataCamp นี้ หรือเรียนคอร์ส Python Data Science Toolbox!

ฟังก์ชันใน Python

ในการเขียนโปรแกรมจะใช้ฟังก์ชันเพื่อรวมชุดคำสั่งที่ต้องการใช้ซ้ำ หรือที่เนื่องจากความซับซ้อนแล้วควรแยกเป็นโปรแกรมย่อยและเรียกใช้เมื่อจำเป็น นั่นหมายความว่าฟังก์ชันคือส่วนของโค้ดที่เขียนขึ้นเพื่อทำงานตามที่ระบุไว้ เพื่อทำงานนั้น ฟังก์ชันอาจต้องการหรือไม่ต้องการอินพุตหลายตัวก็ได้ เมื่อทำงานเสร็จ ฟังก์ชันอาจคืนค่าหนึ่งค่าหรือหลายค่าก็ได้

ใน Python มีฟังก์ชันอยู่สามประเภท:

  • ฟังก์ชันที่มีมาให้แล้ว (Built-in) เช่น help() เพื่อขอความช่วยเหลือ, min() เพื่อหาค่าต่ำสุด, print() เพื่อพิมพ์วัตถุไปยังเทอร์มินัล เป็นต้น สามารถดูภาพรวมของฟังก์ชันเหล่านี้เพิ่มเติมได้ ที่นี่

  • ฟังก์ชันที่ผู้ใช้กำหนดเอง (User-Defined Functions: UDFs) คือฟังก์ชันที่ผู้ใช้สร้างขึ้นเพื่อช่วยงานของตน และ

  • ฟังก์ชันนิรนาม ซึ่งเรียกอีกอย่างว่าฟังก์ชันแลมบ์ดา เพราะไม่ได้ประกาศด้วยคีย์เวิร์ดมาตรฐาน def

ฟังก์ชัน vs เมธอด

เมธอดหมายถึงฟังก์ชันที่เป็นส่วนหนึ่งของคลาส ต้องเข้าถึงผ่านอินสแตนซ์หรืออ็อบเจ็กต์ของคลาส ฟังก์ชันไม่มีข้อจำกัดนี้: เป็นฟังก์ชันแบบสแตนด์อโลน นั่นหมายความว่าเมธอดทุกตัวเป็นฟังก์ชัน แต่ฟังก์ชันไม่ใช่เมธอดเสมอไป

พิจารณาตัวอย่างนี้ ที่กำหนดฟังก์ชัน plus() ก่อน จากนั้นกำหนดคลาส Summation พร้อมเมธอด sum():

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6IiMgRGVmaW5lIGEgZnVuY3Rpb24gYHBsdXMoKWBcbmRlZiBwbHVzKGEsYik6XG4gIHJldHVybiBhICsgYlxuICBcbiMgQ3JlYXRlIGEgYFN1bW1hdGlvbmAgY2xhc3NcbmNsYXNzIFN1bW1hdGlvbihvYmplY3QpOlxuICBkZWYgc3VtKHNlbGYsIGEsIGIpOlxuICAgIHNlbGYuY29udGVudHMgPSBhICsgYlxuICAgIHJldHVybiBzZWxmLmNvbnRlbnRzICJ9

หากต้องการเรียกใช้เมธอด sum() ที่เป็นส่วนหนึ่งของคลาส Summation จะต้องนิยามอินสแตนซ์หรืออ็อบเจ็กต์ของคลาสนั้นก่อน มาสร้างอ็อบเจ็กต์ดังกล่าวกัน:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiZGVmIHBsdXMoYSxiKTpcbiAgcmV0dXJuIGEgKyBiXG4gIFxuY2xhc3MgU3VtbWF0aW9uKG9iamVjdCk6XG4gIGRlZiBzdW0oc2VsZiwgYSwgYik6XG4gICAgc2VsZi5jb250ZW50cyA9IGEgKyBiXG4gICAgcmV0dXJuIHNlbGYuY29udGVudHMgIiwic2FtcGxlIjoiIyBJbnN0YW50aWF0ZSBgU3VtbWF0aW9uYCBjbGFzcyB0byBjYWxsIGBzdW0oKWBcbnN1bUluc3RhbmNlID0gU3VtbWF0aW9uKClcbnN1bUluc3RhbmNlLnN1bSgxLDIpIn0=

จำไว้ว่าการสร้างอินสแตนซ์นี้ไม่จำเป็นเมื่อจะเรียกใช้ฟังก์ชัน plus() สามารถรัน plus(1,2) ในส่วนโค้ด DataCamp Light ได้โดยไม่มีปัญหา!

พารามิเตอร์ vs อาร์กิวเมนต์

พารามิเตอร์คือชื่อที่ใช้เมื่อกำหนดฟังก์ชันหรือเมธอด และจะถูกแมปกับอาร์กิวเมนต์ กล่าวอีกนัยหนึ่ง อาร์กิวเมนต์คือสิ่งที่ส่งให้กับการเรียกใช้ฟังก์ชันหรือเมธอด ขณะที่โค้ดของฟังก์ชันหรือเมธอดจะอ้างถึงอาร์กิวเมนต์เหล่านั้นด้วยชื่อพารามิเตอร์

พิจารณาตัวอย่างต่อไปนี้และย้อนกลับไปดูส่วน DataCamp Light ด้านบน: คุณส่งอาร์กิวเมนต์สองตัวไปยังเมธอด sum() ของคลาส Summation แม้ว่าก่อนหน้านี้จะกำหนดพารามิเตอร์ไว้สามตัว ได้แก่ self, a และ b

self หายไปไหน?

อาร์กิวเมนต์ตัวแรกของเมธอดในคลาสทุกตัวจะเป็นการอ้างอิงไปยังอินสแตนซ์ปัจจุบันของคลาส ซึ่งในที่นี้คือ Summation ตามธรรมเนียมจะเรียกอาร์กิวเมนต์นี้ว่า self

ทั้งหมดนี้หมายความว่าไม่ต้องส่งการอ้างอิงไปยัง self ในกรณีนี้ เพราะ self เป็นชื่อพารามิเตอร์สำหรับอาร์กิวเมนต์ที่ส่งโดยปริยาย ซึ่งอ้างถึงอินสแตนซ์ที่ใช้เรียกเมธอด มันจะถูกแทรกเข้าไปในรายการอาร์กิวเมนต์โดยอัตโนมัติ

วิธีนิยามฟังก์ชัน: ฟังก์ชันที่ผู้ใช้กำหนดเอง (UDFs)

สี่ขั้นตอนในการนิยามฟังก์ชันใน Python มีดังนี้:

  1. ใช้คีย์เวิร์ด def เพื่อประกาศฟังก์ชัน แล้วตามด้วยชื่อฟังก์ชัน

  2. เพิ่มพารามิเตอร์ให้กับฟังก์ชัน: ควรอยู่ในวงเล็บของฟังก์ชัน ลงท้ายบรรทัดด้วยโคลอน

  3. เพิ่มคำสั่งที่ฟังก์ชันควรดำเนินการ

  4. จบฟังก์ชันด้วยคำสั่ง return หากฟังก์ชันต้องการส่งผลลัพธ์ออกมา หากไม่มีคำสั่ง return ฟังก์ชันจะคืนค่าเป็นอ็อบเจ็กต์ None

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6ImRlZiBoZWxsbygpOlxuICBwcmludChcIkhlbGxvIFdvcmxkXCIpIFxuICByZXR1cm4gIn0=

แน่นอนว่าเมื่อทำไป ฟังก์ชันจะซับซ้อนขึ้น: สามารถเพิ่ม for loop การควบคุมโฟลว์ ฯลฯ เพื่อให้ละเอียดขึ้นได้:

def hello():
    name = input("Enter your name: ")
    if name:
        print(f"Hello {name}")
    else:
        print("Hello World")

hello()

ในฟังก์ชันข้างต้น จะให้ผู้ใช้กรอกชื่อ หากไม่มีการกรอกชื่อ ฟังก์ชันจะพิมพ์ “Hello World” มิฉะนั้น ผู้ใช้จะได้รับคำทักทายแบบระบุชื่อ

โปรดจำไว้ด้วยว่าสามารถกำหนดพารามิเตอร์หนึ่งตัวหรือมากกว่าสำหรับ UDF ได้ จะได้เรียนรู้เพิ่มเติมเมื่อเข้าสู่หัวข้ออาร์กิวเมนต์ของฟังก์ชัน นอกจากนี้ ฟังก์ชันอาจคืนค่าหนึ่งค่าหรือหลายค่าก็ได้

คำสั่ง return

สังเกตว่าเนื่องจากพิมพ์บางอย่างใน UDF hello() อยู่แล้ว จึงไม่จำเป็นต้องคืนค่า จะไม่เห็นความแตกต่างระหว่างฟังก์ชันด้านบนกับฟังก์ชันนี้:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6ImRlZiBoZWxsb19ub3JldHVybigpOlxuICBwcmludChcIkhlbGxvIFdvcmxkXCIpICJ9

อย่างไรก็ตาม หากต้องการทำงานต่อกับผลลัพธ์ของฟังก์ชันและลองทำโอเปอเรชันกับมัน จะต้องใช้คำสั่ง return เพื่อคืนค่าจริง เช่น สตริง จำนวนเต็ม เป็นต้น พิจารณาสถานการณ์ต่อไปนี้ ซึ่ง hello() คืนค่าสตริง "hello" ในขณะที่ฟังก์ชัน hello_noreturn() คืนค่า None:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6ImRlZiBoZWxsbygpOlxuICBwcmludChcIkhlbGxvIFdvcmxkXCIpIFxuICByZXR1cm4oXCJoZWxsb1wiKVxuXG5kZWYgaGVsbG9fbm9yZXR1cm4oKTpcbiAgcHJpbnQoXCJIZWxsbyBXb3JsZFwiKVxuICBcbiMgTXVsdGlwbHkgdGhlIG91dHB1dCBvZiBgaGVsbG8oKWAgd2l0aCAyIFxuaGVsbG8oKSAqIDJcblxuIyAoVHJ5IHRvKSBtdWx0aXBseSB0aGUgb3V0cHV0IG9mIGBoZWxsb19ub3JldHVybigpYCB3aXRoIDIgXG5oZWxsb19ub3JldHVybigpICogMiJ9

ฟังก์ชันที่สองจะเกิดข้อผิดพลาดเพราะไม่สามารถทำโอเปอเรชันใด ๆ กับ None ได้ จะได้รับ TypeError ระบุว่าไม่สามารถทำการคูณระหว่าง NoneType (None ที่เป็นผลจาก hello_noreturn()) กับ int (2)

เคล็ดลับ ฟังก์ชันจะออกจากการทำงานทันทีเมื่อพบคำสั่ง return แม้ว่าจะไม่ได้คืนค่าใด ๆ ก็ตาม:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6ImRlZiBydW4oKTpcbiAgZm9yIHggaW4gcmFuZ2UoMTApOlxuICAgICBpZiB4ID09IDI6XG4gICAgICAgcmV0dXJuXG4gIHByaW50KFwiUnVuIVwiKVxuICBcbnJ1bigpIn0=

อีกประเด็นที่ควรกล่าวถึงเมื่อทำงานกับคำสั่ง return คือสามารถใช้เพื่อคืนค่าหลายค่าได้ โดยทำผ่านทูเพิล

โปรดจำไว้ว่าโครงสร้างข้อมูลนี้คล้ายกับลิสต์มาก: สามารถมีหลายค่า แต่ทูเพิลเป็นแบบเปลี่ยนค่าไม่ได้ (immutable) หมายความว่าไม่สามารถแก้ไขค่าที่เก็บอยู่ได้ สร้างได้ด้วยวงเล็บคู่ () สามารถแตกทูเพิลไปยังตัวแปรหลายตัวได้ด้วยเครื่องหมายจุลภาคและโอเปอเรเตอร์กำหนดค่า

ดูตัวอย่างต่อไปนี้เพื่อทำความเข้าใจว่าฟังก์ชันของคุณสามารถคืนค่าหลายค่าได้อย่างไร:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6IiMgRGVmaW5lIGBwbHVzKClgXG5kZWYgcGx1cyhhLGIpOlxuICBzdW0gPSBhICsgYlxuICByZXR1cm4gKHN1bSwgYSlcblxuIyBDYWxsIGBwbHVzKClgIGFuZCB1bnBhY2sgdmFyaWFibGVzIFxuc3VtLCBhID0gcGx1cygzLDQpXG5cbiMgUHJpbnQgYHN1bSgpYFxucHJpbnQoc3VtKSJ9

หมายเหตุ คำสั่ง return อย่าง return sum, a จะให้ผลเหมือนกับ return (sum, a): แบบแรกจริง ๆ แล้วแพ็ก sum และ a เข้าเป็นทูเพิลเบื้องหลัง!

วิธีเรียกใช้ฟังก์ชัน

ในส่วนก่อนหน้าได้เห็นตัวอย่างมากมายแล้วว่าการเรียกใช้ฟังก์ชันทำอย่างไร การเรียกใช้ฟังก์ชันหมายถึงการรันฟังก์ชันที่นิยามไว้ แล้วแต่จะเรียกตรงจากพรอมต์ Python หรือผ่านฟังก์ชันอื่น (ดังที่จะเห็นในหัวข้อ “Nested Functions”)

เรียกใช้ฟังก์ชัน hello() ที่นิยามใหม่ได้โดยรัน hello() เหมือนในส่วน DataCamp Light ด้านล่างนี้:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiZGVmIGhlbGxvKCk6XG4gIHByaW50KFwiSGVsbG8gV29ybGRcIikgXG4gIHJldHVybiAiLCJzYW1wbGUiOiJoZWxsbygpIn0=

วิธีเพิ่ม docstring ให้ฟังก์ชัน Python

อีกแง่มุมสำคัญของการเขียนฟังก์ชันใน Python: docstring Docstring อธิบายว่าฟังก์ชันทำอะไร เช่น การคำนวณที่ทำหรือค่าที่คืนค่า คำอธิบายนี้ทำหน้าที่เป็นเอกสารของฟังก์ชัน เพื่อให้ผู้ใดก็ตามที่อ่าน docstring ของฟังก์ชันเข้าใจได้ว่าฟังก์ชันทำอะไร โดยไม่ต้องไล่ตามโค้ดทั้งหมดในคำนิยามฟังก์ชัน

Docstring ของฟังก์ชันจะวางไว้บรรทัดถัดจากส่วนหัวของฟังก์ชันและคั่นด้วยเครื่องหมายอัญประกาศสามตัว Docstring ที่เหมาะสมสำหรับฟังก์ชัน hello() คือ ‘พิมพ์ “Hello World”’

def hello() -> None:
    """Prints "Hello World"."""
    print("Hello World")

หมายเหตุ ว่า docstring อาจยาวกว่าตัวอย่างนี้ได้ หากต้องการศึกษา docstring โดยละเอียด แนะนำให้ดูที่คลัง GitHub ของไลบรารี Python เช่น scikit-learn หรือ pandas ซึ่งมีตัวอย่างมากมาย!

Type hints

สิ่งที่เกี่ยวข้องใกล้ชิดกับ docstring และพบเห็นได้บ่อยในโค้ด Python สมัยใหม่คือ type hint ตั้งแต่ Python 3.5 เป็นต้นมา สามารถใส่คำอธิบายชนิดข้อมูลให้กับพารามิเตอร์ของฟังก์ชันและค่าที่คืนว่าจะเป็นชนิดใด ตัวอย่างง่ายที่สุดมีดังนี้:

def plus(a: int, b: int) -> int:
    return a + b

เครื่องหมาย : int หลังแต่ละพารามิเตอร์หมายถึง “ควรเป็นจำนวนเต็ม” และ -> int หลังวงเล็บหมายถึง “ฟังก์ชันนี้คืนค่าเป็นจำนวนเต็ม” Python เองจะไม่บังคับใช้คำอธิบายนี้ขณะรันไทม์ ยังคงส่งสตริงเข้า plus() ได้และ Python จะไม่ร้องจนกว่าจะเกิดปัญหา แต่เครื่องมืออย่าง mypy, pyright และระบบตรวจชนิดในตัวของตัวแก้ไขอย่าง VS Code และ PyCharm จะใช้ hint เหล่านี้เพื่อจับบั๊กก่อนที่จะรันโค้ดจริง

สำหรับชนิดที่ซับซ้อนขึ้น สามารถใช้ generic ที่มีมาให้โดยตรง (ตั้งแต่ Python 3.9+) หรือ import จากโมดูล typing:

def greet(names: list[str]) -> None:
    for name in names:
        print(f"Hello {name}")

def find_user(user_id: int) -> dict | None:
    # returns the user dict, or None if not found
    ...
Type hint เป็นตัวเลือก แต่ถือเป็นแนวปฏิบัติที่ดีสำหรับฟังก์ชันที่ตั้งใจจะนำกลับมาใช้ซ้ำ แบ่งปัน หรือย้อนกลับมาดูในอีกหกเดือนข้างหน้า 它们ทำหน้าที่เป็นเอกสารที่เครื่องตรวจสอบได้ IDE จะเติมคำอัตโนมัติตามนั้น จับการพิมพ์ผิด และเตือนเมื่อส่งชนิดไม่ถูกต้อง

อาร์กิวเมนต์ของฟังก์ชันใน Python

ก่อนหน้านี้ได้เรียนรู้ความแตกต่างระหว่างพารามิเตอร์และอาร์กิวเมนต์โดยย่อแล้ว อาร์กิวเมนต์คือสิ่งที่ส่งให้กับการเรียกใช้ฟังก์ชันหรือเมธอด ขณะที่โค้ดของฟังก์ชันหรือเมธอดจะอ้างถึงอาร์กิวเมนต์ด้วยชื่อพารามิเตอร์ UDF ใน Python รองรับอาร์กิวเมนต์สี่ประเภท:

  • อาร์กิวเมนต์ค่าเริ่มต้น (Default arguments)
  • อาร์กิวเมนต์ที่จำเป็น (Required arguments)
  • อาร์กิวเมนต์แบบระบุคีย์เวิร์ด (Keyword arguments)
  • จำนวนอาร์กิวเมนต์แปรผัน (Variable number of arguments)

Default Arguments

อาร์กิวเมนต์ค่าเริ่มต้นคืออาร์กิวเมนต์ที่รับค่าเริ่มต้นหากไม่มีการส่งค่าเข้ามาระหว่างการเรียกใช้ฟังก์ชัน สามารถกำหนดค่าเริ่มต้นนี้ได้ด้วยโอเปอเรเตอร์กำหนดค่า = ดังตัวอย่างต่อไปนี้:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6IiMgRGVmaW5lIGBwbHVzKClgIGZ1bmN0aW9uXG5kZWYgcGx1cyhhLGIgPSAyKTpcbiAgcmV0dXJuIGEgKyBiXG4gIFxuIyBDYWxsIGBwbHVzKClgIHdpdGggb25seSBgYWAgcGFyYW1ldGVyXG5wbHVzKGE9MSlcblxuIyBDYWxsIGBwbHVzKClgIHdpdGggYGFgIGFuZCBgYmAgcGFyYW1ldGVyc1xucGx1cyhhPTEsIGI9MykifQ==

Required Arguments

ตามชื่อ อาร์กิวเมนต์ที่จำเป็นของ UDF คือสิ่งที่ต้องมี อาร์กิวเมนต์เหล่านี้ต้องถูกส่งเข้ามาระหว่างการเรียกใช้ฟังก์ชันและต้องอยู่ในลำดับที่ถูกต้อง ดังตัวอย่างต่อไปนี้:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6IiMgRGVmaW5lIGBwbHVzKClgIHdpdGggcmVxdWlyZWQgYXJndW1lbnRzXG5kZWYgcGx1cyhhLGIpOlxuICByZXR1cm4gYSArIGIifQ==

จำเป็นต้องมีอาร์กิวเมนต์ที่แมปกับพารามิเตอร์ a และ b เพื่อเรียกใช้ฟังก์ชันโดยไม่เกิดข้อผิดพลาด หากสลับ a และ b ผลลัพธ์จะไม่ต่างกัน แต่จะต่างกันได้หากเปลี่ยน plus() เป็นแบบต่อไปนี้:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6IiMgRGVmaW5lIGBwbHVzKClgIHdpdGggcmVxdWlyZWQgYXJndW1lbnRzXG5kZWYgcGx1cyhhLGIpOlxuICByZXR1cm4gYS9iIn0=

Keyword Arguments

หากต้องการให้แน่ใจว่าเรียกพารามิเตอร์ถูกลำดับ สามารถใช้อาร์กิวเมนต์แบบคีย์เวิร์ดในการเรียกฟังก์ชัน ใช้วิธีนี้เพื่อระบุอาร์กิวเมนต์ด้วยชื่อพารามิเตอร์ มาดูตัวอย่างจากด้านบนเพื่อให้ชัดเจนขึ้น:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6IiMgRGVmaW5lIGBwbHVzKClgIGZ1bmN0aW9uXG5kZWYgcGx1cyhhLGIpOlxuICByZXR1cm4gYSArIGJcbiAgXG4jIENhbGwgYHBsdXMoKWAgZnVuY3Rpb24gd2l0aCBwYXJhbWV0ZXJzIFxucGx1cygyLDMpXG5cbiMgQ2FsbCBgcGx1cygpYCBmdW5jdGlvbiB3aXRoIGtleXdvcmQgYXJndW1lbnRzXG5wbHVzKGE9MSwgYj0yKSJ9

สังเกตว่าเมื่อใช้อาร์กิวเมนต์แบบคีย์เวิร์ด สามารถสลับลำดับพารามิเตอร์และยังคงได้ผลลัพธ์เดียวกันเมื่อรันฟังก์ชัน:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6IiMgRGVmaW5lIGBwbHVzKClgIGZ1bmN0aW9uXG5kZWYgcGx1cyhhLGIpOlxuICByZXR1cm4gYSArIGJcbiAgXG4jIENhbGwgYHBsdXMoKWAgZnVuY3Rpb24gd2l0aCBrZXl3b3JkIGFyZ3VtZW50c1xucGx1cyhiPTIsIGE9MSkifQ==

จำนวนอาร์กิวเมนต์แปรผัน

ในกรณีที่ไม่ทราบจำนวนอาร์กิวเมนต์ที่ต้องการส่งให้ฟังก์ชันแน่ชัด สามารถใช้ไวยากรณ์ดังต่อไปนี้กับ *args ได้:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6IiMgRGVmaW5lIGBwbHVzKClgIGZ1bmN0aW9uIHRvIGFjY2VwdCBhIHZhcmlhYmxlIG51bWJlciBvZiBhcmd1bWVudHNcbmRlZiBwbHVzKCphcmdzKTpcbiAgcmV0dXJuIHN1bShhcmdzKVxuXG4jIENhbGN1bGF0ZSB0aGUgc3VtXG5wbHVzKDEsNCw1KSJ9

เครื่องหมายดอกจัน (*) วางไว้หน้าชื่อตัวแปรที่เก็บค่าของอาร์กิวเมนต์แบบไม่ใช่คีย์เวิร์ดทั้งหมด สังเกตว่าสามารถใช้ชื่ออื่นแทน *args เช่น *varint, *var_int_args หรือชื่อใด ๆ เมื่อส่งเข้าไปยังฟังก์ชัน plus() ก็ได้

เคล็ดลับ: ลองแทนที่ *args ด้วยชื่ออื่นที่มีดอกจัน จะเห็นว่าโค้ดด้านบนยังทำงานต่อไปได้!

จะเห็นว่าฟังก์ชันด้านบนใช้ฟังก์ชันที่มีมาให้ของ Python อย่าง sum() เพื่อบวกรวมอาร์กิวเมนต์ทั้งหมดที่ส่งเข้าไปยัง plus() 

ตัวแปรแบบ global กับแบบ local

โดยทั่วไป ตัวแปรที่กำหนดในเนื้อฟังก์ชันจะมีขอบเขตแบบ local ส่วนตัวแปรที่กำหนดไว้ภายนอกจะมีขอบเขตแบบ global นั่นหมายความว่า ตัวแปร local ถูกกำหนดภายในบล็อกของฟังก์ชันและเข้าถึงได้เฉพาะภายในฟังก์ชันนั้น ขณะที่ตัวแปร global สามารถเข้าถึงได้โดยฟังก์ชันทั้งหมดในสคริปต์ของคุณ:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6IiMgR2xvYmFsIHZhcmlhYmxlIGBpbml0YFxuaW5pdCA9IDFcblxuIyBEZWZpbmUgYHBsdXMoKWAgZnVuY3Rpb24gdG8gYWNjZXB0IGEgdmFyaWFibGUgbnVtYmVyIG9mIGFyZ3VtZW50c1xuZGVmIHBsdXMoKmFyZ3MpOlxuICAjIExvY2FsIHZhcmlhYmxlIGBzdW0oKWBcbiAgdG90YWwgPSAwXG4gIGZvciBpIG4gYXJnczoXG4gICAgdG90YWwgKz0gaVxuICByZXR1cm4gdG90YWxcbiAgXG4jIEFjY2VzcyB0aGUgZ2xvYmFsIHZhcmlhYmxlXG5wcmludChcInRoaXMgaXMgdGhlIGluaXRpYWxpemVkIHZhbHVlIFwiICsgc3RyKGluaXQpKVxuXG4jIChUcnkgdG8pIGFjY2VzcyB0aGUgbG9jYWwgdmFyaWFibGVcbnByaW50KFwidGhpcyBpcyB0aGUgc3VtIFwiICsgc3RyKHRvdGFsKSkifQ==

จะเห็นว่าเกิด NameError ระบุว่า name 'total' is not defined เมื่อพยายามพิมพ์ตัวแปร local total ที่ถูกกำหนดภายในเนื้อฟังก์ชัน ด้านทางกลับกัน ตัวแปร init สามารถพิมพ์ได้โดยไม่มีปัญหา

พารามิเตอร์แบบ positional-only และ keyword-only

ตั้งแต่ Python 3.8 เป็นต้นมา สามารถควบคุมวิธีการส่งอาร์กิวเมนต์ได้มากขึ้นด้วยเครื่องหมายพิเศษสองตัวในลายเซ็นของฟังก์ชัน คือ / และ * สิ่งที่อยู่ก่อน / จะส่งได้เฉพาะแบบตำแหน่งเท่านั้น ส่วนที่อยู่หลัง * จะส่งได้เฉพาะแบบคีย์เวิร์ดเท่านั้น

def greet(name, /, greeting="Hello", *, punctuation="!"):
    print(f"{greeting} {name}{punctuation}")

 ตัวอย่างการเรียกใช้จะเป็นดังนี้:

greet("Alice")                          # works
greet("Alice", greeting="Hi")           # works
greet("Alice", "Hi", punctuation="?")   # works

greet(name="Alice")                     # TypeError: name is positional-only
greet("Alice", "Hi", "?")               # TypeError: punctuation is keyword-only

ทำไมถึงอยากใช้แบบนี้? มีสองเหตุผลหลัก

หนึ่ง, พารามิเตอร์แบบ positional-only ช่วยให้เปลี่ยนชื่อในภายหลังได้โดยไม่ทำให้โค้ดของใครพัง เพราะไม่มีใครได้รับอนุญาตให้ใช้ชื่อนั้นเป็นคีย์เวิร์ด จึงเปลี่ยนชื่อได้อิสระ

สอง, พารามิเตอร์แบบ keyword-only บังคับให้ผู้เรียกใช้ระบุอย่างชัดเจนว่ากำลังส่งอะไร ทำให้การเรียกอ่านง่ายขึ้นเมื่อมีแฟลกหรือการตั้งค่าทางเลือกหลายตัว

สรุปคือ เป็นวิธีที่สะอาดในการบังคับใช้เจตนา

ฟังก์ชันนิรนามใน Python

ฟังก์ชันนิรนามใน Python เรียกว่าฟังก์ชันแลมบ์ดา เพราะแทนที่จะประกาศด้วยคีย์เวิร์ดมาตรฐาน def จะใช้คีย์เวิร์ด lambda

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6ImRvdWJsZSA9IGxhbWJkYSB4OiB4KjJcblxuZG91YmxlKDUpIn0=

ในส่วน DataCamp Light ด้านบน lambda x: x*2 คือฟังก์ชันนิรนามหรือฟังก์ชันแลมบ์ดา x คืออาร์กิวเมนต์ และ x*2 คือ expression หรือคำสั่งที่ถูกประเมินและคืนค่า ความพิเศษของฟังก์ชันนี้คือไม่มีชื่อ แตกต่างจากตัวอย่างในส่วนแรกของบทช่วยสอนฟังก์ชัน หากต้องเขียนฟังก์ชันข้างต้นเป็น UDF จะได้ผลลัพธ์ดังนี้:

def double(x):
  return x*2

พิจารณาตัวอย่างฟังก์ชันแลมบ์ดาที่ทำงานกับอาร์กิวเมนต์สองตัว:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6IiMgYHN1bSgpYCBsYW1iZGEgZnVuY3Rpb25cbnN1bSA9IGxhbWJkYSB4LCB5OiB4ICsgeTtcblxuIyBDYWxsIHRoZSBgc3VtKClgIGFub255bW91cyBmdW5jdGlvblxuc3VtKDQsNSlcblxuIyBcIlRyYW5zbGF0ZVwiIHRvIGEgVURGXG5kZWYgc3VtKHgsIHkpOlxuICByZXR1cm4geCt5In0=

มักใช้ฟังก์ชันนิรนามเมื่อจำเป็นต้องใช้ฟังก์ชันที่ไม่มีชื่อชั่วคราวและถูกสร้างขึ้นขณะรันไทม์ บริบทที่เกี่ยวข้องเช่นเมื่อทำงานกับ filter(), map() และ reduce():

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6ImZyb20gZnVuY3Rvb2xzIGltcG9ydCByZWR1Y2VcblxubXlfbGlzdCA9IFsxLDIsMyw0LDUsNiw3LDgsOSwxMF1cblxuIyBVc2UgbGFtYmRhIGZ1bmN0aW9uIHdpdGggYGZpbHRlcigpYFxuZmlsdGVyZWRfbGlzdCA9IGxpc3QoZmlsdGVyKGxhbWJkYSB4OiAoeCoyID4gMTApLCBteV9saXN0KSlcblxuIyBVc2UgbGFtYmRhIGZ1bmN0aW9uIHdpdGggYG1hcCgpYFxubWFwcGVkX2xpc3QgPSBsaXN0KG1hcChsYW1iZGEgeDogeCoyLCBteV9saXN0KSlcblxuIyBVc2UgbGFtYmRhIGZ1bmN0aW9uIHdpdGggYHJlZHVjZSgpYFxucmVkdWNlZF9saXN0ID0gcmVkdWNlKGxhbWJkYSB4LCB5OiB4K3ksIG15X2xpc3QpXG5cbnByaW50KGZpbHRlcmVkX2xpc3QpXG5wcmludChtYXBwZWRfbGlzdClcbnByaW50KHJlZHVjZWRfbGlzdCkifQ==

ฟังก์ชัน filter() จะกรองลิสต์อินพุตเดิม my_list ตามเงื่อนไข >10 ตามชื่อของมัน ส่วน map() จะนำฟังก์ชันไปใช้กับทุกองค์ประกอบของลิสต์ my_list ในที่นี้คือคูณทุกองค์ประกอบด้วย 2

สังเกตว่า reduce() อยู่ในไลบรารี functools ใช้ฟังก์ชันนี้แบบสะสมกับรายการในลิสต์ my_list จากซ้ายไปขวา และย่อลำดับให้เหลือค่าเดียว ซึ่งในที่นี้คือ 55

การใช้ main() เป็นฟังก์ชันใน Python

หากมีประสบการณ์กับภาษาอื่นอย่าง Java จะทราบว่าต้องมีฟังก์ชัน main เพื่อรันฟังก์ชันต่าง ๆ แต่จากตัวอย่างด้านบนจะเห็นว่า Python ไม่จำเป็นต้องมี อย่างไรก็ตาม การใส่ฟังก์ชัน main() ในโปรแกรม Python จะช่วยจัดโครงร่างโค้ดอย่างมีเหตุผล องค์ประกอบที่สำคัญที่สุดจะถูกรวมไว้ในฟังก์ชัน main() นี้

สามารถนิยามฟังก์ชัน main() และเรียกใช้ได้ง่าย ๆ เช่นเดียวกับฟังก์ชันอื่น ๆ ด้านบน:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiZGVmIGhlbGxvKCk6XG4gIHByaW50KFwiSGVsbG8gV29ybGRcIikgXG4gIHJldHVybiAiLCJzYW1wbGUiOiIjIERlZmluZSBgbWFpbigpYCBmdW5jdGlvblxuZGVmIG1haW4oKTpcbiAgaGVsbG8oKVxuICBwcmludChcIlRoaXMgaXMgYSBtYWluIGZ1bmN0aW9uXCIpXG5cbm1haW4oKSJ9

อย่างไรก็ตาม ในสภาพนี้ โค้ดของฟังก์ชัน main() จะถูกเรียกเมื่อมีการ import ไฟล์เป็นโมดูล เพื่อป้องกันไม่ให้เกิดขึ้น ควรเรียกฟังก์ชัน main() เมื่อ __name__ == '__main__'

ดังนั้นโค้ดในส่วนด้านบนจะกลายเป็นดังนี้:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiZGVmIGhlbGxvKCk6XG4gIHByaW50KFwiSGVsbG8gV29ybGRcIikgXG4gIHJldHVybiAiLCJzYW1wbGUiOiIjIERlZmluZSBgbWFpbigpYCBmdW5jdGlvblxuZGVmIG1haW4oKTpcbiAgaGVsbG8oKVxuICBwcmludChcIlRoaXMgaXMgYSBtYWluIGZ1bmN0aW9uXCIpXG4gIFxuIyBFeGVjdXRlIGBtYWluKClgIGZ1bmN0aW9uIFxuaWYgX19uYW1lX18gPT0gJ19fbWFpbl9fJzpcbiAgICBtYWluKCkifQ==

หมายเหตุ นอกเหนือจากฟังก์ชัน __main__ แล้ว ยังมีฟังก์ชัน __init__ ที่ใช้เริ่มต้นอินสแตนซ์ของคลาสหรืออ็อบเจ็กต์ กล่าวโดยย่อคือทำหน้าที่เป็นคอนสตรักเตอร์หรือตัวเริ่มต้น และถูกเรียกอัตโนมัติเมื่อสร้างอินสแตนซ์ของคลาสใหม่ ด้วยฟังก์ชันนี้ อ็อบเจ็กต์ที่สร้างใหม่จะถูกกำหนดให้กับพารามิเตอร์ self ซึ่งเห็นไปแล้วในบทช่วยสอนนี้ ดูตัวอย่างต่อไปนี้:

class Dog:
    """A simple Dog class.

    Args:
        legs: Number of legs so that the dog can walk.
        color: The color of the fur.
    """

    def __init__(self, legs: int, color: str) -> None:
        self.legs = legs
        self.color = color

    def bark(self) -> str:
        return "bark" * 2

if __name__ == "__main__":
    dog = Dog(4, "brown")
    print(dog.bark())

ฝึกฟังก์ชัน Python ต่อให้คล่อง

ยินดีด้วย! ผ่านบทช่วยสั้น ๆ เกี่ยวกับฟังก์ชันใน Python แล้ว หากต้องการทบทวนเนื้อหา Python พื้นฐานอื่น ๆ อย่าพลาดคอร์ส Data Types for Data Science ซึ่งจะช่วยย้ำและฝึกความรู้เกี่ยวกับลิสต์, ดิกชันนารี, ทูเพิล, เซต และวันที่และเวลา

คำถามที่พบบ่อยเกี่ยวกับฟังก์ชันใน Python

ฟังก์ชันใน Python คืออะไร?

ฟังก์ชันคือบล็อกโค้ดที่นำกลับมาใช้ซ้ำได้เพื่อทำงานเฉพาะอย่าง สามารถรับอินพุต ประมวลผล และคืนเอาต์พุตได้

กำหนดฟังก์ชันใน Python อย่างไร?

เพื่อกำหนดฟังก์ชันใน Python ให้ใช้คีย์เวิร์ด def ตั้งชื่อฟังก์ชัน ใส่พารามิเตอร์ (ถ้ามี) ในวงเล็บ เขียนโค้ด แล้วอาจใช้ return เพื่อคืนค่า

ความแตกต่างระหว่างฟังก์ชันกับเมธอดใน Python คืออะไร?

ฟังก์ชันอยู่เดี่ยว ๆ แต่เมธอดเป็นส่วนหนึ่งของคลาส เมธอดทั้งหมดคือฟังก์ชัน แต่ไม่ใช่ทุกฟังก์ชันคือเมธอด

ประเภทของฟังก์ชันใน Python มีอะไรบ้าง?

Python มีฟังก์ชันที่มีมาให้ (เช่น print()) ฟังก์ชันที่ผู้ใช้กำหนดเอง (ที่คุณสร้างขึ้น) และฟังก์ชันนิรนาม (ฟังก์ชัน lambda ชั่วคราว)

ความแตกต่างระหว่างพารามิเตอร์และอาร์กิวเมนต์คืออะไร?

พารามิเตอร์คือช่องว่างรองรับในคำจำกัดความของฟังก์ชัน ส่วนอาร์กิวเมนต์คือค่าจริงที่ส่งเข้าไปเมื่อเรียกใช้ฟังก์ชัน

ฟังก์ชันแลมบ์ดาคืออะไร?

ฟังก์ชันแลมบ์ดาคือฟังก์ชันไม่มีชื่อแบบบรรทัดเดียวสำหรับงานรวดเร็ว

ทำไมต้องใช้ฟังก์ชัน __main__?

ฟังก์ชัน __main__ ช่วยจัดโค้ดให้เป็นระเบียบและทำให้ส่วนที่ระบุรันเฉพาะเมื่อสคริปต์ถูกรันโดยตรง ไม่ใช่เมื่อถูก import

ความแตกต่างระหว่างตัวแปร global และ local คืออะไร?

ตัวแปรแบบ global ใช้ได้ทุกที่ ส่วนตัวแปรแบบ local ใช้ได้เฉพาะภายในฟังก์ชันของมันเท่านั้น

หัวข้อ

เรียนรู้เพิ่มเติมเกี่ยวกับ Python

Courses

Introduction to Python

4 ชม.
6.8M
Master the basics of data analysis with Python in just four hours. This online course will introduce the Python interface and explore popular packages.
ดูรายละเอียดRight Arrow
เริ่มหลักสูตร
ดูเพิ่มเติมRight Arrow