φυβλαςのβλογ
phyblas的博客



ภาษา python เบื้องต้น บทที่ ๒๓: การรับทอด
เขียนเมื่อ 2016/03/24 23:37
แก้ไขล่าสุด 2024/02/22 11:06
 

ในบทที่แล้วได้พูดถึงการสร้างคลาสขึ้นมาใหม่ไปแล้ว

แต่นอกจากการสร้างคลาสขึ้นมาใหม่ตั้งแต่เริ่มต้นแล้วเรายังสามารถนำคลาสที่มี อยู่แล้วมาเสริมให้เป็นคลาสใหม่ได้ วิธีการนี้เรียกว่าการรับทอด (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__ จะเข้าถึงได้ด้วยชื่อเมธอดตามปกติ



อ้างอิง




-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python

ไม่อนุญาตให้นำเนื้อหาของบทความไปลงที่อื่นโดยไม่ได้ขออนุญาตโดยเด็ดขาด หากต้องการนำบางส่วนไปลงสามารถทำได้โดยต้องไม่ใช่การก๊อปแปะแต่ให้เปลี่ยนคำพูดเป็นของตัวเอง หรือไม่ก็เขียนในลักษณะการยกข้อความอ้างอิง และไม่ว่ากรณีไหนก็ตาม ต้องให้เครดิตพร้อมใส่ลิงก์ของทุกบทความที่มีการใช้เนื้อหาเสมอ

目录

从日本来的名言
模块
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
机器学习
-- 神经网络
javascript
蒙古语
语言学
maya
概率论
与日本相关的日记
与中国相关的日记
-- 与北京相关的日记
-- 与香港相关的日记
-- 与澳门相关的日记
与台湾相关的日记
与北欧相关的日记
与其他国家相关的日记
qiita
其他日志

按类别分日志



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  查看日志

  推荐日志

ตัวอักษรกรีกและเปรียบเทียบการใช้งานในภาษากรีกโบราณและกรีกสมัยใหม่
ที่มาของอักษรไทยและความเกี่ยวพันกับอักษรอื่นๆในตระกูลอักษรพราหมี
การสร้างแบบจำลองสามมิติเป็นไฟล์ .obj วิธีการอย่างง่ายที่ไม่ว่าใครก็ลองทำได้ทันที
รวมรายชื่อนักร้องเพลงกวางตุ้ง
ภาษาจีนแบ่งเป็นสำเนียงอะไรบ้าง มีความแตกต่างกันมากแค่ไหน
ทำความเข้าใจระบอบประชาธิปไตยจากประวัติศาสตร์ความเป็นมา
เรียนรู้วิธีการใช้ regular expression (regex)
การใช้ unix shell เบื้องต้น ใน linux และ mac
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