Notes & software courses · Free to learn
Aph's Blog
On this page

วันที่ 21 — คลาสและออบเจกต์ (Classes and Objects)

👋 อ่านฟรีทั้งหมดบน Aph's Blog — เนื้อหาภาษาไทย ทำตามทีละหน้าใน sidebar ได้เลย หากมีข้อเสนอแนะหรืออยากให้เพิ่มหัวข้อไหน บอกได้เสมอ

เรียนรู้การเขียนโปรแกรมเชิงวัตถุ (OOP) ใน Python ตั้งแต่การสร้างคลาส การใช้ Constructor ไปจนถึงการสืบทอดคุณสมบัติ (Inheritance)

30 Days of Python banner
30 Days of Python

คลาสและออบเจกต์ (Classes and Objects)

Python เป็นภาษาโปรแกรมเชิงวัตถุ ทุกสิ่งใน Python คือออบเจกต์ที่มีคุณสมบัติ (properties) และเมธอด (methods) ของตัวเอง ตัวเลข, สตริง, ลิสต์, ดิกชันนารี, ทูเพิล, เซ็ต ที่ใช้ในโปรแกรมล้วนเป็น instance ของคลาสที่มีอยู่แล้วใน Python เราสร้างคลาสเพื่อสร้างออบเจกต์ คลาสเปรียบเสมือน "แบบพิมพ์เขียว" (blueprint) สำหรับการสร้างออบเจกต์ เราสร้าง instance จากคลาสเพื่อสร้างออบเจกต์ คลาสกำหนดคุณลักษณะและพฤติกรรมของออบเจกต์ ในขณะที่ออบเจกต์แสดงตัวแทนของคลาสนั้น

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

