Inheritance
ในบทก่อนหน้า คุณได้เรียนรู้พื้นฐานการเขียนโปรแกรมเชิงวัตถุในการสร้างคลาสและออบเจ็คไปแล้ว และในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับคุณสมบัติอีกอย่างหนึ่งของ OOP คือการสืบทอดคลาส (Inheritance) ซึ่งเป็นความสามารถที่สำคัญในภาษา Python ที่จะทำให้สามารถนำคลาสที่เขียนไว้แล้วมาใช้อีกครั้งและเพิ่มความสามารถเพิ่มเติมเข้ามา ก่อนที่จะเริ่ม มาทำความเข้าใจกับแนวคิดของการสืบทอดก่อน
Inheritance คืออะไร
Inheritance หรือการสืบทอด คือการที่คลาสหรือออบเจ็ค ได้รับการถ่ายทอดแอตทริบิวต์และเมธอดจากคลาสอื่น นั่นจะทำให้คลาสดังกล่าวมีแอตทริบิวต์และเมธอดเหมือนคลาสที่มันสืบทอดมาเรียกคลาสนั้นว่า super class หรือ base class ส่วนคลาสที่ได้รับการสืบทอดเรียกว่า sub class หรือ child class นอกจากนี้ เรายังสามารถขยายความสามารถโดยการเพิ่มแอตทริบิวต์หรือเมธอด หรือทำการ override เมธอดของ super class ได้ นี่เป็นแนวคิดในการนำโค้ดเดิมกลับมาใช้โดยไม่ต้องเขียนขึ้นใหม่ และเพิ่มความสามารถของเดิมที่มีอยู่ ในภาษา Python นั้นยังสนับสนุน Multiple inheritance ซึ่งอนุญาติให้คลาสสืบทอดจากคลาสหลายๆ คลาสได้ในเวลาเดียวกัน
นี่เป็นรูปแบบของการสืบทอดคลาสในภาษา Python
class DerivedClassName(BaseClassName):
pass
class DerivedClassName(BaseClassName1, BaseClassName2, ...):
pass
ในตัวอย่าง เป็นรูปแบบการสืบทอดคลาส โดยแบบแรกเป็นการสืบทอดจากคลาสเดียว ซึ่งชื่อของ super class จะอยู่ในวงเล็บ (BaseClassName)
และสำหรับตัวอย่างต่อมา คือการสืบทอดแบบหลายคลาส โดยจะมีเครื่องหมายคอมมา (,) แยกระหว่างแต่ละคลาสออกจากกัน ต่อไปมาดูตัวอย่างการสร้างคลาสที่สืบทอดจากคลาสอื่นในภาษา Python
การสืบทอดคลาส
ในการสืบทอดคลาสนั้น เราจะยกตัวอย่างโดยการสร้างคลาสสำหรับเก็บข้อมูลของบุคคลชื่อ Person
หลังจากนั้นเราจะสร้างคลาสของลูกจ้าง Employee ซึ่งคลาสนี้จะสืบทอดมาจากคลาสก่อนหน้า มาดูส่วนของโปรแกรมของเรา
class Person:
def __init__(self, firstName, lastName):
self.firstName = firstName
self.lastName = lastName
def getName(self):
return self.firstName + ' ' + self.lastName
class Employee(Person):
def setWorkDetail(self, department, position):
self.department = department
self.position = position
def getWorkDetail(self):
return self.position + ', ' + self.department
emp1 = Employee('Mladen', 'Solomun')
emp1.setWorkDetail('Software Engineer', 'C++ programmer')
print('Name: ' + emp1.getName())
print('Work: ' + emp1.getWorkDetail())
emp2 = Employee('John', 'Askew')
emp2.setWorkDetail('Sound Engineer', 'Musical acoustics')
print('Name: ' + emp2.getName())
print('Work: ' + emp2.getWorkDetail())
ในตัวอย่าง เราได้สร้างคลาส Person
ซึ่งคลาสนี้เป็น super class เพื่อที่จะนำไปให้คลาสอื่นสืบทอด ในคลาสมีสองแอตทริบิวต์คือ firstName
ใช้สำหรับเก็บชื่อ และ lastName
ใช้สำหรับเก็บนามสกุล และมีเมธอด getName()
เพื่อรับชื่อและนามสกุลได้ในพร้อมกัน
class Employee(Person):
...
หลังจากนั้นเราได้สร้างคลาส Employee
ซึ่งได้สืบทอดมาจากคลาส Person
นั่นหมายความว่าแอตทริบิวต์และเมธอดทั้งหมดจากคลาส Person
จะถูกถ่ายทอดมายังคลาสนี้ด้วย นั่นจะทำให้มันมีทุกอย่างเหมือนที่คลาสหลักมี และนอกจากนี้ในคลาสนี้ยังมีเมธอดและแอตทริบิวต์เพิ่มเติมของมันเอง โดยเมธอด setWorkDetail()
เป็นเมธอดสำหรับกำหนดรายละเอียดการทำงานโดยมีตำแหน่งงานและแผนกที่สังกัด และเมธอด getWorkDetail()
แสดงข้อมูลเกี่ยวกับการทำงาน
emp1 = Employee('Mladen', 'Solomun')
emp1.setWorkDetail('Software Engineer', 'C++ programmer')
print('Name: ' + emp1.getName())
print('Work: ' + emp1.getWorkDetail())
emp2 = Employee('John', 'Askew')
emp2.setWorkDetail('Sound Engineer', 'Musical acoustics')
print('Name: ' + emp2.getName())
print('Work: ' + emp2.getWorkDetail())
หลังจากเราได้สร้างคลาสเสร็จแล้ว ต่อไปเป็นการนำมาใช้งาน เราได้สร้างออบเจ็คของ Employee
ขึ้นมาสองออบเจ็คคือ emp1
และ emp2
แต่ละออบเจ็คได้มีการกำหนดชื่อและนามสกุล และมีการกำหนดข้อมูลการทำงาน หลังจากนั้นเป็นการแสดงข้อมูลเกี่ยวกับแต่ละคน โดยแสดงชื่อและข้อมูลการทำงาน
Name: Mladen Solomun
Work: C++ programmer, Software Engineer
Name: John Askew
Work: Musical acoustics, Sound Engineer
นี่เป็นผลลัพธ์การทำงานของโปรแกรม คุณจะเห็นได้ว่าการสืบทอดนั้นทำให้เรานำคลาสเดิมกลับมาใช้ได้ และนอกจากนี้ยังสามารถเพิ่มแอตทริบิวต์และเมธอดเข้าไปอีก ซึ่งจะทำให้ช่วยประหยัดเวลาในการเขียนโปรแกรม ลดความซ้ำซ้อนของโค้ด
Multiple Inheritance
ในตัวอย่างก่อนหน้า เป็นการสืบทอดคลาสจากเพียงแค่คลาสเดียว อย่างไรก็ตามในภาษา Python นั้นสนับสนุนการสืบทอดจากหลายคลาสได้ในพร้อมกัน ต่อไปมาดูตัวอย่างของโปรแกรมที่จะใช้ประโยชน์จากการสืบทอดหลายคลาส
class Geographic:
def setCordinate(self, latitude, longitude):
self.latitude = latitude
self.longitude = longitude
def getCordinate(self):
return str(self.latitude) + ', ' + str(self.longitude)
def getTimeZone(self):
timezone = round(self.longitude / 12 - 1)
if timezone > 0:
return '+' + str(timezone)
else:
return str(timezone)
def getClimate(self):
if self.latitude <= -66.5 or self.latitude >= 66.5:
return 'Polar zone'
elif self.latitude <= -23.5 or self.latitude >= 23.5:
return 'Temperate zone'
else:
return 'Tropical zone'
class Temperature:
def setCelsius(self, celsius):
self.celsius = celsius
def getFahrenheit(self):
return self.celsius * 1.8 + 32
def getKelvin(self):
return self.celsius + 273.15
def getWeather(self):
if self.celsius <= 0:
return 'freezing'
elif self.celsius <= 18:
return 'cold'
elif self.celsius <= 28:
return 'warm'
else:
return 'hot'
class Country(Geographic, Temperature):
def __init__(self, name, area, population):
self.name = name
self.area = area
self.population = population
def getPopulationDensity(self):
return self.population / self.area
def showDetails(self):
print('Country: %s' % self.name)
print('Area: %.2f sq km' % self.area)
print('Population: %d' % self.population)
print('Density: %.2f person per sq km' %
self.getPopulationDensity())
print('Decimal cordinate: %s' % self.getCordinate())
print('Time zone: %s' % self.getTimeZone())
print('Climate: %s' % self.getClimate())
print('Temperature in Celsius: %.2f degree' % self.celsius)
print('Temperature in Fahrenheit: %.2f degree' %
self.getFahrenheit())
print('Temperature in Kelvin: %.2f' % self.getKelvin())
print('The weather is %s' % self.getWeather())
print()
ในตัวอย่าง เราได้สร้าง super class มาสองคลาสคือ Geographic
เป็นคลาสจัดการการทำงานในทางภูมิศาสตร์ และคลาสที่สอง Temperature
เป็นคลาสสำหรับจัดการอุณหภูมิ ต่อไปเราจะมาอธิบายการทำงานของคลาสเหล่านี้อย่างละเอียด เพื่อให้คุณเข้าใจในการทำงานของมัน คุณอาจจะหยิบแก้วกาแฟของคุณมาดื่มไปด้วยก็ได้ เพราะมันอาจจะยาวสักหน่อย แต่เชื่อเถอะว่ามันสนุกแน่นอน
class Geographic:
def setCordinate(self, latitude, longitude):
self.latitude = latitude
self.longitude = longitude
def getCordinate(self):
return str(self.latitude) + ', ' + str(self.longitude)
def getTimeZone(self):
timezone = round(self.longitude / 12 - 1)
if timezone > 0:
return '+' + str(timezone)
else:
return str(timezone)
def getClimate(self):
if self.latitude <= -66.5 or self.latitude >= 66.5:
return 'Polar zone'
elif self.latitude <= -23.5 or self.latitude >= 23.5:
return 'Temperate zone'
else:
return 'Tropical zone'
คลาสแรกของเราคือคลาส Geographic
คลาสนี้รับผิดชอบการทำงานเกี่ยวกับภูมิศาสตร์ โดยเรามีเมธอด setCordinate()
สำหรับกำหนดค่า latitude
และ longitude
ซึ่งนี่เป็นพิกัดที่ตั้งของสิ่งต่างๆ บนโลก ในคลาสนี้เราได้มีเมธอดที่สำคัญคือ getTimeZone()
เป็นเมธอดสำหรับหาค่า timezone จาก longitude
ซึ่งลองจิจูดหรือเส้นแวง เป็นเส้นระยะตามยาวของพื้นผิวโลก มันใช้สำหรับกำหนดเขตเวลาบนโลกออกเป็นเขตต่างๆ เนื่องจากโลกของเราเป็นทรงกลม ดังนั้นจึงทำให้เวลาในแต่ละพื้นที่แตกต่างกัน ดังรูปข้างล่าง
ต่อมาเป็นเมธอด getClimate()
เมธอดนี้จะนำค่า latitude
เส้นละติจูดหรือที่เรียกกันว่าเส้นรุ้ง ซึ่งมันใช้เป็นตัวแบ่งสภาพอากาศของโลกออกเป็นสามแบบใหญ่ๆ คือเขตร้อน เขตอบอุ่น และเขตขั้วโลก ดังนั้นเมธอดนี้จะบอกว่าพื้นที่นั้นอยู่ในเขตอากาศแบบไหน โดยคำนวณจากค่าละติจูด
class Temperature:
def setCelsius(self, celsius):
self.celsius = celsius
def getFahrenheit(self):
return self.celsius * 1.8 + 32
def getKelvin(self):
return self.celsius + 273.15
def getWeather(self):
if self.celsius <= 0:
return 'freezing'
elif self.celsius <= 18:
return 'cold'
elif self.celsius <= 28:
return 'warm'
else:
return 'hot'
ต่อมาเป็นคลาส Temperature
คลาสนี้จัดการเกี่ยวกับอุณหภูมิ โดยมีเมธอด setCelsius()
สำหรับรับค่าอุณหภูมิในหน่วยองศาเซลเซียส หลังจากนั้นเราได้มีเมธอดแปลงค่าหน่วยนี้ไปยังหน่วยอื่นๆ ในองศาฟาเรนไฮต์ และเคลวิน และมีเมธอด getWeather()
สำหรับคำนวณหาสภาพอากาศว่าร้อน อบอุ่น หนาว หรือแช่แข็ง
class Country(Geographic, Temperature):
def __init__(self, name, area, population):
self.name = name
self.area = area
self.population = population
def getPopulationDensity(self):
return self.population / self.area
def showDetails(self):
print('Country: %s' % self.name)
print('Area: %.2f sq km' % self.area)
print('Population: %d' % self.population)
print('Density: %.2f person per sq km' %
self.getPopulationDensity())
print('Decimal cordinate: %s' % self.getCordinate())
print('Time zone: %s' % self.getTimeZone())
print('Climate: %s' % self.getClimate())
print('Temperature in Celsius: %.2f degree' % self.celsius)
print('Temperature in Fahrenheit: %.2f degree' %
self.getFahrenheit())
print('Temperature in Kelvin: %.2f' % self.getKelvin())
print('The weather is %s' % self.getWeather())
print()
ตอนนี้เราได้สร้าง super class เสร็จไปแล้ว และคุณได้เข้าใจการทำงานของมันทั้งหมด ต่อไปเป็นการสร้างคลาส Country
ซึ่งคลาสนี้สืบทอดจากคลาสทั้งสองก่อนหน้า นั่นจะทำให้มันมีแอตทริบิวต์และเมธอดทั้งหมดเหมือนกับ super class ของมัน
สำหรับในคลาส Country
เป็นคลาสของประเทศที่จะเก็บรายละเอียดต่างๆ โดยมีแอตทริบิวต์ name
เป็นชื่อของประเทศ area
เป็นขนาดพื้นที่มีหน่วยในตารางกิโลเมตร และ population
เป็นจำนวนประชากรทั้งหมดในประเทศ และคลาสนี้มีสองเมธอดคือ getPopulationDensity()
เป็นเมธอดสำหรับคำนวณความหนาแน่นของประชากรต่อพื้นที่หนึ่งตารางกิโลเมตร และเมธอด showDetails()
สำหรับแสดงรายละเอียดทั้งหมดเกี่ยวกับประเทศ
c = Country('Thailand', 513120, 68863514)
c.setCordinate(13.75, 100.483333)
c.setCelsius(28.5)
c.showDetails()
c2 = Country('England', 130279, 55268100)
c2.setCordinate(51.5, -0.116667)
c2.setCelsius(9)
c2.showDetails()
c2 = Country('Canada', 9984670, 35151728)
c2.setCordinate(45.4, -75.666667)
c2.setCelsius(-3)
c2.showDetails()
หลังจากสร้างคลาสเสร็จแล้ว ต่อไปเป็นการนำคลาส Country
มาสร้างออบเจ็คของสามประเทศคือ ไทย อังกฤษ และแคนาดา โดยในแต่ละออบเจ็คได้กำหนดข้อมูลของประเทศ กำหนดพิกัดด้วยเมธอด setCordinate()
กำหนดอุณหภูมิด้วยเมธอด setCelsius()
และสุดท้ายเรียกดูรายละเอียดทั้งหมดด้วยเมธอด showDetails()
Country: Thailand
Area: 513120.00 sq km
Population: 68863514
Density: 134.21 person per sq km
Decimal cordinate: 13.75, 100.483333
Time zone: +7
Climate: Tropical zone
Temperature in Celsius: 28.50 degree
Temperature in Fahrenheit: 83.30 degree
Temperature in Kelvin: 301.65
The weather is hot
Country: England
Area: 130279.00 sq km
Population: 55268100
Density: 424.23 person per sq km
Decimal cordinate: 51.5, -0.116667
Time zone: -1
Climate: Temperate zone
Temperature in Celsius: 9.00 degree
Temperature in Fahrenheit: 48.20 degree
Temperature in Kelvin: 282.15
The weather is cold
Country: Canada
Area: 9984670.00 sq km
Population: 35151728
Density: 3.52 person per sq km
Decimal cordinate: 45.4, -75.666667
Time zone: -7
Climate: Temperate zone
Temperature in Celsius: -3.00 degree
Temperature in Fahrenheit: 26.60 degree
Temperature in Kelvin: 270.15
The weather is freezing
นี่เป็นผลลัพธ์การทำงานของโปรแกรม ซึ่งเป็นการแสดงข้อมูลทางภูมิศาสตร์ อุณหภูมิและสภาพอากาศของแต่ละประเทศ ในตอนนี้คุณเห็นแล้วว่าเราได้ใช้การสืบทอดคลาสเพื่อทำให้คลาส Country
มีความสามารถที่หลายหลากเหมือนกับ super class ของมัน
Method overriding
สำหรับเรื่องสุดท้ายในบทนี้ จะเป็นการเรียนรู้เกี่ยวกับการ override เมธอด ซึ่งคือการที่ sub class ทำการกำหนดการทำงานให้กับเมธอดจาก super class ใหม่ โดยยังคงใช้ชื่อเดิม ซึ่งจะทำให้เกิดคลาสใหม่ในบริบทของ sub class และเมธอดจาก super class จะไม่สามารถเข้าถึงได้ มาดูตัวอย่างการทำงานของโปรแกรม
class Animal:
def move(self):
print('Animal is moving')
class Dog(Animal):
def move(self):
print('Dog is running')
def parentMove(self):
print('Call parent method')
Animal.move(self)
a = Animal()
a.move()
d = Dog()
d.move()
d.parentMove()
ในตัวอย่าง เราได้สร้างคลาส Animal
โดยคลาสนี้มีเมธอด move()
สำหรับแสดงข้อความการเคลื่อนที่ของสัตว์ ต่อมาเราได้สร้างคลาส Dog
ซึ่งเป็นคลาสที่สืบทอดมาจากคลาส Animal
ในคลาส Dog
เราได้ทำการเขียนการทำงานของเมธอด move()
ใหม่ เพื่อบอกว่าการเคลื่อนที่ของสุนัขนั้นคือการวิ่ง ดังนั้นการทำงานของเมธอดในคลาสหลักจึงถูกทับไป
อย่างไรก็ตาม เรายังคงสามารถเรียกใช้งานเมธอดจากคลาสหลักได้ ในเมธอด parentMove()
เป็นการเรียกใช้งานเมธอดจาก super class ในคำสั่ง Animal.move(self)
ในตอนนี้ถึงแม้ว่าเราจะได้ทำการ override เมธอดนี้ไปแล้ว แต่เราก็ยังสามารถเรียกใช้มันได้เช่นเดิม
Animal is moving
Dog is running
Call parent method
Animal is moving
นี่เป็นผลลัพธ์การทำงานของโปรแกรม จะเห็นว่าการ override เมธอดนั้นเป็นการเขียนทับการทำงานเมธอดของ super class นี่มักจะใช้ในกรณีที่คุณต้องการการทำงานใหม่ที่แตกต่างจากเดิม แต่ยังคงต้องการใช้ชื่อเมธอดเดิมอยู่ และไม่ต้องการที่จะไปเปลี่ยนการทำงานของเมธอดใน super class
ในบทนี้ คุณได้เรียนรู้เกี่ยวกับการสืบทอดคลาสในภาษา Python ซึ่งเป็นแนวคิดการนำโค้ดเดิมกลับมาใช้โดยที่ไม่ต้องสร้างคลาสใหม่ที่มีแอตทริบิวต์และเมธอดเหมือนกันใหม่ทั้งหมด ซึ่งนี่จะทำให้คุณสามารถทำงานได้เร็วขึ้น และนอกจากนี้คุณยังได้เรียนรู้เกี่ยวกับการสืบทอดแบบหลายคลาส และการ override การทำงานของเมธอด
Reference : http://marcuscode.com