![](images/python_with_Birds.gif)
zsh:1: unknown file attribute: i

ฟังก์ชัน (Functions)#

55 minutes

วัตถุประสงค์#

หลังจากทำทำแล็บ นศ.จะสามารถ

  • เข้าใจหลักการของฟังก์ชันและตัวแปรในภาษาไพธอน

  • เขียนฟังก์ชันและเข้าใจการเรียกใช้ฟังก์ชัน/การส่งผ่านข้อมูล

Ref:

ฟังก์ชัน (Functions in Python)#

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

ฟังก์ชันมีคุณสมบัติดังต่อไปนี้

  • มีชื่อฟังก์ชัน

  • มีหน้าที่เฉพาะเจาะจงชัดเจน

  • มีชุดคำสั่งที่มีลำดับขั้นตอนรวมอยู่ภายใน

  • มีการส่งคืนค่ากลับ (เสมอ)

  • ถูกเรียกใช้ซ้ำๆ ได้

  • ถูกเรียกจากหลายๆ ที่ได้

ฟังก์ชันที่ใช้ในภาษาไพธอนสามารถแบ่งออกเป็น 2 ประเภทหลักๆ คือ

  1. ฟังก์ชันที่ถูกสร้างไว้แล้ว (Pre-defined function)

ฟังก์ชันที่ถูกสร้างไว้แล้ว (Pre-defined function) เป็นฟังก์ชันที่ถูกสร้างขึ้นโดยผู้พัฒนาไพธอน (ในรูปแบบ Library function) และเป็นส่วนหนึ่งของภาษาไพธอน (Built-in function) เราจึงสามารถเรียกใช้ฟังก์ชันประเภทนี้ได้ทันที เช่น ฟังก์ชัน print( ), input( ), sum( ), len( ) เป็นต้น

  1. ฟังก์ชันที่ผู้ใช้สร้างขึ้นเอง (User-Define Functions)

Built-in functions#

ในภาษาไพธอน มี Built-in function (หรือ Pre-defined function) มากมายหลายฟังก์ชัน เช่น

ฟังก์ชัน print( )

# Build-in function print()

album_ratings = [10.0, 8.5, 9.5, 7.0, 7.0, 9.5, 9.0, 9.5] 
print(album_ratings)
[10.0, 8.5, 9.5, 7.0, 7.0, 9.5, 9.0, 9.5]

ฟังก์ชัน sum( ) รับข้อมูลที่เป็น iterable เช่น ลิสต์หรือทูเพิล แล้วคืนค่ากลับเป็นผลรวมของสมาชิกทุกตัวที่อยู่ในลิสต์หรือทูเพิล

# Use sum() to add every element in a list or tuple together

sum(album_ratings)
70.0

ฟังก์ชัน len() ใช้หาขนาดของลิสต์หรือทูเพิล (จำนวนสมาชิก)

# Show the length of the list or tuple

len(album_ratings)
8

∴ หาค่าเฉลี่ยของลิส album_ratings ได้ดังนี้

sum(album_ratings)/len(album_ratings)
8.75

เราเรียกข้อมูลที่ส่งให้แก่ฟังก์ชัน (ข้อมูลที่อยู่ในวงเล็บ) เมื่อมีการเรียกฟังก์ชันว่า อาร์กิวเมนต์ (หรือ Actual Parameter)

นอกจากนี้ยังมีฟังก์ชันที่เคยผ่านตากันมาแล้ว เช่น type(), ascii(), bool(), float(), int(), str(), tuple(), list(), dict(), set(), range(), enumerate(), max(), min(), pow(), abs(), round(), slice(), sorted(), complex( ), help() และอื่นๆ อีก ดูใน Common Built‐in Functions (Quick Reference Sheet (Python-3.6)) หรือศึกษาเพิ่มเติมได้ที่ Built-in Functions in Python (python.org)

“ลำดับ (ตำแหน่ง) ของอาร์กิวเมนต์ที่ส่งให้แก่ฟังก์ชัน” สำคัญ !!

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

ยกตัวอย่างเช่น จำนวนเชิงซ้อน complex( ) มีอาร์กิวเมนต์สองตัว ตัวแรกเป็นจำนวนจริงและตัวที่สองเป็นจำนวนจินตภาพ ดังนั้น complex(3, 5) จึงไม่เท่ากับ complex(5, 3)

complex(3, 5) 
(3+5j)
help(complex)
Help on class complex in module builtins:

