การรับทอด
นอกจากการสร้างคลาสขึ้นมาใหม่ตั้งแต่เริ่มต้นแล้วเรายังสามารถนำคลาสที่มี อยู่แล้วมาเสริมให้เป็นคลาสใหม่ได้ วิธีการนี้เรียกว่าการรับทอด (inheritance)
วิธีการนี้มีประโยชน์เพราะสามารถใช้ประโยชน์จากคลาส เดิมที่มีอยู่แล้วโดยไม่ต้องสร้างใหม่แค่นำมาเปลี่ยนแปลงแก้ไขให้เข้ากับการใช้งานตามที่ต้องการมากขึ้นเท่านั้น
เมื่อเราสร้างคลาสใหม่ขึ้นด้วย วิธีการรับทอด คลาสใหม่ที่สร้างจะถูกเรียกว่าเป็นซับคลาส (subclass) ของคลาสเดิม และคลาสเดิมก็จะเรียกว่าเป็นซูเปอร์คลาส (superclass) ของคลาสใหม่ คลาสที่สร้างมาจากการรับทอดจะมีแอตทริบิวต์และเมธอด เหมือนกับซูเปอร์คลาสของมัน แต่สามารถเพิ่มเมธอดหรือแอตทริบิวต์ใหม่ลงไป หรือเขียนทันของเก่าได้
อินสแตนซ์ของซับคลาสจะเป็นอินสแตนซ์ของซูเปอร์คลาสไปด้วย แต่อินสแตนซ์ของซูเปอร์คลาสจะไม่เป็นอินสแตนซ์ของซับคลาสไปด้วย การรับทอดทำได้โดยการใส่ชื่อคลาสที่ต้องการรับทอดไว้ในวงเล็บหลังชื่อคลาสใหม่ตอนที่ประกาศสร้างคลาสใหม่ขึ้น
การสร้างคลาสด้วยการรับทอด
จะขอยกตัวอย่างที่ต่อเนื่องจากบทที่แล้ว ในบทที่แล้วได้สร้างคลาส "ผู้กล้า"
ขึ้น ซึ่งผู้กล้านี้ก็อาจสามารถแบ่งย่อยเป็นอาชีพต่างๆได้อีกเช่นนักรบหรือจอมเวทย์
ในบทนี้เราจะสร้างคลาสเหล่านี้ขึ้นมาใหม่โดยรับทอดจากคลาส "ผู้กล้า"
class อาวุธ:
def __init__(self,ชื่อ,พลังโจมตีกายภาพ,พลังโจมตีเวทย์,ความทนทาน):
self.ชื่อ = ชื่อ
self.พลังโจมตีกายภาพ = พลังโจมตีกายภาพ
self.พลังโจมตีเวทย์ = พลังโจมตีเวทย์
self.ความทนทาน = ความทนทาน
class เสื้อผ้า:
def __init__(self,ชื่อ,พลังป้องกัน,ความทนทาน):
self.ชื่อ = ชื่อ
self.พลังป้องกัน = พลังป้องกัน
self.ความทนทาน = ความทนทาน
class ผู้กล้า:
def __init__(self,ชื่อ,เลเวล=1,ความแข็งแรง=4,ความอดทน=4,hpสูงสุด=10):
self.ชื่อ = ชื่อ
self.เลเวล = เลเวล
self.ความแข็งแรง = ความแข็งแรง
self.ความอดทน = ความอดทน
self.hpสูงสุด = hpสูงสุด
self.hp = hpสูงสุด
เสื้อผ้า = เสื้อผ้า('ชุดเก่าๆ',3,5)
อาวุธ = อาวุธ('มีดสั้นเก่าๆ',3,0,5)
เงินเดือน = 500
def พลังโจมตี(self):
return self.ความแข็งแรง + self.อาวุธ.พลังโจมตีกายภาพ
def พลังป้องกัน(self):
return self.ความอดทน + self.เสื้อผ้า.พลังป้องกัน
def ถูกโจมตี(self,ความเสียหาย):
if(ความเสียหาย>self.พลังป้องกัน()):
self.hp -= ความเสียหาย - self.พลังป้องกัน()
else:
self.hp -= 1
if(self.hp<0):
self.hp = 0
class นักรบ(ผู้กล้า):
เสื้อผ้า = เสื้อผ้า('ชุดนักรบฝึกหัด',5,5)
อาวุธ = อาวุธ('ดาบฝึกหัด',5,0,5)
class จอมเวทย์(ผู้กล้า):
def __init__(self,ชื่อ,เลเวล=1,ความแข็งแรง=4,พลังเวทย์=4,ความอดทน=4,hpสูงสุด=10,mpสูงสุด=10):
self.ชื่อ = ชื่อ
self.เลเวล = เลเวล
self.พลังเวทย์ = พลังเวทย์
self.ความแข็งแรง = ความแข็งแรง
self.ความอดทน = ความอดทน
self.hpสูงสุด = hpสูงสุด
self.hp = hpสูงสุด
self.mpสูงสุด = mpสูงสุด
self.mp = mpสูงสุด
เสื้อผ้า = เสื้อผ้า('ชุดจอมเวทย์ฝึกหัด',2,5)
อาวุธ = อาวุธ('คฑาฝึกหัด',0,5,5)
def พลังโจมตีเวทย์(self):
return self.พลังเวทย์ + self.อาวุธ.พลังโจมตีเวทย์
จะเห็นว่ามีการสร้างคลาสขึ้นใหม่ ๓ คลาส คือ “อาวุธ”, “เสื้อผ้า” และ “ผู้กล้า” ซึ่งใกล้เคียงกับบทที่แล้วแต่ต่างไปเล็กน้อย จากนั้นก็สร้างคลาสใหม่ขึ้นอีก ๒ คลาสโดยวิธีการรับทอด นั่นคือ “นักรบ” และ “จอมเวทย์” ซึ่งจะเห็นได้ว่ามีวงเล็บ “ผู้กล้า” อยู่ข้างหลัง ซึ่งแสดงถึงว่าทั้ง ๒ คลาสนี้รับทอดมาจาก “ผู้กล้า” นั่นเอง
ในคลาส “นักรบ” ไม่ได้มีการเพิ่มหรือแก้ไขเมธอด แต่มีแค่การใส่ค่าแอตทริบิวต์ในคลาส นั่นคือ “อาวุธ” และ “เสื้อผ้า” ใหม่ ซึ่งแอตทริบิวต์นี้จะไปทับของที่มีอยู่แล้วในคลาส “ผู้กล้า” ส่วนคลาส “จอมเวทย์” ก็มีการเปลี่ยน “อาวุธ” และ “เสื้อผ้า” เหมือนกัน และยังมีการนิยามเมธอด __init__
ขึ้นใหม่ ซึ่งเมธอดนี้จะไปทับ __init__
ทำให้ใช้อันใหม่นี้แทน ซึ่งข้อแตกต่างจะเห็นว่ามีการเพิ่ม “พลังเวทย์” และ “mpสูงสุด” ขึ้นมา
นอกจากนี้ยังเพิ่มเมธอด “พลังโจมตีเวทย์” ซึ่งไม่ได้ถูกนิยามขึ้นในคลาส “ผู้กล้า” ตั้งแต่แรก เมธอดนี้จึงถูกสร้างขึ้นใหม่และใช้ได้เฉพาะออบเจ็กต์ของคลาส “จอมเวทย์” เท่านั้น คลาส “นักรบ” ไม่มีการนิยาม __init__
ขึ้นมาใหม่ ดังนั้นจึงมีเมธอด init ที่เหมือนกับคลาส “ผู้กล้า” ทุกประการ จะเห็นว่า __init__
ของ “จอมเวทย์” นั้นต่างจากของ “ผู้กล้า” ไม่มาก แค่เพิ่มพารามิเตอร์ขึ้นมาเท่านั้น ในกรณีแบบนี้เราอาจไม่ต้องเขียนใหม่ทั้งหมดแต่ใช้ฟังก์ชัน __init__
ของ “ผู้กล้า” ได้ สามารถทำได้โดยเขียนใหม่เป็น
class จอมเวทย์(ผู้กล้า):
def __init__(self,ชื่อ,เลเวล=1,ความแข็งแรง=4,พลังเวทย์=4,ความอดทน=4,hpสูงสุด=10,mpสูงสุด=10):
ผู้กล้า.__init__(self,ชื่อ,เลเวล,ความแข็งแรง,ความอดทน,hpสูงสุด)
self.พลังเวทย์ = พลังเวทย์
self.mpสูงสุด = mpสูงสุด
self.mp = mpสูงสุด
จะเห็นว่ามีการเรียกใช้ __init__
ของ “ผู้กล้า” ภายในเมธอด __init__
ของ “จอมเวทย์” อีกที โดยพารามิเตอร์ก็ต้องใส่ให้สัมพันธ์กันด้วย พารามิเตอร์ที่ซ้ำกับคลาส “ผู้กล้า” จะถูกป้อนค่าให้กับแอตทริบิวต์ของออบเจ็กต์ด้วย __init__
ด้านในนี้ ส่วนพารามิเตอร์ที่เหลือซึ่งเพิ่มเข้ามาก็ค่อยมาป้อนให้กับแอตทริบิวต์ของออบเจ็กต์อีกที นอกนี้ยังมีวิธีเขียนอีกแบบ นั่นคือใช้ฟังก์ชัน super
class จอมเวทย์(ผู้กล้า):
def __init__(self,ชื่อ,เลเวล=1,ความแข็งแรง=4,พลังเวทย์=4,ความอดทน=4,hpสูงสุด=10,mpสูงสุด=10):
super(จอมเวทย์,self).__init__(ชื่อ,เลเวล,ความแข็งแรง,ความอดทน,hpสูงสุด)
self.พลังเวทย์ = พลังเวทย์
self.mpสูงสุด = mpสูงสุด
self.mp = mpสูงสุด
ฟังก์ชัน super ต้องการอาร์กิวเมนต์ ๒ ตัว ตัวแรกคือคลาส ตัวหลังคือออบเจ็กต์ ในที่นี้ออบเจ็กต์ถูกแทนด้วย self ผลที่ได้คือเป็นการที่ออบเจ็กต์ของคลาสนี้เรียกเมธอดของซุเปอร์คลาสของคลาส มัน ในที่นี้คืออบเจ็กต์ของคลาส “จอมเวทย์” เรียกใช้เมธอดของคลาส “ผู้กล้า” ซึ่งเป็นซูเปอร์คลาส สังเกตได้ว่าพอใช้ super แล้ว ในอาร์กิวเมนต์ของ init ก็ไม่ต้องมี self แล้ว อย่างไรก็ตามกรณีที่ฟังก์ชัน super นี้ถูกใช้ในโครงสร้างคลาสจะสามารถละอาร์กิวเมนต์ได้ ดังนั้นจึงเขียนแค่นี้ได้
class จอมเวทย์(ผู้กล้า):
def __init__(self,ชื่อ,เลเวล=1,ความแข็งแรง=4,พลังเวทย์=4,ความอดทน=4,hpสูงสุด=10,mpสูงสุด=10):
super().__init__(ชื่อ,เลเวล,ความแข็งแรง,ความอดทน,hpสูงสุด)
self.พลังเวทย์ = พลังเวทย์
self.mpสูงสุด = mpสูงสุด
self.mp = mpสูงสุด
***การละแบบนี้ทำได้เฉพาะในไพธอน 3 ส่วนในไพธอน 2 ไม่สามารถละอาร์กิวเมนต์แบบนี้ได้ ต้องเขียนเต็มเท่านั้น รายละเอียด ลองสร้างออบเจ็กต์มาทดสอบการใช้กันดูได้เลย
ผู้เล่นA = จอมเวทย์('มานะ',1,5,8,4,12,11)
ผู้เล่นB = นักรบ('พากเพียร',1,7,6,14)
print(ผู้เล่นA.เสื้อผ้า.ชื่อ) # ได้ ชุดจอมเวทย์ฝึกหัด
print(ผู้เล่นB.เสื้อผ้า.ชื่อ) # ได้ ชุดนักรบฝึกหัด
print(ผู้เล่นA.hp) # ได้ 12
ผู้เล่นA.ถูกโจมตี(10)
print(ผู้เล่นA.hp) # ได้ 8
การรับทอดหลายต่อ
การรับทอดสามารถทำได้หลายต่อเป็นทอดๆกี่ครั้งก็ได้ เช่นนักรบก็อาจแบ่งเป็นนักดาบและนักธนู จอมเวทย์ก็อาจแบ่งเป็นจอมเวทมนตร์ขาวและจอมเวทมนตร์ดำ เป็นต้น
class นักดาบ(นักรบ):
0
class นักธนู(นักรบ):
อาวุธ = อาวุธ('ธนูฝึกหัด',6,0,5)
class จอมเวทมนตร์ดำ(จอมเวทย์):
0
class จอมเวทมนตร์ขาว(จอมเวทย์):
0
ในที่นี้ขอละการเขียนรายละเอียดของคลาสใหม่นี้เพิ่มเติม แต่หลักการก็คล้ายๆเดิม คือ “นักดาบ” และ “นักธนู” จะรับทอดเมธอดและแอตทริบิวต์ของ “นักรบ” ซึ่งรับทอดแอตทริบิวต์ของ “ผู้กล้า” มาอีกต่อ ซับคลาสของซับคลาสของคลาสหนึ่งก็ถือเป็นซับคลาสของคลาสนั้นด้วย ดังนั้น “นักดาบ” ถือเป็นซับคลาสของ “ผู้กล้า” ไปด้วย และออบเจ็กต์ของคลาส “นักดาบ” ก็จะเป็นอินสแตนซ์ของคลาส “นักรบ” แล้วก็เป็นอินสแตนซ์ของคลาส “ผู้กล้า” ไปด้วย ความจริงแล้วคลาสที่เราสร้างขึ้นมาจากเริ่มต้นโดยไม่ได้ใส่วงเล็บไว้ข้างหลัง นั้นก็ถือเป็นการรับทอดคลาสที่ชื่อว่า “object” อยู่แล้วในตัว เพียงแต่สามารถละได้เท่านั้น โดยทั่วไปจึงไม่ต้องเขียนวงเล็บ แต่ถ้าจะเขียนก็จะเห็น
class ผู้กล้า(object):
ซึ่งก็มีค่าเหมือนเขียน
class ผู้กล้า:
นั่นหมายความว่าจริงๆแล้วคลาสทุกชนิดเป็นซับคลาสของคลาสที่ชื่อ object นั่นเพราะในไพธอนนั้นข้อมูลทุกอย่างล้วนเป็นออบเจ็กต์ ดังนั้นไม่ว่าอะไรก็ตามจึงเป็นอินสแตนซ์ของคลาสที่ชื่อ object นั่นเอง หากเรียงลำดับการรับทอดในตัวอย่างนี้ก็จะเป็น
object > ผู้กล้า > นักรบ > นักดาบ
การรับทอดจากหลายคลาส
ในการรับทอดนั้นที่จริงอาจสามารถรับทอดจากหลายๆคลาสพร้อมกันได้ ไม่จำกัดว่ารับทอดได้แค่คลาสเดียว หากจะรับทอดจากหลายคลาสก็แค่ใส่หลายๆคลาสลงในวงเล็บข้างหลังชื่อคลาสตอน ประกาศสร้างคลาส เช่น ลองสร้างคลาส “นักรบเวทย์” ขึ้นมาเป็นซับคลาสของ “นักรบ” กับ “นักเวทย์”
class นักรบเวทย์(นักรบ,จอมเวทย์):
0
กรณีที่คลาสทั้งสองที่รับทอดมานั้นมีการนิยามเมธอดหรือแอตทริบิวต์เหมือนกันจะยึดตามตัวที่ชื่อขึ้นก่อน ในที่นี้แอตทริบิวต์ “เสื้อผ้า” กับ “อาวุธ” ต่างก็ถูกนิยามใหม่ในคลาส “นักรบ” และ “จอมเวทย์” แต่ “นักรบ” ขึ้นก่อน ดังนั้นแอตทริบิวต์นี้จะถูกนิยามตาม “นักรบ” ในขณะที่ “จอมเวทย์” มีนิยามเมธอด __init__
ขึ้นมาใหม่แต่ “นักรบ” ไม่มี ดังนั้นเมธอด __init__
ของ “นักรบเวทย์” ก็จะรับทอด __init__
ของ “จอมเวทย์”
ผู้เล่นD = นักรบเวทย์('หรรษา')
print(นักรบเวทย์.เสื้อผ้า.ชื่อ) # ได้ ชุดนักรบฝึกหัด
print(นักรบเวทย์.อาวุธ.ชื่อ) # ได้ ดาบฝึกหัด
print(ผู้เล่นD.mpสูงสุด) # ได้ 10
อนึ่ง ที่จริงแล้วการรับทอดจาก ๒ คลาสขึ้นไปพร้อมกันนั้นในบางภาษาเช่นภาษาจาวาจะไม่สามารถทำได้ และนักเขียนโปรแกรมบางคนก็ไม่สนับสนุนการทำแบบนี้เพราะอาจทำให้เกิดปัญหาได้ในกรณีที่ชื่อตัวแปรหรือเมธอดมีการซ้อนทับกัน กรณีแบบนี้จะต้องมีอย่างใดอย่างหนึ่งหายไปและทำให้มีการทำงานไม่สมบูรณ์ ในกรณีของ C++ หากมีเมธอดชื่อซ้ำกันแล้วไม่ได้ระบุไว้ว่าจะให้เหลือของฝ่ายไหนก็จะเกิดข้อผิดพลาดขึ้น ดังนั้นแม้ว่าภาษาไพธอนจะสามารถรับทอดจาก ๒ คลาสขึ้นไปได้ แต่ก็ไม่ควรจะทำโดยไม่มีความจำเป็นและต้องระวังด้วยว่า ๒ คลาสนั้นไม่มีเมธอดหรือแอตทริบิวต์ที่ชื่อซ้ำ ไม่มีผลข้างเคียงอะไรหากรับทอดมาพร้อมกัน
เมธอดหรือแอตทริบิวต์ที่ชื่อขึ้นต้นด้วย __
โดยทั่วไปแล้วเมธอดและแอตทริบิวต์จะตั้งชื่อเป็นอะไรก็ได้ หลักการตั้งชื่อก็เหมือนตัวแปรทั่วไป แต่ว่าจะมีกรณีพิเศษเกิดขึ้นหากตั้งชื่อโดยมีขีดล่างสองอันนำหน้า
เมธอดหรือแอตทริบิวต์ที่ชื่อขึ้นต้นด้วย __
จะไม่สามารถเข้าถึงได้โดยตรงจากภายนอกคลาส ยกตัวอย่าง ประกาศคลาส "ผู้กล้า"
ใหม่โดยเปลี่ยนแค่ให้แอตทริบิวต์ “เงินเดือน” มี __
นำหน้า
class ผู้กล้า:
def __init__(self,ชื่อ):
self.ชื่อ = ชื่อ
__เงินเดือน = 500
จากนั้นลองสร้างออบเจ็กต์แล้วเข้าถึงค่า
ผู้เล่นJ = ผู้กล้า('เจ')
print(ผู้เล่นJ.__เงินเดือน)
จะขึ้นว่า
AttributeError: 'ผู้กล้า' object has no attribute '__เงินเดือน'
หรือแม้แต่เข้าถึงผ่านคลาสก็ได้ผลแบบเดียวกัน คือจะขึ้นว่าไม่มีแอตทริบิวต์นี้
print(ผู้กล้า.__เงินเดือน)
โดยปกติแล้วเป็นธรรมเนียมปฏิบัติที่จะตั้งชื่อแอตทริบิวต์หรือเมธอดที่ไม่ต้องการให้มีการเข้าถึงโดยตรงจากภายนอกโดยขึ้นต้นด้วยขีดล่าง แต่การใส่ขีดล่างเพียงขีดเดียวไม่มีผลอะไรในทางปฏิบัติ จึงเป็นเพียงแค่ธรรมเนียมปฏิบัติ* ส่วนการใส่ขีดล่างสองขีดจึงจะมีผลจริงๆ (*ความจริงแล้วมีผลอยู่เล็กน้อย แต่ไม่ได้สำคัญดังนั้นจะยังไม่พูดถึงในตอนนี้) แต่การเข้าถึงโดยใช้จากภายในยังสามารถทำได้ตามปกติ เช่นลองสร้างเมธอดที่ใช้ค่า "__เงินเดือน"
ขึ้นมา
class ผู้กล้า:
def __init__(self,ชื่อ):
self.ชื่อ = ชื่อ
__เงินเดือน = 500
def แสดงเงินเดือน(self):
return self.__เงินเดือน
ผู้เล่นK = ผู้กล้า('เค')
print(ผู้เล่นK.แสดงเงินเดือน()) # ได้ 500
จะเห็นว่าจากภายนอกเข้าถึงโดยตรงไม่ได้แต่สามารถเห็นผลของค่านั้นได้โดยอ้อมเช่นผ่านเมธอด ในที่นี้ใช้เมธอด “แสดงเงินเดือน” อย่างไรก็ตามจริงๆแล้วไม่ใช่ว่าจะเข้าถึงโดยตรงไม่ได้ หากต้องการก็สามารถทำได้เช่นกัน แต่ชื่อจะถูกเปลี่ยนโดยต้องขึ้นต้นด้วยขีดล่างหนึ่งขีดตามด้วยชื่อคลาส ในที่นี้จะเป็น _ผู้กล้า__เงินเดือน ดังนั้นลอง
print(ผู้เล่นK._ผู้กล้า__เงินเดือน) # ได้ 500
จะพบว่าแสดงค่าได้ตามปกติไม่เกิดปัญหา ดังนั้นก็ไม่ใช่ว่าจะสามารถซ่อนค่าแอตทริบิวต์ได้สมบูรณ์จริงๆอยู่ดีแม้จะตั้ง ชื่อแบบนี้ เพราะแค่เขียนชื่อยาวโดยเพิ่มชื่อคลาสขึ้นมาก็เข้าถึงโดยตรงได้แล้ว ในบางภาษาอาจมีการซ่อนแอตทริบิวต์หรือเมธอดจากการเข้าถึงจากภายนอก แต่ในไพธอนไม่สามารถทำแบบนั้นได้ เพียงแต่วิธีนี้มักถูกเปรียบเทียบว่าเสมือนคล้ายการซ่อนซึ่งทำได้ในบางภาษา (บางคนก็เข้าใจผิดว่านี่เป็นการซ่อน) แต่ประโยชน์จริงๆของการทำแบบ นี้คือในกรณีที่มีการสืบทอดคลาส สามารถป้องกันไม่ให้มีการเขียนทับได้แม้จะนิยามแอตทริบิวต์หรือเมธอดที่ชื่อ ซ้ำกันขึ้นมา
class ผู้กล้า:
def __init__(self,ชื่อ):
self.ชื่อ = ชื่อ
__เงินเดือน = 500
def แสดงเงินเดือน(self):
return self.__เงินเดือน
class นักรบ(ผู้กล้า):
__เงินเดือน = 1000
ผู้เล่นL = นักรบ('แอล')
print(ผู้เล่นL.แสดงเงินเดือน()) # ได้ 500
จะเห็นว่าเมธอด “แสดงเงินเดือน” ซึ่งมีไว้ใช้คืนค่า __
เงินเดือน นั้นคืนค่าเงินเดือน 500 ซึ่งเป็นค่าของคลาส “ผู้กล้า” ทั้งๆที่โดยปกติแล้วหากรับทอดมาแล้วมีการนิยามแอตทริบิวต์ซ้ำมันก็น่าจะถูก เขียนทับ ดังนั้นจึงควรได้ค่า 1000 ซึ่งเป็นค่าใหม่ นั่นเป็นเพราะว่าแอตทริบิวต์หรือเมธอดที่ขึ้นต้นด้วย __
จะไม่ถูกเขียนทับคลาสที่รับทอดมา เพราะชื่อจริงๆของมันจะต้องมีชื่อคลาสนำหน้า ดังนั้นจึงแบ่งแยกกันชัดเจน
print(ผู้เล่นL._ผู้กล้า__เงินเดือน) # ได้ 500
print(ผู้เล่นL._นักรบ__เงินเดือน) # ได้ 1000
เท่ากับว่ามีเงินเดือนของผู้กล้าแล้วก็ยังมีเงินเดือนของนักรบอีกแยกต่างหาก เมธอด “แสดงเงินเดือน” ถูกประกาศในคลาส “ผู้กล้า” ดังนั้นจึงใช้ "__เงินเดือน"
ของคลาส “ผู้กล้า” แต่หากนิยามเมธอดใหม่ในคลาส "นักรบ"
ค่า "__เงินเดือน"
ในคลาส “นักรบ” จะถูกใช้แทน ลองเขียนใหม่โดยเปลี่ยนจาก "__เงินเดือน"
เป็น “เงินเดือน” ซึ่งไม่มีขีดล่างสองขีดนำหน้า หรือจะมีขีดเดียว หรือจะเป็นชื่ออื่นก็ได้ จะพบว่าผลลัพธ์ที่ได้นั้นจะต่างกันออกไป โดยจะได้ค่า 1000 แทนที่จะเป็น 500
class ผู้กล้า:
def __init__(self,ชื่อ):
self.ชื่อ = ชื่อ
เงินเดือน = 500
def แสดงเงินเดือน(self):
return self.เงินเดือน
class นักรบ(ผู้กล้า):
เงินเดือน = 1000
ผู้เล่นM = นักรบ('เอ็ม')
print(ผู้เล่นM.แสดงเงินเดือน()) # ได้ 1000
print(ผู้เล่นM.เงินเดือน) # ได้ 1000
ตัวอย่างข้างต้นเป็นกรณีของแอตทริบิวต์ สำหรับเมธอดเองก็สามารถทำได้ในลักษณะเดียวกัน
class ผู้กล้า:
def __init__(self,ชื่อ):
self.ชื่อ = ชื่อ
def __แสดงเงินเดือน(self):
return 500
class นักรบ(ผู้กล้า):
def __แสดงเงินเดือน(self):
return 1000
ผู้เล่นN = นักรบ('เอ็น')
print(ผู้เล่นN._ผู้กล้า__แสดงเงินเดือน()) # ได้ 500
print(ผู้เล่นN._นักรบ__แสดงเงินเดือน()) # ได้ 1000
อนึ่ง หากชื่อเมธอดลงท้ายด้วย __
ต่อให้ขึ้นต้นด้วย __
ก็จะไม่มีคุณสมบัติดังที่ว่านี้ เช่นพวกเมธอดพิเศษอย่าง __init__
จะเข้าถึงได้ด้วยชื่อเมธอดตามปกติ
อ้างอิง
http://docs.python.jp/3/reference/datamodel.html
http://www.lifewithpython.com/2014/01/python-super-function.html
http://shin.hateblo.jp/entry/2013/11/01/211716
http://methane.hatenablog.jp/entry/20081227/1230400144
http://yut.hatenablog.com/entry/20110120/1295533994
http://qiita.com/icoxfog417/items/e8f97a6acad07903b5b0
http://www.geocities.jp/m_hiroi/light/abcruby12.html
Reference : https://phyblas.hinaboshi.com/tsuchinoko23