python
asabeneh@Asabeneh:~$ python
Python 3.9.6 (default, Jun 28 2021, 15:26:21)
[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> num = 10
>>> type(num)
<class 'int'>
>>> string = 'string'
>>> type(string)
<class 'str'>
>>> boolean = True
>>> type(boolean)
<class 'bool'>
>>> lst = []
>>> type(lst)
<class 'list'>
>>> tpl = ()
>>> type(tpl)
<class 'tuple'>
>>> set1 = set()
>>> type(set1)
<class 'set'>
>>> dct = {}
>>> type(dct)
<class 'dict'>

การสร้างคลาส (Creating a Class)

ในการสร้างคลาส เราต้องใช้คีย์เวิร์ด class ตามด้วยชื่อและเครื่องหมายโคลอน ชื่อคลาสควรเขียนแบบ CamelCase

python
# syntax
class ClassName:
  code goes here

ตัวอย่าง:

python
class Person:
  pass
print(Person)
shell
<__main__.Person object at 0x10804e510>

การสร้างออบเจกต์ (Creating an Object)

เราสามารถสร้างออบเจกต์ได้โดยการเรียกคลาส:

python
p = Person()
print(p)

Constructor ของคลาส (Class Constructor)

ในตัวอย่างด้านบน เราสร้างออบเจกต์จากคลาส Person แต่คลาสที่ไม่มี constructor ไม่มีประโยชน์ในงานจริงมากนัก ลองใช้ฟังก์ชัน constructor เพื่อทำให้คลาสมีประโยชน์มากขึ้น เหมือน constructor ใน Java หรือ JavaScript Python มีฟังก์ชัน __init__() ที่เป็น constructor ในตัว ฟังก์ชัน constructor __init__ มีพารามิเตอร์ self ซึ่งเป็น reference ไปยัง instance ปัจจุบันของคลาส

ตัวอย่าง:

python
class Person:
      def __init__ (self, name):
        # self allows to attach parameter to the class
          self.name =name

p = Person('Asabeneh')
print(p.name)
print(p)
shell
# output
Asabeneh
<__main__.Person object at 0x2abf46907e80>

ลองเพิ่มพารามิเตอร์เพิ่มเติมให้กับฟังก์ชัน constructor:

python
class Person:
      def __init__(self, firstname, lastname, age, country, city):
          self.firstname = firstname
          self.lastname = lastname
          self.age = age
          self.country = country
          self.city = city


p = Person('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki')
print(p.firstname)
print(p.lastname)
print(p.age)
print(p.country)
print(p.city)
shell
# output
Asabeneh
Yetayeh
250
Finland
Helsinki

เมธอดของออบเจกต์ (Object Methods)

ออบเจกต์สามารถมีเมธอดได้ เมธอดคือฟังก์ชันที่เป็นส่วนหนึ่งของออบเจกต์

ตัวอย่าง:

python
class Person:
      def __init__(self, firstname, lastname, age, country, city):
          self.firstname = firstname
          self.lastname = lastname
          self.age = age
          self.country = country
          self.city = city
      def person_info(self):
        return f'{self.firstname} {self.lastname} is {self.age} years old. He lives in {self.city}, {self.country}'

p = Person('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki')
print(p.person_info())
shell
# output
Asabeneh Yetayeh is 250 years old. He lives in Helsinki, Finland

ค่าเริ่มต้นของเมธอดออบเจกต์ (Object Default Methods)

บางครั้งคุณอาจต้องการกำหนดค่าเริ่มต้น (default values) สำหรับเมธอดของออบเจกต์ หากเรากำหนดค่าเริ่มต้นให้กับพารามิเตอร์ใน constructor เราสามารถหลีกเลี่ยงข้อผิดพลาดเมื่อเรียกหรือสร้าง instance ของคลาสโดยไม่มีพารามิเตอร์ได้

ตัวอย่าง:

python
class Person:
      def __init__(self, firstname='Asabeneh', lastname='Yetayeh', age=250, country='Finland', city='Helsinki'):
          self.firstname = firstname
          self.lastname = lastname
          self.age = age
          self.country = country
          self.city = city

      def person_info(self):
        return f'{self.firstname} {self.lastname} is {self.age} years old. He lives in {self.city}, {self.country}.'

p1 = Person()
print(p1.person_info())
p2 = Person('John', 'Doe', 30, 'Nomanland', 'Noman city')
print(p2.person_info())
shell
# output
Asabeneh Yetayeh is 250 years old. He lives in Helsinki, Finland.
John Doe is 30 years old. He lives in Noman city, Nomanland.

เมธอดสำหรับแก้ไขค่าเริ่มต้นของคลาส (Method to Modify Class Default Values)

ในตัวอย่างด้านล่าง คลาส Person มีพารามิเตอร์ constructor ทั้งหมดที่มีค่าเริ่มต้น นอกจากนี้ยังมีพารามิเตอร์ skills ซึ่งเข้าถึงได้โดยใช้เมธอด ลองสร้างเมธอด add_skill เพื่อเพิ่มทักษะลงใน skills list:

python
class Person:
      def __init__(self, firstname='Asabeneh', lastname='Yetayeh', age=250, country='Finland', city='Helsinki'):
          self.firstname = firstname
          self.lastname = lastname
          self.age = age
          self.country = country
          self.city = city
          self.skills = []

      def person_info(self):
        return f'{self.firstname} {self.lastname} is {self.age} years old. He lives in {self.city}, {self.country}.'
      def add_skill(self, skill):
          self.skills.append(skill)

p1 = Person()
print(p1.person_info())
p1.add_skill('HTML')
p1.add_skill('CSS')
p1.add_skill('JavaScript')
p2 = Person('John', 'Doe', 30, 'Nomanland', 'Noman city')
print(p2.person_info())
print(p1.skills)
print(p2.skills)
shell
# output
Asabeneh Yetayeh is 250 years old. He lives in Helsinki, Finland.
John Doe is 30 years old. He lives in Noman city, Nomanland.
['HTML', 'CSS', 'JavaScript']
[]

การสืบทอด (Inheritance)

การใช้ inheritance ช่วยให้เราสามารถนำโค้ดของคลาสแม่มาใช้ซ้ำได้ Inheritance ช่วยให้เราสามารถกำหนดคลาสที่สืบทอดเมธอดและคุณสมบัติทั้งหมดจากคลาสแม่ได้ คลาสแม่ (parent class) หรือ super class หรือ base class คือคลาสที่ให้เมธอดและคุณสมบัติทั้งหมด คลาสลูก (child class) คือคลาสที่สืบทอดมาจากคลาสอื่นหรือคลาสแม่ ลองสร้างคลาส Student โดยสืบทอดมาจากคลาส Person:

python
class Student(Person):
    pass


s1 = Student('Eyob', 'Yetayeh', 30, 'Finland', 'Helsinki')
s2 = Student('Lidiya', 'Teklemariam', 28, 'Finland', 'Espoo')
print(s1.person_info())
s1.add_skill('JavaScript')
s1.add_skill('React')
s1.add_skill('Python')
print(s1.skills)

print(s2.person_info())
s2.add_skill('Organizing')
s2.add_skill('Marketing')
s2.add_skill('Digital Marketing')
print(s2.skills)
shell
output
Eyob Yetayeh is 30 years old. He lives in Helsinki, Finland.
['JavaScript', 'React', 'Python']
Lidiya Teklemariam is 28 years old. He lives in Espoo, Finland.
['Organizing', 'Marketing', 'Digital Marketing']

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

การ Override เมธอดของคลาสแม่ (Overriding parent method)

python
class Student(Person):
    def __init__ (self, firstname='Asabeneh', lastname='Yetayeh',age=250, country='Finland', city='Helsinki', gender='male'):
        self.gender = gender
        super().__init__(firstname, lastname,age, country, city)
    def person_info(self):
        gender = 'He' if self.gender =='male' else 'She'
        return f'{self.firstname} {self.lastname} is {self.age} years old. {gender} lives in {self.city}, {self.country}.'

s1 = Student('Eyob', 'Yetayeh', 30, 'Finland', 'Helsinki','male')
s2 = Student('Lidiya', 'Teklemariam', 28, 'Finland', 'Espoo', 'female')
print(s1.person_info())
s1.add_skill('JavaScript')
s1.add_skill('React')
s1.add_skill('Python')
print(s1.skills)

print(s2.person_info())
s2.add_skill('Organizing')
s2.add_skill('Marketing')
s2.add_skill('Digital Marketing')
print(s2.skills)
shell
Eyob Yetayeh is 30 years old. He lives in Helsinki, Finland.
['JavaScript', 'React', 'Python']
Lidiya Teklemariam is 28 years old. She lives in Espoo, Finland.
['Organizing', 'Marketing', 'Digital Marketing']

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

💻 แบบฝึกหัด — วันที่ 21

แบบฝึกหัด: ระดับ 1

  1. Python มีโมดูลชื่อ statistics และเราสามารถใช้โมดูลนี้ทำการคำนวณทางสถิติทั้งหมดได้ แต่เพื่อฝึกการสร้างฟังก์ชันและการนำกลับมาใช้ซ้ำ ลองพัฒนาโปรแกรมที่คำนวณค่ากลาง (mean, median, mode) และค่าการกระจาย (range, variance, standard deviation) ของตัวอย่างข้อมูล นอกจากนี้ให้หาค่า min, max, count, percentile และการแจกแจงความถี่ (frequency distribution) ของตัวอย่าง สร้างคลาสชื่อ Statistics และสร้างฟังก์ชันทั้งหมดที่คำนวณค่าทางสถิติเป็นเมธอดสำหรับคลาส Statistics ตรวจสอบผลลัพธ์ด้านล่าง
python
ages = [31, 26, 34, 37, 27, 26, 32, 32, 26, 27, 27, 24, 32, 33, 27, 25, 26, 38, 37, 31, 34, 24, 33, 29, 26]

print('Count:', data.count()) # 25
print('Sum: ', data.sum()) # 744
print('Min: ', data.min()) # 24
print('Max: ', data.max()) # 38
print('Range: ', data.range()) # 14
print('Mean: ', data.mean()) # 30
print('Median: ', data.median()) # 29
print('Mode: ', data.mode()) # {'mode': 26, 'count': 5}
print('Standard Deviation: ', data.std()) # 4.2
print('Variance: ', data.var()) # 17.5
print('Frequency Distribution: ', data.freq_dist()) # [(20.0, 26), (16.0, 27), (12.0, 32), (8.0, 37), (8.0, 34), (8.0, 33), (8.0, 31), (8.0, 24), (4.0, 38), (4.0, 29), (4.0, 25)]
shell
# you output should look like this
print(data.describe())
Count: 25
Sum:  744
Min:  24
Max:  38
Range:  14
Mean:  30
Median:  29
Mode:  (26, 5)
Variance:  17.5
Standard Deviation:  4.2
Frequency Distribution: [(20.0, 26), (16.0, 27), (12.0, 32), (8.0, 37), (8.0, 34), (8.0, 33), (8.0, 31), (8.0, 24), (4.0, 38), (4.0, 29), (4.0, 25)]

แบบฝึกหัด: ระดับ 2

  1. สร้างคลาสชื่อ PersonAccount ที่มีคุณสมบัติ firstname, lastname, incomes, expenses และมีเมธอด total_income, total_expense, account_info, add_income, add_expense และ account_balance โดย incomes คือชุดของรายได้และคำอธิบาย เช่นเดียวกับ expenses