class complex(object)
 |  complex(real=0, imag=0)
 |  
 |  Create a complex number from a real part and an optional imaginary part.
 |  
 |  This is equivalent to (real + imag*1j) where imag defaults to 0.
 |  
 |  Methods defined here:
 |  
 |  __abs__(self, /)
 |      abs(self)
 |  
 |  __add__(self, value, /)
 |      Return self+value.
 |  
 |  __bool__(self, /)
 |      self != 0
 |  
 |  __divmod__(self, value, /)
 |      Return divmod(self, value).
 |  
 |  __eq__(self, value, /)
 |      Return self==value.
 |  
 |  __float__(self, /)
 |      float(self)
 |  
 |  __floordiv__(self, value, /)
 |      Return self//value.
 |  
 |  __format__(...)
 |      complex.__format__() -> str
 |      
 |      Convert to a string according to format_spec.
 |  
 |  __ge__(self, value, /)
 |      Return self>=value.
 |  
 |  __getattribute__(self, name, /)
 |      Return getattr(self, name).
 |  
 |  __getnewargs__(...)
 |  
 |  __gt__(self, value, /)
 |      Return self>value.
 |  
 |  __hash__(self, /)
 |      Return hash(self).
 |  
 |  __int__(self, /)
 |      int(self)
 |  
 |  __le__(self, value, /)
 |      Return self<=value.
 |  
 |  __lt__(self, value, /)
 |      Return self<value.
 |  
 |  __mod__(self, value, /)
 |      Return self%value.
 |  
 |  __mul__(self, value, /)
 |      Return self*value.
 |  
 |  __ne__(self, value, /)
 |      Return self!=value.
 |  
 |  __neg__(self, /)
 |      -self
 |  
 |  __pos__(self, /)
 |      +self
 |  
 |  __pow__(self, value, mod=None, /)
 |      Return pow(self, value, mod).
 |  
 |  __radd__(self, value, /)
 |      Return value+self.
 |  
 |  __rdivmod__(self, value, /)
 |      Return divmod(value, self).
 |  
 |  __repr__(self, /)
 |      Return repr(self).
 |  
 |  __rfloordiv__(self, value, /)
 |      Return value//self.
 |  
 |  __rmod__(self, value, /)
 |      Return value%self.
 |  
 |  __rmul__(self, value, /)
 |      Return value*self.
 |  
 |  __rpow__(self, value, mod=None, /)
 |      Return pow(value, self, mod).
 |  
 |  __rsub__(self, value, /)
 |      Return value-self.
 |  
 |  __rtruediv__(self, value, /)
 |      Return value/self.
 |  
 |  __sub__(self, value, /)
 |      Return self-value.
 |  
 |  __truediv__(self, value, /)
 |      Return self/value.
 |  
 |  conjugate(...)
 |      complex.conjugate() -> complex
 |      
 |      Return the complex conjugate of its argument. (3-4j).conjugate() == 3+4j.
 |  
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |  
 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  imag
 |      the imaginary part of a complex number
 |  
 |  real
 |      the real part of a complex number

อย่างไรก็ตาม ภาษาไพธอนสามารถเรียกใช้ฟังก์ชันแบบ Keyword Arguments ได้ ความสามารถนี้ทำให้เราไม่ต้องส่งอาร์กิวเมนต์ตามลำดับก็ได้ ดังตัวอย่างต่อไปนี้

complex(imag=5, real=3)
(3+5j)
complex(imag=5, real=3) == complex(3, 5)
True

การสร้างฟังก์ชัน#

Function syntax:

def <function_name>([<parameters>]):
    <statement-1>
        .
        .
        .
    <statement-N>

เราสามารถสร้างฟังก์ชันขึ้นเองได้ รูปแบบการประกาศฟังก์ชันมีกฎง่ายๆ มีดังนี้

ใช้คำสั่ง def และหลังจากนั้น function_name เป็นชื่อของฟังก์ชัน และในวงเล็บ () เป็นการกำหนดพารามิเตอร์ของฟังก์ชัน พารามิเตอร์ของฟังก์ชันนั้นสามารถมีจำนวนเท่าไหร่ก็ได้หรือไม่มีก็ได้ และเช่นเดียวกับภาษาอื่นๆ ฟังก์ชันอาจจะมีหรือไม่มีการส่งค่ากลับก็ได้ (สำหรับฟังก์ชันที่ไม่มีการ return ค่ากลับนั้น เราจะเรียกว่า Procedure)

  • บล็อกโค้ดฟังก์ชัน เริ่มด้วยคำสั่ง def ตามด้วยชื่อฟังก์ชัน function_name และในวงเล็บ () เป็นการกำหนดพารามิเตอร์ parameters ของฟังก์ชัน

  • พารามิเตอร์ parameters ของฟังก์ชันจะกำหนดให้มีจำนวนเท่าไหร่ก็ได้หรือไม่มีก็ได้ ถ้ามีต้องกำหนดภายในวงเล็บ พารามิเตอร์เป็นตัวแปรภายในฟังก์ชี่น ทำหน้าที่รับค่า/ข้อมูลจากภายนอก (ตอนที่มีการเรียกใช้ฟังก์ชัน)

  • หลังเครื่องหมายวงเล็บปิดจะต้องมีเครื่องหมาย colon (:) ปิดท้าย เพื่อบอกว่า จะเริ่มบล็อกคำสั่งของฟังก์ชันแล้ว

  • บล็อกคำสั่งของฟังก์ชันจะอยู่หลัง : โดยจะอยู่เยื้องย่อหน้าเข้าไป (Indentation)

  • สามารถใส่คำอธิบายการทำงานของฟังก์ชัน (เรียกว่า docstring) ก่อนบล็อกคำสั่งได้โดยเขียนอยู่ภายในเครื่องหมาย triple single quotes (‘’’…’’’) หรือ triple double quotes (“””…”””)

  • คำสั่ง return เป็นการออกจากฟังก์ชัน โดยจะส่งค่ากลับไปยังจุดที่เรียก ฟังก์ชันอาจจะมีหรือไม่มีคำสั่งนี้ก็ได้ (กรณีทีไม่มี ค่าส่งกลับจะเป็น None)

ตัวอย่าง การสร้างฟังก์ชันเพิ่มค่าให้กับพารามิเตอร์ a พิมพ์ออกหน้าจอและส่งคืนผลลัพธ์เป็น b

# First function example: Add 1 to a and store as b
def add(a):
    """
    add 1 to a
    """
    b = a + 1
    print(a, "if you add one", b)
    return(b)

