φυβλαςのβλογ
บล็อกของ 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
ภาษา mongol
ภาษาศาสตร์
maya
ความน่าจะเป็น
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
-- บันทึกในฮ่องกง
-- บันทึกในมาเก๊า
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
qiita
บทความอื่นๆ

บทความแบ่งตามหมวด



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

  ค้นหาบทความ

  บทความแนะนำ

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

บทความแต่ละเดือน

2024年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2023年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2022年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2021年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2020年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

ค้นบทความเก่ากว่านั้น

ไทย

日本語

中文