ใน
บทที่แล้วได้พูดถึงการสร้างคลาสขึ้นมาใหม่ไปแล้ว
แต่นอกจากการสร้างคลาสขึ้นมาใหม่ตั้งแต่เริ่มต้นแล้วเรายังสามารถนำคลาสที่มี อยู่แล้วมาเสริมให้เป็นคลาสใหม่ได้ วิธีการนี้เรียกว่า
การรับทอด (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สูงสุด
***ในไพธอน 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
อนึ่ง ที่จริงแล้วการรับทอดจาก ๒ คลาสขึ้นไปพร้อมกันนั้นในบางภาษาเช่นภาษาจาวาจะไม่สามารถทำได้ และนักเขียนโปรแกรมบางคนก็ไม่สนับสนุนการทำแบบนี้เพราะอาจทำให้เกิดปัญหาได้ในกรณีที่ชื่อตัวแปรหรือเมธอดมีการซ้อนทับกัน กรณีแบบนี้จะต้องมีอย่างใดอย่างหนึ่งหายไปและทำให้มีการทำงานไม่สมบูรณ์
ในกรณีของซี++ หากมีเมธอดชื่อซ้ำกันแล้วไม่ได้ระบุไว้ว่าจะให้เหลือของฝ่ายไหนก็จะเกิดข้อผิดพลาดขึ้น
ดังนั้นแม้ว่าภาษาไพธอนจะสามารถรับทอดจาก ๒ คลาสขึ้นไปได้ แต่ก็ไม่ควรจะทำโดยไม่มีความจำเป็นและต้องระวังด้วยว่า ๒ คลาสนั้นไม่มีเมธอดหรือแอตทริบิวต์ที่ชื่อซ้ำ ไม่มีผลข้างเคียงอะไรหากรับทอดมาพร้อมกัน
เมธอดหรือแอตทริบิวต์ที่ชื่อขึ้นต้นด้วย __ โดยทั่วไปแล้วเมธอดและแอตทริบิวต์จะตั้งชื่อเป็นอะไรก็ได้ หลักการตั้งชื่อก็เหมือนตัวแปรทั่วไป แต่ว่าจะมีกรณีพิเศษเกิดขึ้นหากตั้งชื่อโดยมีขีดล่างสองอันนำหน้า
เมธอดหรือแอตทริบิวต์ที่ชื่อขึ้นต้นด้วย
__
จะไม่สามารถเข้าถึงได้โดยตรงจากภายนอกคลาส
ยกตัวอย่าง ประกาศคลาส
ผู้กล้า
ใหม่โดยเปลี่ยนแค่ให้แอตทริบิวต์
เงินเดือน
มี
__
นำหน้า
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__
จะเข้าถึงได้ด้วยชื่อเมธอดตามปกติ
อ้างอิง