คลาส (Classes) และออบเจ็ค (Objects)
ในบทนี้ คุณได้เรียนรู้เกี่ยวกับโมดูลในภาษา Python และได้ทราบว่าการใช้งานโมดูลนั้นสามารถช่วยแบ่งโค้ดออกเป็นส่วนๆ และเรียกใช้งานได้เมื่อต้องการ เราได้พูดถึงการสร้างและการใช้งานโมดูลโดยการนำเข้าโมดูลด้วยคำสั่ง import
และคำสั่ง from import การจัดหมวดหมู่ของโมดูลด้วย Package นี่เป็นสิ่งที่สำคัญเมื่อโปรแกรมของคุณมีขนาดใหญ่ขึ้น คุณอาจจะแบ่งมันออกเป็นส่วนๆ โดยแยกเป็นโมดูล และจัดกลุ่มของโมดูลด้วยการใช้ Package และนอกจากนี้ คุณยังสามารถสร้างไลบรารี่ของคุณ เพื่อให้นักพัฒนาคนอื่นๆ ได้ใช้งาน
ก่อนที่จะเริ่มต้น มาทำความเข้าใจกับคำศัพท์ที่จำเป็นต้องทราบสำหรับการเขียนโปรแกรมเชิงวัตถุในภาษา Python
- คลาส คือประเภทข้อมูลที่สร้างโดยผู้ใช้ โดยจะนำไปใช้สร้างออบเจ็ค กล่าวอีกนัยหนึ่ง คลาสคือประเภทข้อมูลของออบเจ็ค
- ออบเจ็ค คือสิ่งที่สร้างมาจากคลาสหรือ class instances
- แอตทริบิวต์ (instance attributes) คือข้อมูลที่เป็นสมาชิกของแต่ละออบเจ็ค โดยมักจะกำหนดไว้ในเมธอด
__init__()
ของคลาส - เมธอด คือฟังก์ชันการทำงานที่กำหนดไว้ในคลาส
- คลาสแอตทริบิวต์ (class attributes) คือตัวแปรที่ประกาศไว้ในคลาส ซึ่งจะแชร์กับออบเจ็คทั้งหมดที่สร้างจากคลาสนั้นๆ
คลาสคืออะไร
คลาส คือสิ่งที่ใช้กำหนดรูปแบบของข้อมูล (Attributes) และเมธอด (Methods) การทำงานเข้าด้วยกัน การสร้างคลาส หมายถึงการสร้างประเภทของออบเจ็คขึ้นมา กล่าวอีกนัยหนึ่ง คลาสคือประเภทข้อมูลของออบเจ็คโดยคลาสนั้นสร้างขึ้นโดยผู้ใช้ (User-defined type) โดยปกติแล้ว ประเภทข้อมูลพื้นฐานในภาษา Python นั้นคือคลาส เมื่อคุณสร้างตัวแปรใดๆ ขึ้นมา ตัวแปรเหล่านั้นเป็นออบเจ็คของคลาส เพื่อทำให้คุณเข้าใจมากขึ้นมาดูตัวอย่างต่อไปนี้
a = 1
b = 1.34
c = 'marcuscode.com'
print(type(a))
print(type(b))
print(type(c))
ในตัวอย่าง เราได้ประกาศตัวแปรสามตัวคือ Integer Floating และ String ตามลำดับ ดังนั้นตัวแปรเหล่านี้ถือว่าเป็นออบเจ็คของคลาส ดังผลลัพธ์ข้างล่าง
<class 'int'>
<class 'float'>
<class 'str'>
เหมือนที่คุณเห็น เราใช้ฟังก์ชัน type()
เพื่อดูประเภทข้อมูลของออบเจ็คใดๆ หรือใช้สำหรับดูประเภทของคลาสที่มันสร้างมาจาก จากตัวอย่างนั้น เราเรียกคลาส int
float
และ str
ว่า build-in type สำหรับในบทนี้ เรากำลังจะพูดเกี่ยวกับการสร้างคลาสซึ่งเป็น User-defined type นั่นเอง
การสร้างคลาสและออบเจ็ค
คลาส จะประกอบไปด้วยสมาชิกสองประเภท คือ แอตทริบิวต์หรือตัวแปร ที่ใช้ในการเก็บข้อมูลภายในคลาสนั้นๆ และเมธอด (methods) เป็นฟังก์ชันการทำงานหรือจัดการข้อมูลในคลาสนั้น เมธอดนั้นคล้ายกับฟังก์ชัน แต่ในบริบทของการเขียนโปรแกรมเชิงวัตถุแล้วเราจะเรียกว่าเมธอดแทน เพราะว่ามันถูกประกาศอยู่ภายในคลาส นี่เป็นรูปแบบของการสร้างคลาสในภาษา Python
class ClassName:
# statements
เราจะใช้คำสั่ง class
สำหรับสร้างคลาสในภาษา Python และตามด้วยชื่อของคลาส ClassName
ชื่อของคลาสควรจะขึ้นต้นด้วยตัวใหญ่และเป็นรูปแบบ camel case หลังจากนั้นเป็นคำสั่งในการกำหนดตัวแปรและเมธอดของคลาส ต่อไปมาดูตัวอย่างการสร้างคลาสในภาษา Python
class Book:
def __init__(self, name, price):
self.name = name
self.price = price
def getDetail(self):
print('Name: %s' % self.name)
print('Price: %d USD' % self.price)
ในตัวอย่าง เราได้สร้างคลาส Book
และภายในมีเมธอด __init__()
ซึ่งเป็นคอนสตรัคเตอร์ (Constructor) ซึ่งจะถูกเรียกอัตโนมัติเมื่อออบเจ็คถูกสร้างสำเร็จ พารามิเตอร์แรกของเมธอดจะเป็น self
เสมอ นี่จะใช้เป็นตัวแปรในการอ้างถึงออบเจ็คปัจจุบัน คลาสนี้จะมีสองแอตทริบิวต์คือ name
และ price
ใช้สำหรับเก็บชื่อและราคาของหนังสือของแต่ละออบเจ็ค หลังจากที่เราได้สร้างคลาสเสร็จแล้ว ต่อไปเราจะนำมาสร้างออบเจ็ค
b1 = Book('Python language', 59)
b2 = Book('C++ language', 69)
b1.getDetail()
b2.getDetail()
b1.price = 99
b1.getDetail()
ในตัวอย่าง เราได้สร้างตัวแปรออบเจ็คจากคลาส Book
สองตัวแปร คือ b1
และ b2
สำหรับพารามิเตอร์แรกในคอนสตรัคเตอร์นั้นเราได้ละเว้นไป เพราะ Python จะใส่เป็นออบเจ็คปัจจุบันให้อัตโนมัติ ดังนั้นพารามิเตอร์ที่เราจะต้องใส่คือชื่อและราคาของหนังสือ
หลังจากที่ออบเจ็คถูกสร้างแล้ว ทั้ง b1
และ b2
จะมีแอตทริบิวต์ name
price
และเมธอด getDetail()
เป็นของตัวเองที่ไม่เกี่ยวข้องกัน ในการเข้าถึงสมาชิกภายในออบเจ็คจะใช้เครื่องหมายจุด (.) ดังนั้นเมื่อเราเรียก b1.getDetail()
จะเป็นการแสดงรายละเอียดข้อมูลในออบเจ็ค b1
ซึ่ง b2
ก็เช่นเดียวกัน และต่อมาเราได้เปลี่ยนค่า price
ของออบเจ็ค b1
ให้มีค่าเป็น 99 และแสดงรายละเอียดอีกครั้ง และนี่เป็นผลลัพธ์การทำงานของโปรแกรม
Name: Python language
Price: 59 USD
Name: C++ language
Price: 69 USD
Name: Python language
Price: 99 USD
ในตอนนี้ คุณได้เห็นแล้วว่าคลาสหนึ่งคลาสสามารถนำไปสร้างเป็นออบเจ็คกี่อันก็ได้ ซึ่งนี่เองถือว่าเป็นแนวคิดที่สำคัญของการเขียนโปรแกรมเชิงวัตุในการนำโค้ดกลับมาใช้ซ้ำ
หลังจากที่คุณได้เห็นการประกาศคลาสและสร้างออบเจ็คในเบื้องต้นแล้ว ต่อไปมาดูตัวอย่างเพิ่มเติมสำหรับการทำงานกับคลาสในภาษา Python
class Person:
def __init__(self, firstName, lastName):
self.firstName = firstName
self.lastName = lastName
def getName(self):
return self.firstName + ' ' + self.lastName
p = Person('Chase', 'Rice')
p.career = 'Singer'
p.country = 'USA'
print('Name: ' + p.getName())
print('Career: ' + p.career)
print('Country: ' + p.country)
p2 = Person('Max', 'Graham')
p2.genres = ['Electronica', 'trance', 'tech house', 'techno']
print('Name: ' + p2.getName())
print('Genres: ', p2.genres)
ในตัวอย่าง เราได้สร้างคลาส Person
ที่ประกอบไปด้วยแอตทริบิวต์ firstName
และ lastName
และเมธอด getName()
สำหรับรับชื่อกับนามสกุลพร้อมกัน และเราได้กำหนดค่าให้กับแอตทริบิวต์ career
และ country
ในภายหลัง ซึ่งโดยปกติแล้วในการกำหนดแอตทริบิวต์เริ่มต้นควรจะทำในเมธอด __init__()
ดังนั้น นี่จะทำให้คุณเห็นว่าในภาษา Python เราสามารถสร้างแอตทริบิวต์ใดๆ ในขณะที่โปรแกรมทำงานได้
Name: Chase Rice
Career: Singer
Country: USA
Name: Max Graham
นี่เป็นผลลัพธ์การทำงานของโปรแกรม คุณได้เห็นแล้วว่าการเขียนโปรแกรมในภาษา Python นั้นค่อนข้างยืดหยุ่น คุณไม่จำเป็นต้องประกาศแอตทริบิวต์ทั้งหมดไว้ในตอนแรกก็ได้ คุณอาจจะเพิ่มเข้ามาในภายหลังเฉพาะออบเจ็คที่ต้องการได้ เหมือนในออบเจ็ค p2
ไม่ได้ต้องการมีแอตทริบิวต์เหมือนกับออบเจ็ค p
แต่ทั้งสองยังมีแอตทริบิวต์บางอย่างที่เหมือนกัน
Constructor และ Destructor
ต่อมาเราจะพูดเกี่ยวกับการใช้งาน Constructor และ Destructor ในภาษา Python นั้นมีเมธอดพิเศษ (Special methods) ที่สร้างให้อัตโนมัติเมื่อคุณสร้างคลาสขึ้นมา เพื่อใช้งานเราจะต้อง override เมธอดเหล่านั้น เมธอดแรกคือ __init__()
ซึ่งเมธอดนี้จะทำงานเมื่อออบเจ็คถูกสร้างสำเร็จ หรือเรียกว่า Constructor มันมักจะใช้ในการกำหนดแอตทริบิวต์และค่าเริ่มต้นให้กับออบเจ็ค ต่อมาคือเมธอด __del__()
ซึ่งเมธอดนี้จะทำงานเมื่อออบเจ็คถูกทำลาย หรือเรียกว่า Destructor มาดูตัวอย่างการใช้งาน
class Person:
def __init__(self, firstName, lastName):
self.firstName = firstName
self.lastName = lastName
print('Object was created')
def getName(self):
return self.firstName + ' ' + self.lastName
def __del__(self):
print('Object was destroyed')
p = Person('Chase', 'Rice')
print(p.getName())
del p
ในตัวอย่าง เราได้ทำการ override เมธอด __init__()
มันถูกเรียกอัตโนมัติเมื่อเราสร้างออบเจ็คสำเร็จ จากคำสั่ง Person('Chase', 'Rice')
หลังจากนั้นเราได้ทำการ override เมธอด __del__()
ซึ่งเมธอดนี้จะถูกเรียกใช้งานก่อนที่ออบเจ็คจะถูกทำลาย ในโค้ดเราได้ทำลายออบเจ็คด้วยคำสั่ง del p
ซึ่งจะทำให้ออบเจ็คถูกลบออกไปจากหน่วยความจำ
Object was created
Chase Rice
Object was destroyed
นี่เป็นผลลัพธ์การทำงานของโปรแกรม เมื่อสร้างออบเจ็คสำเร็จเราได้แสดงข้อความในเมธอด __init__()
ว่าสร้างออบเจ็คสำเร็จแล้ว และเมื่อเราลบออบเจ็คโปรแกรมแสดงข้อความในเมธอด __del__()
ว่าออบเจ็คถูกทำลายไปแล้ว ซึ่งการทำงานเหล่านี้จะเกิดขึ้นอัตโนมัติ แน่นอนว่าในภาษา Python เรามักจะใช้คอนสตรัคเตอร์เสมอ แต่ว่า Destructor มักจะไม่ได้ใช้บ่อยนัก อย่างไรก็ตามยังมีเมธอดพิเศษอื่นๆ อีกที่เรายังไม่ได้พูดถึงในบทนี้
Static variables และ Static methods
สำหรับเรื่องสุดท้ายที่คุณจะได้เรียนในบทนี้ คือการใช้งาน static variable และ static method โดย static variable หรือคลาสแอตทริบิวต์ คือตัวแปรที่ประกาศภายในคลาสซึ่งตัวแปรนี้จะแชร์กับออบเจ็คทุกอันที่สร้างจากคลาสนี้ ส่วน static method เป็นเมธอดที่สร้างไว้ในคลาสแต่ไม่ได้มีส่วนเกี่ยวกับข้องกับการจัดการออบเจ็ค มาดูตัวอย่างการใช้งาน
class Box:
# shared variable for all object create by this class
color = 'green'
# class method for object
def __init__(self, width, height, dept):
self.width = width
self.height = height
self.dept = dept
# class method for object
def getVolume(self):
return self.width * self.height * self.dept
@staticmethod
def compare(a, b):
if a.getVolume() > b.getVolume():
return 'greater than'
elif a.getVolume() == b.getVolume():
return 'equal'
else:
return 'less than'
a = Box(2, 3, 4)
b = Box(1, 2, 5)
Box.color = 'red'
print('Box a volume = %d' % a.getVolume())
print('Box b volume = %d' % b.getVolume())
print('Box a color = %s' % a.color)
print('Box b color = %s' % b.color)
print('Box a volume a is %s box b' % Box.compare(a, b))
ในตัวอย่าง เราได้ประกาศคลาส Box
โดยคลาสนี้มีตัวแปรของคลาส คือ color
นั่นหมายความว่าตัวแปรนี้จะถูกใช้งานร่วมกันกับทุกออบเจ็คที่สร้างจากคลาสนี้ ต่อมาภายในเมธอด __init__()
เป็นการกำหนดข้อมูลให้กับออบเจ็คแต่ละอันที่จะมีความกว้าง ความยาว และความสูง และเมธอด getVolume()
สำหรับรับปริมาตรของกล่อง
ภายในคลาส Box
เราได้สร้าง static method compare()
โดยใช้ decorator @staticmethod
นำหน้าก่อนหนึ่งบรรทัด เมธอดนี้ไม่ได้มีส่วนเกี่ยวข้องกับข้อมูลภายในคลาส สังเกตว่ามันไม่มีพารามิเตอร์ self
ถูกส่งเข้ามา สำหรับการเรียกใช้งาน static variables หรือ static method นั้นจะไม่ขึ้นกับออบเจ็ค นั่นหมายความว่าเราจะใช้ชื่อของคลาสแทน ในคำสั่ง Box.color = 'red'
เป็นการกำหนดสีให้กับกล่องทุกกล่องเป็นสีแดง และคำสั่ง Box.compare(a, b)
เป็นการเปรียบเทียบปริมาตรของกล่องทางซ้ายว่ามากกว่าทางขวาหรือไม่
Box a volume = 24
Box b volume = 10
Box a color = red
Box b color = red
Box a volume a is greater than box b
นี่เป็นผลลัพธ์การทำงานของโปรแกรม จะเห็นว่าเราได้ทำการเปลี่ยนค่าสีของกล่องเป็นสีแดงในคำสั่งเดียว แต่มันถูกนำไปใช้กับทุกกล่อง และเมธอดสำหรับเปรียบเทียบปริมาตรของกล่องมันสามารถใช้ได้โดยไม่ขึ้นกับออบเจ็คใดๆ นั่นหมายความว่า static method อาจจะเป็นเมธอดที่ทำงานเกี่ยวกับออบเจ็คที่สร้างจากคลาสนี้ แต่ไม่ได้เป็นเมธอดสำหรับจัดการข้อมูลในคลาสโดยตรง
ในบทนี้ คุณได้เรียนรู้เกี่ยวกับคลาสและออบเจ็คในภาษา Python ซึ่งเป็นสิ่งที่คุณควรจะทำความเข้าใจเพื่อที่จะใช้ประโยชน์จาก OOP ซึ่งมันช่วยให้การเขียนโปรแกรมมีประสิทธิภาพและรวดเร็วขึ้น นอกจากนี้เรายังพูดเกี่ยวกับเมธอดพิเศษ Constructor และ Destructor และสมาชิกที่เป็น static ของคลาส สำหรับเนื้อหาของ OOP ยังไม่จบเพียงเท่านี้ มันยังมีการสืบทอด (Inheritance) ซึ่งคุณจะได้เรียนในบทต่อไป
Reference : http://marcuscode.com