ฟังก์ชัน คือกลุ่มของโค้ดที่ถูกรวบรวมไว้เพื่อทำงานเฉพาะอย่าง ซึ่งฟังก์ชันจะทำงานก็ต่อเมื่อถูกเรียกใช้เท่านั้น และเราสามารถส่งข้อมูลเข้าไปประมวลผลในฟังก์ชันในขณะเรียกใช้ฟังก์ชันได้ด้วย เรียกว่า พารามิเตอร์ นอกจากนี้ยังสามารถกำหนดให้ฟังก์ชันคืนค่าอย่างใดอย่างหนึ่งกลับออกมาหลังจากประมวลผลเสร็จเรียบร้อยแล้ว
การสร้างฟังก์ชัน
การสร้างฟังก์ชันในภาษา Python สามารถทำได้โดยการกำหนดคีย์เวิร์ด def ตามด้วยชื่อฟังก์ชัน ดังตัวอย่าง
def my_function():
print("สวัสดีชาวโลก")- บรรทัดที่ 1 สร้างฟังก์ชันชื่อว่า
my_function - บรรทัดที่ 2 โค้ดคำสั่งที่จะให้ทำงานภายในฟังก์ชัน
การเรียกใช้ฟังก์ชัน
การเรียกใช้ฟังก์ชัน ทำได้โดยการพิมพ์ชื่อฟังก์ชันตามด้วยวงเล็บ ดังตัวอย่าง
def my_function():
print("สวัสดีชาวโลก")
my_function()- บรรทัดที่ 4 เรียกใช้ฟังก์ชันที่เราได้สร้างไว้
การใช้งาน Arguments
กรณีที่เราต้องการให้ฟังก์ชันที่สร้างขั้นมาสามารถรับข้อมูลจากภายนอกเข้าไปประมวลผลได้ด้วย เราสามารถส่งข้อมูลเข้าไปในฟังก์ชันโดยผ่านอากิวเมนต์ Arguments ซึ่งจะถูกกำหนดไว้ภายในวงเว็บหลังชื่อฟังก์ชัน และแต่ละฟังก์ชันสามารถอากิวเมนต์ได้หลายตัวเท่าที่เราต้องการ แต่ต้องคั่นอากิวเมนต์แต่ละตัวด้วยเครื่องหมายคอมม่า โดยมีรูปแบบ functionname(arg1, arg2, arg3) ดังตัวอย่าง
def fullname(firstname, lastname):
print(firstname + " " + lastname)- บรรทัดที่ 1 สร้างฟังก์ชันชื่อว่า
fullnameโดยมีอากิวเมนต์ 2 ตัว คือfirstnameและlastname - บรรทัดที่ 2 สั่งให้ให้แสดงผลออกมาทางหน้าจอ
การเรียกใช้ฟังก์ชันที่มี Arguments
เมื่อต้องการเรียกใช้ฟังก์ชันที่มี Arguments เราต้องส่งข้อมูลเข้าไปตามจำนวนอากิวเมนต์ที่ฟังก์ชันนั้น ๆ ต้องการ เรียกข้อมูลที่ส่งเข้าไปว่า พารามิเตอร์ Parameters ดังตัวอย่าง
def fullname(firstname, lastname):
print(firstname + " " + lastname)
fullname("Rhaenyra", "Targaryen")- บรรทัดที่ 4 เรียกใช้ฟังก์ชัน
fullnameโดยส่งพารามิเตอร์เข้าไป 2 ตัว คือ “Rhaenyra” และ “Targaryen” ตามจำนวนอากิวเมนต์ของฟังก์ชัน
ผลลัพธ์ที่ได้คือ
Rhaenyra Targaryen
ตามคำสั่งการทำงานที่กำหนดไว้ภายในฟังก์ชันนั่นเอง
ข้อแตกต่างระหว่าง Arguments และ Parameters
ทั้งอากิวเมนต์ Arguments และ พารามิเตอร์ Parameters ใช้สำหรับสิ่งเดียวกัน แต่เรียกชื่อต่างกันตามจุดประสงค์ของการใช้งาน
- อากิวเมนต์ Arguments เป็นชื่อเรียกตัวแปรที่สร้างไว้รองรับข้อมูลที่ส่งเข้ามาเมื่อเรียกใช้ฟังก์ชัน
- พารามิเตอร์ Parameters คือข้อมูลที่ถูกส่งเข้าไปกำหนดค่าให้กับอากิวเมนต์เมื่อเรียกใช้ฟังก์ชัน
Arbitrary Arguments, *args
ทุกครั้งที่เรียกใช้ฟังก์ชันที่มีอากิวเมนต์ เราต้องส่งพารามิเตอร์เข้าไปให้ครบตามจำนวนอากิวเมนต์ที่ฟังก์ชันนั้น ๆ ต้องการ ห้ามขาดและห้ามเกินเด็ดขาด ไม่เช่นนั้นจะเกิดข้อผิดพลาดขึ้น
แต่ในกรณีที่เราไม่รู้ว่าฟังก์ชันต้องรับอากิวเมนต์กี่ตัว หรือจำนวนอากิวเมนต์ไม่แน่นอน สามารถแก้ปัญหาโดยการเติมเครื่องหมายดอกจันทน์ * ไว้หน้าชื่ออากิวเมนต์
ในกรณีนี้ฟังก์ชันจะรับอากิวเมนต์เป็นแบบ tuple และสามารถเข้าถึงข้อมูลภายในอากิวเมนต์นั้น ๆ ด้วยวิธีการเข้าถึงข้อมูลแบบ tuple ดังตัวอย่าง
def my_dragons(*dragons):
print("My Dragons:")
for dragon in dragons:
print(dragon)
my_dragons("Syrax", "Caraxes", "Vermax", "Seasmoke", "Vhagar", "Dreamfyre", "Sunfyre", "Meleys")- บรรทัดที่ 1 สร้างฟังก์ชันชื่อว่า
my_dragonsโดยมีอากิวเมนต์เพียง 1 ตัว แต่เติมเครื่องหมาย*ไว้ข้างหน้าอากิวเมนต์ เพื่อให้อากิวเมนต์ดังกล่าวรับค่าเข้ามาในแบบ tuple - บรรทัดที่ 3-4 ใช้ลูป
forเข้าถึงสมาชิกในตัวแปรdragonsทีละตัวแล้วแสดงผลออกมา - บรรทัดที่ 6 เรียกใช้ฟังก์ชัน my_dragons โดยส่งพารามิเตอร์เข้าไป 8 ตัว (กี่ตัวก็ได้ เพราะอากิวเมนต์เป็นแบบ Arbitrary Arguments)
ผลลัพธ์
My Dragons:
Syrax
Caraxes
Vermax
Seasmoke
Vhagar
Dreamfyre
Sunfyre
Meleys
อากิวเมนต์แบบ Keyword
นอกจากการส่งอากิวเมนต์แบบปกติและแบบ Arbitrary ดังที่ผ่านมาแล้ว เรายังสามารถส่งอากิวเมนต์แบบ key = value ได้อีกด้วย โดยการส่งอากิวเมนต์แบบนี้ เวลาเรียกใช้ฟังก์ชันเราไม่จำเป็นต้องกังวลเรื่องการเรียงลำดับของอากิวเมนต์ เพราะมีคีย์กำกับอยู่แล้ว ดังตัวอย่าง
def my_dragons(dragon2, dragon1, dragon4, dragon3):
print("My second dragon is " + dragon2)
my_dragons(dragon1 = "Syrax", dragon2 = "Caraxes", dragon3 = "Vermax", dragon4 ="Seasmoke")- บรรทัดที่ 4 เรียกใช้ฟังก์ชัน
my_dragonsโดยส่งอากิวเมนต์เป็นแบบkey = value
สังเกตว่าลำดับอากิวเมนต์ภายในฟังก์ชัน กับลำดับอากิวเมนต์ตอนเรียกใช้ฟังก์ชันไม่ตรงกัน แต่ก็ไม่มีข้อผิดพลาดใด ๆ เพราะเราได้กำหนดชื่อตัวแปรเป็นคีย์เวิร์ดไว้แล้วว่าอากิวเมนต์แต่ละตัวที่ส่งเข้าไปหมายถึงอากิวเมนต์ตัวไหนในฟังก์ชัน
การใช้งาน Arbitrary Keyword Arguments, **kwargs
ในกรณีที่ต้องการใช้งานอากิวเมนต์แบบ key = value แต่ไม่รู้ว่ามีกี่ตัว หรือไม่สามารถกำหนดล่วงหน้าได้ว่ามีกี่ตัว สามารถแก้ปัญหาได้โดยการใช้อากิวเมนต์แบบ Arbitrary Keyword Arguments โดยการเติมเครื่องหมายดอกจันทน์จำนวน 2 ตัว ** หน้าอากิวเมนต์
ในกรณีนี้ฟังก์ชันจะรับอากิวเมนต์เป็นแบบ Dictionary ดังตัวอย่าง
def person(**var):
print(var["firstname"] + " " + var["lastname"])
person(firstname = "Rhaenyra", lastname= "Targaryen")- บรรทัดที่ 1 สร้างฟังก์ชันชื่อว่า
personโดยกำหนดอากิวเมนต์แบบ Arbitrary Keyword Arguments**var - บรรทัดที่ 2 เข้าถึงดิกชันนารี
varโดยระบุคีย์เวิร์ดเป็นfirstnameและlastnameเพื่อให้แสดงผลออกมา - บรรทัดที่ 4 เรียกใช้ฟังก์ชัน
personโดยระบุอากิวเมนต์แบบkey = value
ผลลัพธ์
Rhaenyra Targaryen
Default Parameter Value
ในการสร้างฟังก์ชัน เราสามารถกำหนดค่าพารามิเตอร์ไว้ล่วงหน้าก็ได้ หลังจากนั้นเมื่อเราเรียกใช้ฟังก์ชัน เราจะกำหนดอากิวเมนต์หรือไม่ก็ได้ โดยเมื่อเรียกใช้ฟังก์ชัน
- ถ้าเรากำหนดค่าให้อากิวเมนต์ ค่าที่เราจะกำหนดจะถูกนำไปใช้เป็นค่าพารามิเตอร์
- ถ้าไม่กำหนด ค่าดีฟอลต์ที่กำหนดไว้จะถูกนำมาใช้แทน
ดังตัวอย่าง
def person(name = "Rhaenyra"):
print("My name is " + name)
person()
# My name is Rhaenyra- บรรทัดที่ 1 สร้างฟังก์ชันโดยมีอากิวเมนต์ 1 ตัว กำหนดค่าเริ่มต้นไว้เรียบร้อย
- บรรทัดที่ 4 เรียกใช้ฟังก์ชันโดยไม่ระบุพารามิเตอร์ใด ๆ
ชนิดข้อมูลของอากิวเมนต์
เราสามารถกำหนดอากิวเมนต์เป็นข้อมูลชนิดใดก็ได้ โดยอากิวเมนต์ในฟังก์ชันจะกลายเป็นชนิดข้อมูลตามที่เรากำหนด เช่น ถ้าเราส่งข้อมูลประเภท list เข้าไป อากิวเมนต์ในฟังก์ชันก็จะเป็นข้อมูลประเภท list ด้วยเช่นกัน
def my_dragons(dragons):
for dragon in dragons:
print(dragon)
dragons = ["Syrax", "Caraxes", "Vermax", "Seasmoke"]
my_dragons(dragons)Syrax
Caraxes
Vermax
Seasmoke
การคืนค่าจากฟังก์ชัน
ถ้าต้องการให้ฟังก์ชันคืนค่าใด ๆ กลับออกมาหลังจากถูกเรียกใช้ สามารถใช้คีย์เวิร์ด return เพื่อบอกให้ฟังก์ชันส่งค่าที่ต้องการกลับออกมา ดังตัวอย่าง
def greet(name):
return "Hello " + name
print(greet("Dreamfyre"))
# Hello Dreamfyre- บรรทัดที่ 2 ใช้คีย์เวิร์ด
returnเพื่อส่งค่ากลับออกมาจากฟังก์ชัน - บรรทัดที่ 4 ให้แสดงผลค่าที่ส่งกลับออกมาจากฟังก์ชัน
pass Statement
เมื่อสร้างฟังก์ชันขึ้นมาแล้ว จะไม่เขียนโค้ดการทำงานใด ๆ ภายในฟังก์ชันเลยไม่ได้ เพราะจะเกิดข้อผิดพลาด อย่างไรก็ตาม หากมีบางกรณีที่เราจำเป็นต้องสร้างฟังก์ชันขึ้นมาก่อน โดยยังไม่รู้ว่าจะเขียนโค้ดทำงานใด ๆ ลงไป เราสามารถเขียนคำสั่ง pass ไว้ก่อน เพื่อให้ไม่เกิดข้อผิดพลาด โดยฟังก์ชันนั้น ๆ จะไม่มีการทำงานใด ๆ ทั้งสิ้น
def greet(name):
passPositional-Only Arguments
Positional-Only Arguments คืออาร์กิวเมนต์ที่ต้องระบุในตำแหน่งที่กำหนดไว้เมื่อเรียกใช้ฟังก์ชัน ไม่สามารถระบุชื่อ (keyword) เมื่อเรียกใช้ได้
รูปแบบการใช้ positional-only arguments คือการใช้เครื่องหมาย / ในการกำหนดในส่วนการประกาศฟังก์ชัน ดังนี้
def my_function(a, b, /, c, d):
print(a, b, c, d)จากตัวอย่าง a และ b เป็น positional-only arguments ซึ่งหมายความว่าต้องถูกกำหนดตามลำดับในขณะที่เรียกใช้ฟังก์ชัน ส่วน c และ d สามารถกำหนดได้ทั้งในรูปแบบตำแหน่งและ keyword
ตัวอย่างการเรียกใช้
def my_function(a, b, /, c, d):
print(a, b, c, d)
my_function(1, 2, 3, 4) # ถูกต้อง
my_function(1, 2, c=3, d=4) # ถูกต้อง
# my_function(a=1, b=2, c=3, d=4) # ผิดพลาด จะเกิด TypeErrorการใช้ positional-only arguments ช่วยเพิ่มความชัดเจนและป้องกันความสับสนเมื่อใช้งานฟังก์ชัน ทำให้โค้ดอ่านง่ายขึ้นและลดความเสี่ยงในการเกิดข้อผิดพลาดจากการระบุ keyword ที่ผิด
Keyword-Only Arguments
Keyword-Only Arguments คืออาร์กิวเมนต์ที่ต้องระบุชื่อ (keyword) เมื่อเรียกใช้ฟังก์ชัน ไม่สามารถกำหนดตามตำแหน่งได้ การกำหนด keyword-only arguments ใช้เครื่องหมาย * ในการแบ่งส่วนระหว่าง positional arguments กับ keyword-only arguments
ตัวอย่างการใช้งาน keyword-only arguments
def my_function(a, b, *, c, d):
print(a, b, c, d)จากตัวอย่าง a และ b เป็น positional arguments ซึ่งสามารถกำหนดได้ตามตำแหน่งหรือชื่อ แต่ c และ d เป็น keyword-only arguments ซึ่งต้องระบุชื่อเมื่อเรียกใช้ฟังก์ชัน
ตัวอย่างการเรียกใช้
def my_function(a, b, *, c, d):
print(a, b, c, d)
my_function(1, 2, c=3, d=4) # ถูกต้อง
my_function(a=1, b=2, c=3, d=4) # ถูกต้อง
#my_function(1, 2, 3, 4) # ผิดพลาด จะเกิด TypeError- บรรทัดที่ 4
my_function(1, 2, c=3, d=4)เป็นการเรียกใช้ฟังก์ชันที่ถูกต้อง โดยระบุค่าให้cและdเป็น keyword arguments - บรรทัดที่ 5
my_function(a=1, b=2, c=3, d=4)เป็นการเรียกใช้ฟังก์ชันที่ถูกต้อง โดยระบุค่าทั้งหมดเป็น keyword arguments - บรรทัดที่ 6
my_function(1, 2, 3, 4)เป็นการเรียกใช้ฟังก์ชันที่ผิดพลาด เนื่องจากcและdต้องระบุเป็น keyword arguments เท่านั้น
การใช้ keyword-only arguments ช่วยให้โค้ดชัดเจนและป้องกันความสับสนจากการกำหนดค่าในตำแหน่งที่ไม่ถูกต้อง นอกจากนี้ยังช่วยให้สามารถเพิ่มอาร์กิวเมนต์ใหม่ๆ เข้าไปในฟังก์ชันได้โดยไม่ทำให้ฟังก์ชันเดิมเกิดข้อผิดพลาด
การใช้งาน Positional-Only และ Keyword-Only ร่วมกัน
การใช้งาน Positional-Only และ Keyword-Only ร่วมกันในฟังก์ชันเดียว สามารถทำได้เพื่อควบคุมวิธีการระบุค่าให้กับอาร์กิวเมนต์ในฟังก์ชัน โดยกำหนดให้บางอาร์กิวเมนต์ต้องระบุในตำแหน่งที่กำหนด (Positional-Only) และบางอาร์กิวเมนต์ต้องระบุเป็น keyword เท่านั้น (Keyword-Only)
โดยการใช้เครื่องหมาย / สำหรับกำหนด positional-only arguments และเครื่องหมาย * สำหรับกำหนด keyword-only arguments ในการประกาศฟังก์ชัน
ตัวอย่างการใช้งาน
def my_function(pos1, pos2, /, pos_or_kw, *, kw1, kw2):
print(f"pos1: {pos1}, pos2: {pos2}, pos_or_kw: {pos_or_kw}, kw1: {kw1}, kw2: {kw2}")pos1และpos2เป็น Positional-Only Argumentspos_or_kwเป็น Positional-Or-Keyword Argument (สามารถระบุได้ทั้งแบบตำแหน่งหรือ keyword)kw1และkw2เป็น Keyword-Only Arguments
ตัวอย่างการเรียกใช้
def my_function(pos1, pos2, /, pos_or_kw, *, kw1, kw2):
print(f"pos1: {pos1}, pos2: {pos2}, pos_or_kw: {pos_or_kw}, kw1: {kw1}, kw2: {kw2}")
my_function(1, 2, 3, kw1=4, kw2=5) # ถูกต้อง
my_function(1, 2, pos_or_kw=3, kw1=4, kw2=5) # ถูกต้อง
# my_function(1, 2, 3, 4, 5) # ผิดพลาด จะเกิด TypeError เพราะ kw1 และ kw2 ต้องเป็น keyword-only
# my_function(pos1=1, pos2=2, pos_or_kw=3, kw1=4, kw2=5) # ผิดพลาด จะเกิด TypeError เพราะ pos1 และ pos2 เป็น positional-onlymy_function(1, 2, 3, kw1=4, kw2=5)เป็นการเรียกใช้ฟังก์ชันที่ถูกต้อง โดยกำหนดค่าให้กับkw1และkw2เป็น keyword argumentsmy_function(1, 2, pos_or_kw=3, kw1=4, kw2=5)เป็นการเรียกใช้ฟังก์ชันที่ถูกต้อง โดยกำหนดค่าpos_or_kwเป็น keyword argumentmy_function(1, 2, 3, 4, 5)เป็นการเรียกใช้ฟังก์ชันที่ผิดพลาด เนื่องจากkw1และkw2ต้องระบุเป็น keyword arguments เท่านั้นmy_function(pos1=1, pos2=2, pos_or_kw=3, kw1=4, kw2=5)เป็นการเรียกใช้ฟังก์ชันที่ผิดพลาด เนื่องจากpos1และpos2ต้องระบุในตำแหน่งที่กำหนดเท่านั้น
การผสมผสานการใช้งาน Positional-Only และ Keyword-Only Arguments ช่วยให้ฟังก์ชันมีความยืดหยุ่นในการรับค่าและช่วยให้โค้ดชัดเจนยิ่งขึ้น
Recursion
Recursion หรือการเรียกตัวเองของฟังก์ชัน เป็นแนวคิดในการเขียนโปรแกรมที่ฟังก์ชันหนึ่งจะเรียกใช้ตัวมันเองเพื่อแก้ปัญหาที่มีโครงสร้างซ้ำ ๆ กัน โดยปกติการใช้ recursion จะต้องมีเงื่อนไขหยุด (base case) เพื่อป้องกันการเรียกฟังก์ชันไม่สิ้นสุด
ตัวอย่างเช่นการคำนวณค่า factorial ของตัวเลข ค่า factorial ของ n (เขียนว่า n!) คือผลคูณของตัวเลขทุกตัวตั้งแต่ 1 ถึง n
สามารถเขียนเป็นฟังก์ชัน recursive ได้ดังนี้
def factorial(n):
# Base case: เมื่อ n เท่ากับ 0 หรือ 1, factorial ของมันจะเป็น 1
if n == 0 or n == 1:
return 1
# Recursive case: คำนวณ factorial ของ n โดยเรียกฟังก์ชันตัวเอง
else:
return n * factorial(n - 1)- บรรทัดที่ 3-4 ถ้า
nเท่ากับ 0 หรือ 1 ฟังก์ชันจะคืนค่า 1 (base case) - บรรทัดที่ 6-7 มิฉะนั้น ฟังก์ชันจะคืนค่า
nคูณกับการเรียกใช้ฟังก์ชันfactorialของ n-1 (recursive case)
ตัวอย่างการเรียกใช้ฟังก์ชัน
def factorial(n):
# Base case: เมื่อ n เท่ากับ 0 หรือ 1, factorial ของมันจะเป็น 1
if n == 0 or n == 1:
return 1
# Recursive case: คำนวณ factorial ของ n โดยเรียกฟังก์ชันตัวเอง
else:
return n * factorial(n - 1)
print(factorial(5)) # Output: 120ขั้นตอนการทำงาน
- factorial(5) จะคืนค่า 5 * factorial(4)
- factorial(4) จะคืนค่า 4 * factorial(3)
- factorial(3) จะคืนค่า 3 * factorial(2)
- factorial(2) จะคืนค่า 2 * factorial(1)
- factorial(1) จะคืนค่า 1 (base case)
ดังนั้นค่า factorial(5) จะเป็น 5 * 4 * 3 * 2 * 1 = 120
การใช้ recursion ต้องระวังเรื่องการกำหนด base case ให้ถูกต้องและแน่ใจว่ามีเงื่อนไขหยุดที่ทำให้ฟังก์ชันไม่ทำงานไม่สิ้นสุดและเกิด stack overflow
Stack Overflow คืออะไร?
Stack Overflow เป็นข้อผิดพลาด (error) ที่เกิดขึ้นเมื่อหน่วยความจำที่จัดสรรให้กับ stack เต็มจนไม่สามารถจัดเก็บข้อมูลเพิ่มเติมได้ ซึ่งมักเกิดจากการเรียกใช้ฟังก์ชันซ้ำ ๆ กันในลักษณะของ recursion โดยไม่มีเงื่อนไขหยุดที่เหมาะสม ทำให้เกิดการเรียกใช้ฟังก์ชันอย่างไม่สิ้นสุด (infinite recursion)
ในการทำงานของโปรแกรม คอมพิวเตอร์จะใช้หน่วยความจำที่เรียกว่า stack เพื่อเก็บข้อมูลการเรียกใช้ฟังก์ชัน เมื่อมีการเรียกใช้ฟังก์ชันใหม่ ข้อมูลเกี่ยวกับการเรียกใช้ฟังก์ชันนั้น (เช่น พารามิเตอร์ ตัวแปรภายใน และที่อยู่ที่จะกลับไปเมื่อฟังก์ชันสิ้นสุด) จะถูกเพิ่มลงใน stack และเมื่อฟังก์ชันนั้นสิ้นสุด ข้อมูลนั้นจะถูกลบออกจาก stack
ถ้าไม่มีการหยุดการเรียกใช้ฟังก์ชันอย่างเหมาะสม ฟังก์ชันจะถูกเรียกใช้ซ้ำ ๆ และข้อมูลจะถูกเพิ่มลงใน stack เรื่อย ๆ จน stack เต็ม และเกิดข้อผิดพลาด stack overflow ขึ้น