ส่วนประกอบของฟังก์ชัน add( )

![](images/FuncsDefinition.png” width=”350” />

เราสามารถใช้คำสั่ง help(<function_name>) หรือใส่เครื่องหมาย ? หลังชื่อฟังก์ชัน เพื่อให้แสดงคำอธิบายของฟังก์ชัน (เรียกว่า docstring) ได้

(หากต้องการดู source code ใส่เครื่องหมาย ?? หลังชื่อฟังก์ชัน )

# Get a help on add function

help(add)
Help on function add in module __main__:

add(a)
    add 1 to a
add?
ถ้าใช้ Jupyter notebook หรือ Google colab ดู DocString ของฟังก์ชันได้โดยการกดคีย์ shift+tab

การเรียกใช้ฟังก์ชันสามารถทำได้ 2 วิธี คือ

  1. เรียกใช้จากโปรแกรมเดียวกัน (จากไฟล์เดียวกัน) และ

  2. เรียกใช้จากโปรแกรมอื่น (จากไฟล์อื่น)

ณ ที่นี้ เราจะเรียกใช้ฟังก์ชันจากโปรแกรมเดียวกัน (จากไฟล์เดียวกัน)

ส่วนวิธีเรียกใช้จากโปรแกรมอื่น (จากไฟล์อื่น) เป็นวิธีสำหรับการเขียนโปรแกรมที่มีขนาดใหญ่และมีความซับซ้อน ซึ่งมักจะนำฟังก์ชันจัดเก็บเป็นโมดูล (Module) เพื่อให้โปรแกรมต่างๆ สามารถเรียกใช้ผ่านคำสั่ง import

วิธีการเรียกใช้จากโปรแกรมอื่นจะอธิบายในภายหลัง

# Call the function add()

add(1)
1 if you add one 2
2
# Call the function add()

add(3)
3 if you add one 4
4
# For Jupyter notebook, you can hit Shift-Tab to bring up the signature and docstring of the function or class
add(3) + 4
3 if you add one 4
8

เราสามารถสร้างฟังก์ชันใหม่ได้อีก

ยกตัวอย่างเช่น ฟังก์ชันคูณตัวเลขสองตัว โดยจะใช้ตัวแปร a และ b (ฟังก์ชันนี้มีพารามิเตอร์ 2 พารามิเตอร์) รับค่าตัวเลขสองตัว

# Define a function for multiple two numbers

def Mult(a, b):
    c = a * b
    return(c)
    print('This is not printed')
    
result = Mult(12,2)
print(result)
24

เรียกฟังก์ชัน Mult( ) ซ้ำอีกครั้ง เพื่อคูณจำนวนเต็ม

# Use mult() multiply two integers

Mult(2, 3)
6

ฟังก์ชัน Mult( ) ใช้กับข้อมูลชนิดอื่นๆ ก็ได้

# Use mult() multiply two floats

Mult(10.0, 3.14)
31.400000000000002
# Use mult() multiply two different type values together

Mult(2, "Michael Jackson ")
'Michael Jackson Michael Jackson '

ฟังก์ชั้นที่ไม่มีคำสั่ง return (ส่งกลับเป็นค่าพิเศษ None)#

ฟังก์ชันในไพธอนจะคืนค่ากลับมาเสมอ ซึ่งปกติจะใช้ด้วยคำสั่ง return แต่ถ้าไม่มีคำสั่ง return ฟังก์ชันจะส่งกลับเป็นค่าพิเศษ None (By default (NoneType); null value or no value at all เป็นข้อมูลชนิดหนึ่งในไพธอน) ดังนั้น ฟังก์ชันทั้ง 2 ฟังก์ชันต่อไปนี้เหมือนกันมีค่าเท่ากัน

# Define functions, one with return value None and other without return value

def MJ():
    print('Michael' + ' ' + 'Jackson')
    
def MJ1():
    MJ()
    return(None)
# See the output

MJ()
Michael Jackson
# See the output

MJ1()
Michael Jackson

ถ้าใช้คำสั่ง print กับฟังก์ชันที่ไม่มีคำสั่ง return (ฟังก์ชันที่ไม่มีค่าคืนกลับ) จะส่งค่าคืนกลับเป็น None (By default)

# See what functions returns are

print(MJ())
print(MJ1())
Michael Jackson
None
Michael Jackson
None

ลองสร้างฟังก์ชัน con( ) สำหรับเชื่อม 2 สตริงเข้าด้วยกันโดยใช้โอเปอเรเตอร์ “+”

# Define the function for combining strings

def con(a, b):
    return(a + ' ' + b)
# Test on the con() function

con("Michael", "Jackson")
'Michael Jackson'
# Test on the con() function

con("Jackson", "Michael")
'Jackson Michael'

ลำดับของอาร์กิวเมนต์ที่อินพุตลงในฟังก์ชันต้องตรงกับลำดับของพารามิเตอร์หรือตัวแปรที่ประกาศภายในฟังก์ชัน (∵ Positional Argument)

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

# Test on the con() function

con('Michael')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In [27], line 3
      1 # Test on the con() function
----> 3 con('Michael')

TypeError: con() missing 1 required positional argument: 'b'

ตัวแปร (Variables) ในฟังก์ชัน#

รูปแบบในการเรียกฟังก์ชัน

<function_name>(<argument1, argument2, ..>)

โดยที่

  • function_name คือ ชื่อของฟังก์ชันที่ประกาศไว้ก่อนหน้านี้

  • agument คือ ค่าของข้อมูลที่เราใส่ไปในฟังก์ชัน (โดยค่าดังกล่าวจะถูกส่งผ่านไปให้ตัวแปร (parameter) ของใช้ฟังก์ชันนั้นๆ)

[ข้อควรระวัง] ลำดับของอาร์กิวเมนต์ต้องตรงกับลำดับตำแหน่งของพารามิเตอร์ที่ประกาศภายไว้ (∵ Positional Argument) ถ้าฟังก์ชันที่เรียกใช้ไม่มีพารามิเตอร์ก็ไม่ต้องใส่ค่าอาร์กิวเมนต์

เมื่อมีการเรียกฟังก์ชัน ค่าของข้อมูลที่ส่งไปให้ฟังก์ชันจะถูกเก็บในตัวแปรที่ประกาศไว้ในวงเล็บหลังชื่อของฟังก์ชัน เราเรียกตัวแปรนี้ว่า Function parameter หรือ Formal parameter

ตัวแปรที่ประกาศภายในฟังก์ชันรวมถึงพารามิเตอร์ของฟังก์ชันซึ่งถือเป็นส่วนหนึ่งของฟังก์ชั้นเป็น ตัวแปรโลคอล (Local Variable) มีขอบเขตการใช้งาน (ทั้งการเรียกใช้และการแก้ไข) เฉพาะภายในฟังก์ชันเท่านั้น! หากมีการเรียกใช้จากภายนอกฟังก์ชัน จะเกิดข้อผิดพลาดเนื่องจากไม่มีข้อมูลของตัวแปร (ยกเว้นแต่จะถูกกำหนดให้เป็นตัวแปรร่วม (ตัวแปรโกลบอล (Global Variable) เท่านั้น)

รายละเอียดระหว่าง ตัวแปรโลคอล (Local Variable) และ ตัวแปรโกลบอล (Global Variable) จะอธิบายภายหลัง

# Function Definition

def square(a):
    '''
    Square the input and add 1
    '''
    # Local variable b
    b = 1
    c = a*a + b
    print(a, "if you square + 1", c) 
    return(c)

รูปด้านล่างแสดงส่วนประกอบของฟังก์ชัน square( ) และการเรียกใช้ฟังก์ชัน

![](images/FuncsVar.png” width=”450” />

เราสามารถเรียกฟังก์ชันโดยส่งอินพุต 22 ผ่านตัวแปร x

# Initializes Global variable  

x = 22
# Makes function call and return function to z
z = square(x)
z
22 if you square + 1 485
485
# Directly enter a number as parameter

square(100)
100 if you square + 1 10001
10001

ทราบหรือไม่ว่า โค้ดในรูปภาพข้างต้น ตัวแปรใดเป็นพารามิเตอร์ของฟังก์ชัน square() ตัวแปรใดเป็นตัวแปรโลคอล (Local Variable) และตัวแปรใดเป็นตัวแปรโกลบอล (Global Variable) บ้าง??

# Check your answer

รายละเอียดของขอบเขตของตัวแปร (Scope of a Variable) จะอธิบายอีกครั้งภายหลัง

อาร์กิวเมนต์ (Argument) และ พารามิเตอร์ (Parameter) ต่างกัน/?

อาร์กิวเมนต์ (หรือ Actual Parameter) คือข้อมูลที่ส่งให้แก่ฟังก์ชันเมื่อมีการเรียกใช้ฟังก์ชัน เมื่อมีการเรียกใช้ฟังก์ชันโดยการส่งอาร์กิวเมนต์ให้แก่ฟังก์ชัน ค่าของอาร์กิวเมนต์จะถูกก๊อปปี้ให้กับพารามิเตอร์ที่สัมพันธ์กันภายในฟังก์ชัน (ฉะนั้น Argument != Parameter)

พารามิเตอร์ (หรือ Formal parameter) คือตัวแปร (Parameter variable) ที่รับข้อมูลจากภายนอกเข้ามาใช้ภายในฟังก์ชัน.

ต่างกันตรงที่มุมมอง ว่ามองจากมุมไหน ถ้ามองในมุมของโปรแกรมย่อย (ฟังก์ชัน) จะเรียกว่าพารามิเตอร์ แต่ถ้ามองในมุมของโปรแกรมที่เรียกใช้จะเรียกว่าอาร์กิวเมนต์

Src: Programming FAQ: What is the difference between arguments and parameters?

ฟังก์ชันทำให้การเขียนโปรแกรมทำได้ง่ายขึ้น#

เรามาพิจารณาบล๊อก Block 1 และ Block 2 ทั้งสองบล็อกทำงานเหมือนกัน ต่างกันเพียงชื่อตัวแปรและค่าต่างๆ

Block 1:

# a and b calculation block1

a1 = 4
b1 = 5
c1 = a1 + b1 + 2 * a1 * b1 - 1
if(c1 < 0):
    c1 = 0 
else:
    c1 = 5
c1   
5

Block 2:

# a and b calculation block2

a2 = 0
b2 = 0
c2 = a2 + b2 + 2 * a2 * b2 - 1
if(c2 < 0):
    c2 = 0 
else:
    c2 = 5
c2   
0

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

โค้ดใน Block 1 และ code Block 2 ข้างต้น เขียนเป็นฟังก์ชันได้ดังนี้

# Make a Function for the calculation above

def Equation(a,b):
    c = a + b + 2 * a * b - 1
    if(c < 0):
        c = 0 
    else:
        c = 5
    return(c) 

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

![](images/FuncsPros.gif” width=”700” />

โค้ด Block 1 และ code Block 2 เขียนใหม่เป็น Block 3 และ code Block 4

Block 3:

a1 = 4
b1 = 5
c1 = Equation(a1, b1)
c1
5

Block 4:

a2 = 0
b2 = 0
c2 = Equation(a2, b2)
c2
0

ฟังก์ชันทำให้การเขียนโปรแกรมทำได้ง่ายขึ้น โปรแกรมสั้นกระชับและอ่านง่ายได้ขึ้น


การใช้คำสั่ง if/else และคำสั่งลูปในฟังก์ชัน#

เราสามารถคืนค่ากลับแบบมีเงื่อนไขได้โดยใช้คำสั่ง if และคำสั่ง return()

# Function example

def type_of_album(artist, album, year_released):
    print(artist, album, year_released)
    if year_released > 1980:
        return "Modern"
    else:
        return "Oldie"
    
x = type_of_album("Michael Jackson", "Thriller", 1980)
print(x)
Michael Jackson Thriller 1980
Oldie

เขียนฟังก์ชันสั่งให้ print( ) สมาชิกทุกตัวที่อยู่ในลิสต์โดยใช้คำสั่งวนลูป (For loop)

# Print the list using for loop

def PrintList(the_list):
    for element in the_list:
        print(element)
# Implement the printlist function

PrintList(['1', 1, 'the man', "abc", ('x','y')])
1
1
the man
abc
('x', 'y')
# Implement the printlist function

PrintList('愛している')
愛
し
て
い
る

การกำหนดค่าเริ่มต้น (ค่าปริยาย) ให้กับอาร์กิวเมนต์ (Default argument)#

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

รูปแบบในการกำหนดค่าปริยายให้กับอาร์กิวเมนต์ : อาร์กิวเมนต์ที่มีการกำหนดค่าเริ่มต้น (ค่าปริยาย) จะต้องอยู่ทางขวาสุดเสมอ นั่นหมายความว่า อาร์กิวเมนต์ที่ไม่มีกำหนดค่าเริ่มต้นจะต้องอยู่ทางซ้ายสุดเสมอ

ฟังก์ชัน isGoodRating() ต่อไปนี้ กำหนดค่าปริยายให้กับอาร์กิวเมนต์ (rating) เป็น 4

# Example for setting param with default value

def isGoodRating(rating=4): 
    if(rating < 7):
        print("this album sucks, it's rating is",rating)
        
    else:
        print("this album is good, its rating is",rating)
# Test the value with default value and with input

isGoodRating()
isGoodRating(10)
this album sucks, it's rating is 4
this album is good, its rating is 10

อีกตัวอย่าง ฟังก์ชัน greeting() ต่อไปนี้ มี 2 อาร์กิวเมนต์ คือ name และ msg

# Python Function Arguments: Positional, Keywords and Default
def greeting(name, msg):
    """This function greets to
    the person with the provided message
    The arguments name and msg are expected to be of type str."""
    print("Hello", name + ', ' + msg)

greeting("Michael", "Good morning!")
Hello Michael, Good morning!
greeting("Michael") # only one argument: TypeError: greeting() missing 1 required positional argument: 'msg'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In [44], line 1
----> 1 greeting("Michael")

TypeError: greeting() missing 1 required positional argument: 'msg'
greeting() # no arguments: TypeError: greeting() missing 2 required positional arguments: 'name' and 'msg'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In [45], line 1
----> 1 greeting()

TypeError: greeting() missing 2 required positional arguments: 'name' and 'msg'

เพิ่มความยืดหยุ่น โดยการกำหนดค่าเริ่มต้น (ค่าปริยาย) ให้กับอาร์กิวเมนต์ (Default argument)

# Python Function Arguments: Positional, Keywords and Default
def greeting(name, msg="Good morning!"):
    """This function greets to
    the person with the provided message
    The arguments name and msg are expected to be of type str."""
    print("Hello", name + ', ' + msg)

greeting("Michael")
greeting("John", "How do you do?")
Hello Michael, Good morning!
Hello John, How do you do?

แต่ถ้าเราลองสลับตำเหน่งของพารามิเตอร์ จะเกิดอะไรขึ้น? → เกิด SyntaxError: non-default argument follows default argument

def greeting(msg="Good morning!", name):
    """This function greets to
    the person with the provided message
    The arguments name and msg are expected to be of type str."""
    print("Hello", name + ', ' + msg)

greeting("Michael")
  Cell In [47], line 1
    def greeting(msg="Good morning!", name):
                 ^
SyntaxError: non-default argument follows default argument

SyntaxError: non-default argument follows default argument คือ ???

อาร์กิวเมนต์ที่มีการกำหนดค่าเริ่มต้น (ค่าปริยาย) จะต้องอยู่ทางขวาสุด **ส่วนอาร์กิวเมนต์ที่ไม่มีกำหนดจะต้องอยู่ทางซ้ายสุดเสมอ**

การเรียกฟังก์ชันในรูปแบบระบุคีย์เวิร์ด (Keyword Arguments)#

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

แต่ถ้าใช้อาร์กิวเมนต์แบบระบุคีย์เวิร์ด ในรูปแบบ “keyword = value” แล้วหละก็ ฟังก์ชันจะสามารถรับชื่อตัวแปรและค่าของตัวแปรเป็นเซ็ทๆ ได้ทำให้สามารถส่งผ่านอาร์กิวเมนต์ไปยังฟังก์ชันได้โดยที่ไม่ต้องเรียงตามลำดับตามที่กำหนดไว้ในฟังก์ชัน

# No Keyword Argument
greeting("How do you do?", "John")
Hello How do you do?, John
# with Keyword Arguments
greeting(msg = "How do you do?", name = "John")
Hello John, How do you do?
greeting('Jan')
Hello Jan, Good morning!

ฟังก์ชันและตัวแปรประเภท Collections** (Arbitrary Arguments)#

**ตัวแปรประเภท Collections เป็นประเภทที่จัดเก็บข้อมูลรวมกันเป็นชุดเดียว และใช้ชื่อตัวแปรเดียว โดยในกลุ่ม Collections จะมีตัวแปร 4 ชนิดได้แก่ List, Tuple, Set, Dictionary

ในกรณีที่เราไม่ต้องการระบุจำนวนอาร์กิวเมนต์ของฟังก์ชัน เราสามารถ ระบุอาร์กิวเมนต์แบบอ้างอิง (Reference) โดยมีรูปแบบคือ

Function syntax:

def <function_name>([<normal_parameter>, <*tuple_parameter>, <**dictionary_parameter>]):
    <statement-1>
    <statement-2>
    ...
    <statement-N>

ใช้เครื่องหมายดอกจันทร์ (asterisk) หนึ่งอัน (*) และสองอัน (**) นำหน้าชื่อของพารามิเตอร์

แต่โปรเกรมเมอร์ส่วนใหญ่จะใช้ *args และ **kwargs แทน *tuple_parameter และ **dictionary_parameter ตามลำดับ เนื่องจากสะดวกนั่นเอง

  • *tuple_parameter (*args) - อาร์กิวเมนต์ (Areguments) จำนวนใดๆ

  • **dictionary_parameter (**kwargs) - คีย์เวิร์ดอาร์กิวเมนต์ (Keyword arguments) จำนวนใดๆ


ดังนั้น เขียนใหม่ได้ว่า

**Function syntax:**

```python
def <function_name>([<args>, <*argsr>, <**kwargs>]):
    <statement-1>
    <statement-2>
    ...
    <statement-N>

(ในภาษาไพธอนไม่มีการใช้พอยน์เตอร์ (pointer) เหมือนในภาษาอื่นๆ เช่น C, C++, Java)

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

def printAll(*args): # All the arguments are 'packed' into args which can be treated like a tuple
    #print("Type of arguments:", type(args)) 
    print("Number of arguments:", len(args)) 
    for argument in args:
        print(argument)
        
#printAll with 3 arguments
printAll('Horsefeather','Adonis','Bone')
#printAll with 4 arguments
printAll('Sidecar','Long Island','Mudslide','Carriage')
Number of arguments: 3
Horsefeather
Adonis
Bone
Number of arguments: 4
Sidecar
Long Island
Mudslide
Carriage
def printAll(args: tuple):
    print("Number of arguments:", len(args)) 
    for argument in args:
        print(argument)
         
#printAll with 3 arguments
printAll(('Horsefeather','Adonis','Bone')) # กรณีนี้ ตอนส่ง ต้องส่งในรูปของ Tuple!!
#printAll with 4 arguments
printAll(('Sidecar','Long Island','Mudslide','Carriage'))
Number of arguments: 3
Horsefeather
Adonis
Bone
Number of arguments: 4
Sidecar
Long Island
Mudslide
Carriage

ตัวอย่าง ฟังก์ชันที่มีอาร์กิวเมนต์ที่เป็นดิกชันนารี (อาร์กิวเมนต์ทั้งหมดถูกแพ็คลงในดิกชันนารี) ทั้งสองตัวอย่างต่อไปนี้ทำงานเหมือนกัน แต่การเรียกใช้งานต่างกัน!

def printDictionary(**kwargs):
    #print("Type of arguments:", type(kwargs)) 
    for key in kwargs:
        print(key + " : " + kwargs[key])

printDictionary(CountryID='CA', Country='Canada', City='Toronto')
printDictionary(CountryID='TH', Country='Thailand', City='Bangkok')
CountryID : CA
Country : Canada
City : Toronto
CountryID : TH
Country : Thailand
City : Bangkok
dic_t = {'CountryID':'TH', 'Country':'Thailand','City':'Bangkok'}
dic_t
{'CountryID': 'TH', 'Country': 'Thailand', 'City': 'Bangkok'}
def printDictionary(kwargs: dict):
    for key in kwargs:
        print(key + " : " + kwargs[key])

printDictionary(dic_t)
CountryID : TH
Country : Thailand
City : Bangkok

แต่ถ้าเรียกแบบนี้ เกิด TypeError เนื่องจากอาร์กิวเมนต์ที่ส่งไม่เป็นข้อมูลชนิด dict

#printDictionary(CountryID='TH', Country='Thailand', City='Bangkok')

ต้องส่งอาร์กิวเมนต์ที่เป็นข้อมูลชนิด dict เท่านั้น

printDictionary(dict(CountryID='TH', Country='Thailand', City='Bangkok'))
CountryID : TH
Country : Thailand
City : Bangkok

ข้อควรระวัง กรณีของฟังก์ชันที่มีอาร์กิวเมนต์ที่เป็นลิสต์

def addItems(list):
    list.append("Three")
    list.append("Four")

myList = ["One","Two"]

addItems(myList)

myList
    
['One', 'Two', 'Three', 'Four']
addItems(myList)
myList
['One', 'Two', 'Three', 'Four', 'Three', 'Four']

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

เนื่องจากลิสส่งค่าโดยใช้การอ้างอิง (Pass by Reference) ซึ่งการส่งแบบนี้จะไม่มีการสร้างสำเนาเก็บค่าของตัวแปร แต่จะเป็นการอ้างอิงตำแหน่งในหน่วยความจำของตัวแปร ทำให้ตัวแปรที่ส่งไปยังฟังก์ชันและตัวแปรในฟังก์ชันใช้หน่วยความจำร่วมกัน ดังนั้นเมื่อตัวแปรในฟังก์ชันมีการเปลี่ยนค่า ตัวแปรที่ส่งค่าไปก็จะเปลี่ยนค่าด้วย ดังนั้น ควรระมัดระวังกรณีที่ส่งผ่านอ็อบเจกต์ชนิด mutable ไปยังฟังก์ชัน


ตัวอย่างข้างต้นเป็นฟังก์ชันที่มีอาร์กิวเมนต์ *args หรือ **kwargs อย่างใดอย่างหนึ่งเท่านั้น แต่เรายังสามารถสร้างฟังก์ชันที่มีอาร์กิวเมนต์ทั้ง *args และ **kwargs รวมกันได้ เพรียงแต่ *args จะต้องอยู่ก่อน (อยู่ทางซ้าย) **kwargs เสมอ

ขอบเขตของตัวแปร (Scope of a Variable)#

“ขอบเขตของตัวแปร” คือสิ่งที่ใช้กำหนดว่า ตัวแปรที่ประกาศขึ้นมา จะสามารถเรียกใช้งานจากที่ไหนได้บ้าง.

ตัวอย่างต่อไปนี้ ตัวแปร myFavouriteBand เป็นตัวแปรโกลบอล (Global Variable) สามารถเข้าถึงได้จากทุกๆ ส่วนในโปรแกรม เช่น ภายในฟังก์ชัน getBandRating( ) ก็สามารถเข้าถึงตัวแปรนี้ได้

# Example of global variable

myFavouriteBand = "AC/DC"

def getBandRating(bandname):
    if bandname == myFavouriteBand:
        return 10.0
    else:
        return 0.0

print("AC/DC's rating is:", getBandRating("AC/DC"))
print("Deep Purple's rating is:",getBandRating("Deep Purple"))
print("My favourite band is:", myFavouriteBand)
AC/DC's rating is: 10.0
Deep Purple's rating is: 0.0
My favourite band is: AC/DC

ตัวอย่างต่อไปนี้ ตัวแปร myFavouriteBand เป็นตัวแปรโลคอล (Local Variable) เนื่องจากถูกประกาศภายในฟังก์ชัน getBandRating( ) นั่นหมายความว่าสามารถเข้าถึงเฉพาะภายในฟังก์ชัน getBandRating( ) เท่านั้น (ถ้าเรียกใช้จะเกิดความผิดพลาดหรือเออเรอร์ NameError: name ‘myFavouriteBand’ is not defined)

# Deleting the variable "myFavouriteBand" from the previous example to demonstrate an example of a local variable 

del myFavouriteBand

# Example of local variable

def getBandRating(bandname):
    myFavouriteBand = "AC/DC"
    if bandname == myFavouriteBand:
        return 10.0
    else:
        return 0.0

print("AC/DC's rating is: ", getBandRating("AC/DC"))
print("Deep Purple's rating is: ", getBandRating("Deep Purple"))
print("My favourite band is", myFavouriteBand)
AC/DC's rating is:  10.0
Deep Purple's rating is:  0.0
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [61], line 16
     14 print("AC/DC's rating is: ", getBandRating("AC/DC"))
     15 print("Deep Purple's rating is: ", getBandRating("Deep Purple"))
---> 16 print("My favourite band is", myFavouriteBand)

NameError: name 'myFavouriteBand' is not defined

ตัวอย่างสุดท้าย

เรามีตัวแปร myFavouriteBand 2 ตัวแปร (ชื่อเดียวกัน) ตัวแรกเป็นตัวแปรโกลบอล ตัวที่สองเป็นตัวแปรโลคอลอยู่ภายในฟังก์ชัน getBandRating( )

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

# Example of global variable and local variable with the same name

myFavouriteBand = "AC/DC"

def getBandRating(bandname):
    myFavouriteBand = "Deep Purple"
    if bandname == myFavouriteBand:
        return 10.0
    else:
        return 0.0

print("AC/DC's rating is:",getBandRating("AC/DC"))
print("Deep Purple's rating is: ",getBandRating("Deep Purple"))
print("My favourite band is:",myFavouriteBand)
AC/DC's rating is: 0.0
Deep Purple's rating is:  10.0
My favourite band is: AC/DC
  • ตัวแปรที่ประกาศภายในฟังก์ชันหรือใน Local scope จะเรียกว่า ตัวแปรโลคอล (Local Variable) มีขอบเขตการใช้งาน (ทั้งการเรียกใช้และการแก้ไข) เฉพาะภายในฟังก์ชันเท่านั้น ดังนั้น ตัวแปรที่ประกาศภายในฟังก์ชันรวมถึงพารามิเตอร์ของฟังก์ชันซึ่งถือเป็นส่วนหนึ่งของฟังก์ชั้น จะมีขอบเขตการใช้งานเฉพาะภายในฟังก์ชันเท่านั้น! หากทำการเรียกจากภายนอกฟังก์ชัน จะเกิดข้อผิดพลาดเนื่องจากไม่มีข้อมูลของตัวแปร (เว้นแต่จะถูกกำหนดให้เป็นตัวแปรร่วมโดยใช้คีย์เวิร์ด global เท่านั้น)

  • ตัวแปรที่ประกาศภายนอกฟังก์ชันหรือใน Global scope จะเรียกว่า ตัวแปรโกลบอล (Global Variable) สามารถเรียกใช้งานได้ทั้งโปรแกรม ไม่ว่าจะภายในหรือภายนอกฟังก์ชัน แต่การแก้ไขจะทำได้เฉพาะใน Global scope เท่านั้นไม่สามารถแก้ไขภายในฟังก์ชันได้

ตัวแปรโกลบอล (Global Variable)#

ตัวแปรที่ประกาศภายนอกฟังก์ชันเป็น ตัวแปรโกลบอล (Global Variable) สามารถที่จะถูกเรียกดูข้อมูลหรือเรียกใช้งานได้ทั้งภายในและภายนอกฟังก์ชันได้ ในขณะที่ตัวแปรที่ประกาศภายในฟังก์ชันเป็น ตัวแปรโลคอล (Local Variable) สามารถที่จะถูกเรียกหรือแก้ไขได้เฉพาะภายในฟังก์ชันเท่านั้น

ลองรั้นฟังก์ชัน printer1( ) ดูผลลัพธ์ที่เกิดขึ้น

# Example of global variable

artist = "Michael Jackson"
def printer1(artist):
    internal_var = artist
    print(artist, "is an artist")
    
printer1(artist)
# try runningthe following code
#printer1(internal_var) 
Michael Jackson is an artist

ทำไมถึงเกิดข้อผิดพลาด Name Error: name ‘internal_var’ is not defined.

เพราะว่าตัวแปรที่ประกาศภายในฟังก์ชันเป็น ตัวแปรโลคอล (Local Variable) ไม่สามารถที่จะถูกเรียกจากภายในฟังก์ชันได้

แต่ก็มีวิธีที่จะเปลี่ยนตัวแปรในฟังก์ชันให้เป็น ตัวแปรโกลบอล (Global Variable) ได้ ดังตัวอย่างต่อไปนี้

artist = "Michael Jackson"

def printer(artist):
    global internal_var 
    internal_var= "Whitney Houston"
    print(artist,"is an artist")

printer(artist) 
printer(internal_var)
Michael Jackson is an artist
Whitney Houston is an artist

Note

การเขียนโปรแกรมที่ดีไม่ควรเรียกใช้ตัวแปรนอกเขตของตัวเอง ทั้งนี้เพื่อไม่ให้เกิดความสับสน โดยเฉพาะในกรณีของโปรแกรมที่มีขนาดใหญ่

[Exersice] Scope of variables#

  1. หลังจากรันโค้ดต่อไปนี้ Output บนหน้าจอเป็นอย่างไร? (เพราะเหตุใด จงอธิบาย)

def f(x):
    x *= 5
    return x

def g(x):
    y = f(x**2)
    z = f(x**3)
    return y + z

print(g(2))
# Write your code below and press Shift+Enter to execute
  1. หลังจากรันโค้ดต่อไปนี้ Output พรินท์ออกหน้าจอเป็นอย่างไร? (เพราะเหตุใด จงอธิบาย)

def f(x):
    x += 8
    return round(x / 6)

def g(x):
    x *= 15
    return 2 * f(x)

def h(x):
    x += 2
    return f(x+1) + g(x)

print(h(f(1)))
# Write your code below and press Shift+Enter to execute
  1. หลังจากรันโค้ดต่อไปนี้ Output พรินท์ออกหน้าจอเป็นอย่างไร?

g = 110

def f(x):
    return x + g

print(f(5))
print(f(10))
print(g)
# Write your code below and press Shift+Enter to execute
  1. หลังจากรันโค้ดก่อนหน้าตามด้วยการรันโค้ดต่อไปนี้ Output พรินท์ออกหน้าจอเป็นอย่างไร?

def f(x):
    global g
    g += 1
    return x + g

print(f(5))
print(f(6))
print(g)
# Write your code below and press Shift+Enter to execute

[Exercise] Functions#

1 สร้างฟังก์ชัน div( ) ที่คำนวณค่า อินพุตตัวแรกหารด้วยอินพุตตัวที่สอง

# Write your code below and press Shift+Enter to execute

2 จากฟังก์ชัน con( ) ที่กำหนดต่อไปนี้ จงตอบคำถาม

# Use the con function for the following question

def con(a, b):
    return(a + b)

2.1 ฟังก์ชัน con ที่ประกาศไป สามารถใช้บวกตัวเลขจำนวนเต็ม (int) สองจำนวนหรือสตริง (str) สองข้อความได้หรือไม่

# Write your code below and press Shift+Enter to execute

2.2 ฟังก์ชัน con ที่ประกาศไป สามารถใช้กับข้อมูลประเภท Collections เช่น lists หรือ tuples ได้หรือไม่?

# Write your code below and press Shift+Enter to execute

””Stay Hungry Stay Foolish” - Steve Jobs (2005)


Author#

S.C.

Change Log#

Date

Version

Change Description

08-08-2021

0.1

First edition