เหตุใดกลไกการสืบทอดของ Python จึงอนุญาตให้ฉันกำหนดคลาสที่ไม่ได้รับการสร้างอินสแตนซ์อย่างถูกต้อง

ฉันขอโทษสำหรับการกำหนดคำถามที่ค่อนข้างคลุมเครือ ฉันจะพยายามชี้แจงสิ่งที่ฉันหมายถึงโดยใช้ตัวอย่างง่ายๆ ด้านล่างนี้ ฉันมีคลาสที่ต้องการใช้เป็นฐานสำหรับคลาสอื่น:

class parent:
    def __init__(self, constant):
        self.constant = constant
    def addconstant(self, number):
        return self.constant + number

พารามิเตอร์ self.constant มีความสำคัญอย่างยิ่งต่อการใช้งานของคลาส เนื่องจากเมธอด addconstant ขึ้นอยู่กับพารามิเตอร์นั้น ดังนั้นเมธอด __init__ จะดูแลการบังคับให้ผู้ใช้กำหนดค่าของพารามิเตอร์นี้ จนถึงตอนนี้ดีมาก

ตอนนี้ฉันกำหนดคลาสย่อยดังนี้:

class child(parent):
    def __init__(self):
        pass

ไม่มีอะไรหยุดฉันไม่ให้สร้างอินสแตนซ์ของคลาสนี้ แต่เมื่อฉันพยายามใช้ addconstant มันจะพังอย่างเห็นได้ชัด

b = child()
b.addconstant(5)
AttributeError: 'child' object has no attribute 'constant'

ทำไม Python ถึงยอมทำเช่นนี้!? ฉันรู้สึกว่า Python ยืดหยุ่นเกินไปและทำให้จุด OOP และการห่อหุ้มแตกสลายไป หากฉันต้องการขยายคลาสเพื่อใช้ประโยชน์จากการสืบทอด ฉันจะต้องระมัดระวังและรู้รายละเอียดบางประการเกี่ยวกับการใช้งานคลาส ในกรณีนี้ ฉันต้องรู้ว่าการบังคับให้ผู้ใช้ตั้งค่าคงที่พารามิเตอร์ constant นั้นเป็นพื้นฐานที่จะไม่ทำลายการใช้งานของคลาส สิ่งนี้ไม่ได้ขัดต่อหลักการห่อหุ้มใช่ไหม


person Onturenio    schedule 19.02.2021    source แหล่งที่มา
comment
Python มอบความรับผิดชอบมากมายให้กับผู้ใช้ในการเป็น “ผู้ใหญ่ที่มีความรับผิดชอบ” เช่น ด้วยคุณลักษณะ "ส่วนตัว" ที่ได้รับการคุ้มครองแทบจะไม่และอื่นๆ มันไม่ได้อยู่เพื่อดูแลคุณ…   -  person deceze♦    schedule 19.02.2021
comment
เหตุผลหลายประการที่ผู้คนชื่นชอบ Python ก็คือว่ามันมีความยืดหยุ่นมากและไม่ได้ปฏิเสธอะไรหลายๆ อย่างเลย ดังนั้นหากคุณต้องการเรียกตัวสร้างค่าเริ่มต้นของพาเรนต์ ก็ให้เรียกมัน ถ้าไม่ก็อย่าเรียก   -  person wim    schedule 19.02.2021
comment
หากฉันต้องการขยายคลาสเพื่อใช้ประโยชน์จากการสืบทอดฉันต้องระมัดระวังและรู้รายละเอียดบางประการในการใช้งานคลาสให้แน่ชัด!   -  person Cyttorak    schedule 19.02.2021
comment
Encapsulation เป็นเรื่องของ Java มากกว่า ไม่มากสำหรับ Python   -  person M-Chen-3    schedule 19.02.2021
comment
โปรดทราบว่าคำจำกัดความของคลาสนั้นไม่ได้กำหนดแอตทริบิวต์ constant โทร parent.__init__ ทำ   -  person chepner    schedule 19.02.2021


คำตอบ (1)


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

ในภาษาเช่น Java คุณลักษณะของ parent จะถูกสร้างขึ้น ณ เวลาคอมไพล์ แต่คำจำกัดความคลาส Python จะถูกดำเนินการ ไม่ใช่คอมไพล์

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

เทคนิคที่มีประโยชน์ในบางครั้งคือการกำหนดค่าเริ่มต้นที่สมเหตุสมผลบนตัวคลาสเอง

class parent:
    constant = 0
    def __init__(self, constant):
        self.constant = constant
    def addconstant(self, number):
        return self.constant + number

Python จะกลับไปเข้าถึงแอตทริบิวต์ของคลาสหากคุณไม่ได้กำหนดไว้บนอินสแตนซ์ ดังนั้น นี่จะเป็นค่าสำรองในกรณีที่คุณลืมทำสิ่งนั้น

person kindall    schedule 19.02.2021
comment
ฉันจะยืนยันว่าทางเลือกเริ่มต้นของคลาสเพียงปิดบังข้อผิดพลาด ตอนนี้คุณจะไม่เห็นข้อความแสดงข้อผิดพลาด แต่อาจมีการทำงานแตกต่างออกไปในลักษณะที่ละเอียดอ่อน - person deceze♦; 19.02.2021
comment
ขึ้นอยู่กับกรณีการใช้งาน แต่ใช่แล้ว ฉันเห็นว่าการโปรดปรานล้มเหลวอย่างรวดเร็วที่นี่ - person kindall; 19.02.2021