การถ่ายทอดทางพันธุกรรมและความหลากหลาย
การถ่ายทอดทางพันธุกรรมและความหลากหลาย - นี่เป็นแนวคิดที่สำคัญมากใน Python คุณต้องเข้าใจมันดีขึ้นถ้าคุณต้องการเรียนรู้
มรดก
ข้อดีประการสำคัญประการหนึ่งของการเขียนโปรแกรมเชิงวัตถุคือการนำกลับมาใช้ใหม่ การถ่ายทอดทางพันธุกรรมเป็นกลไกหนึ่งในการบรรลุเป้าหมายเดียวกัน การสืบทอดช่วยให้โปรแกรมเมอร์สามารถสร้างคลาสทั่วไปหรือคลาสพื้นฐานก่อนจากนั้นจึงขยายไปยังคลาสพิเศษเพิ่มเติม ช่วยให้โปรแกรมเมอร์เขียนโค้ดได้ดีขึ้น
การใช้การสืบทอดคุณสามารถใช้หรือสืบทอดฟิลด์ข้อมูลและวิธีการทั้งหมดที่มีอยู่ในคลาสพื้นฐานของคุณ ในภายหลังคุณสามารถเพิ่มวิธีการและช่องข้อมูลของคุณเองได้ดังนั้นการสืบทอดจึงเป็นวิธีการจัดระเบียบโค้ดแทนที่จะเขียนใหม่ตั้งแต่ต้น
ในคำศัพท์เชิงวัตถุเมื่อคลาส X ขยายคลาส Y ดังนั้น Y จะเรียกว่าคลาส super / parent / base และ X เรียกว่าคลาสย่อย / คลาสย่อย / คลาสที่ได้รับ สิ่งหนึ่งที่ควรทราบในที่นี้คือเฉพาะฟิลด์ข้อมูลและวิธีการที่คลาสย่อยไม่สามารถเข้าถึงได้ ช่องข้อมูลส่วนตัวและวิธีการสามารถเข้าถึงได้ภายในชั้นเรียนเท่านั้น
ไวยากรณ์ในการสร้างคลาสที่ได้รับคือ -
class BaseClass:
Body of base class
class DerivedClass(BaseClass):
Body of derived class
การสืบทอดคุณสมบัติ
ตอนนี้ดูตัวอย่างด้านล่าง -
เอาต์พุต
ก่อนอื่นเราสร้างคลาสที่เรียกว่า Date และส่งผ่านอ็อบเจกต์เป็นอาร์กิวเมนต์, here-object คือคลาสในตัวที่จัดเตรียมโดย Python ต่อมาเราได้สร้างคลาสอื่นที่เรียกว่าเวลาและเรียกคลาส Date เป็นอาร์กิวเมนต์ ด้วยการโทรนี้เราสามารถเข้าถึงข้อมูลและคุณลักษณะทั้งหมดของคลาส Date ในคลาส Time ด้วยเหตุนี้เมื่อเราพยายามรับเมธอด get_date จาก Time class object tm ที่เราสร้างไว้ก่อนหน้านี้จึงเป็นไปได้
Object.Attribute Lookup Hierarchy
- อินสแตนซ์
- ห้องเรียน
- คลาสใด ๆ ที่คลาสนี้สืบทอดมา
ตัวอย่างมรดก
ลองมาดูตัวอย่างการสืบทอดกัน -
มาสร้างสองคลาสเพื่อเข้าร่วมในตัวอย่าง -
- Animal - คลาสจำลองสัตว์
- แมว - คลาสย่อยของสัตว์
- สุนัข - คลาสย่อยของสัตว์
ใน Python ตัวสร้างของคลาสที่ใช้สร้างอ็อบเจกต์ (อินสแตนซ์) และกำหนดค่าสำหรับแอตทริบิวต์
คอนสตรัคเตอร์ของคลาสย่อยจะถูกเรียกไปยังคอนสตรัคเตอร์ของคลาสพาเรนต์เสมอเพื่อเริ่มต้นค่าสำหรับแอ็ตทริบิวต์ในคลาสพาเรนต์จากนั้นจะเริ่มกำหนดค่าสำหรับแอ็ตทริบิวต์
เอาต์พุต
ในตัวอย่างข้างต้นเราจะเห็นแอตทริบิวต์คำสั่งหรือวิธีการที่เราใส่ไว้ในคลาสแม่เพื่อที่คลาสย่อยหรือคลาสย่อยทั้งหมดจะสืบทอดคุณสมบัตินั้นจากคลาสแม่
หากคลาสย่อยพยายามสืบทอดเมธอดหรือข้อมูลจากคลาสย่อยอื่นมันจะเกิดข้อผิดพลาดดังที่เราเห็นเมื่อคลาส Dog พยายามเรียกใช้วิธีการ swatstring () จากคลาส cat นั้นจะแสดงข้อผิดพลาด (เช่น AttributeError ในกรณีของเรา)
ความหลากหลาย (“ หลายรูปร่าง”)
Polymorphism เป็นคุณสมบัติที่สำคัญของการกำหนดคลาสใน Python ที่ใช้เมื่อคุณตั้งชื่อเมธอดโดยทั่วไปในคลาสหรือคลาสย่อย สิ่งนี้อนุญาตให้ฟังก์ชันใช้เอนทิตีประเภทต่างๆในเวลาที่ต่างกัน ดังนั้นจึงให้ความยืดหยุ่นและข้อต่อหลวมเพื่อให้โค้ดสามารถขยายและบำรุงรักษาได้ง่ายเมื่อเวลาผ่านไป
สิ่งนี้ช่วยให้ฟังก์ชันสามารถใช้อ็อบเจ็กต์ของคลาส polymorphic ใด ๆ เหล่านี้โดยไม่จำเป็นต้องตระหนักถึงความแตกต่างในคลาสต่างๆ
Polymorphism สามารถดำเนินการได้โดยการถ่ายทอดทางพันธุกรรมโดยมีคลาสย่อยที่ใช้วิธีการคลาสฐานหรือการแทนที่พวกเขา
ให้ทำความเข้าใจแนวคิดของความหลากหลายด้วยตัวอย่างการสืบทอดก่อนหน้านี้ของเราและเพิ่มวิธีการทั่วไปหนึ่งวิธีที่เรียกว่า show_affection ในทั้งสองคลาสย่อย -
จากตัวอย่างที่เราเห็นมันหมายถึงการออกแบบที่สามารถใช้วัตถุประเภทที่ไม่เหมือนกันได้ในลักษณะเดียวกันหรือเฉพาะอย่างยิ่งสองคลาสขึ้นไปด้วยวิธีการที่มีชื่อเดียวกันหรือส่วนต่อประสานทั่วไปเนื่องจากวิธีการเดียวกัน (show_affection ในตัวอย่างด้านล่าง) ถูกเรียกด้วยวัตถุประเภทใดชนิดหนึ่ง
เอาต์พุต
ดังนั้นสัตว์ทุกตัวจึงแสดงความรัก (show_affection) แต่มันต่างกัน พฤติกรรม "show_affection" จึงมีความหลากหลายในแง่ที่ว่ามันทำหน้าที่แตกต่างกันไปขึ้นอยู่กับสัตว์ ดังนั้นแนวคิด "สัตว์" ที่เป็นนามธรรมจึงไม่ได้เป็น "show_affection" แต่สัตว์บางชนิด (เช่นสุนัขและแมว) มีการนำไปใช้อย่างเป็นรูปธรรมของการกระทำ "show_affection"
Python เองก็มีคลาสที่มีความหลากหลาย ตัวอย่างฟังก์ชัน len () สามารถใช้ได้กับหลายอ็อบเจ็กต์และทั้งหมดจะส่งคืนเอาต์พุตที่ถูกต้องตามพารามิเตอร์อินพุต
การลบล้าง
ใน Python เมื่อคลาสย่อยมีเมธอดที่แทนที่เมธอดของ superclass คุณยังสามารถเรียกเมธอด superclass โดยเรียก
Super (Subclass, self) วิธีการแทน self.method.
ตัวอย่าง
class Thought(object):
def __init__(self):
pass
def message(self):
print("Thought, always come and go")
class Advice(Thought):
def __init__(self):
super(Advice, self).__init__()
def message(self):
print('Warning: Risk is always involved when you are dealing with market!')
การสืบทอดตัวสร้าง
ถ้าเราเห็นจากตัวอย่างการถ่ายทอดทางพันธุกรรมก่อนหน้านี้ __init__ อยู่ในคลาสแม่ในส่วนบน 'ทำให้สุนัขหรือแมวระดับลูกไม่มีเมธอด __init__ อยู่ในนั้น Python ใช้การค้นหาแอตทริบิวต์การสืบทอดเพื่อค้นหา __init__ ในคลาสสัตว์ เมื่อเราสร้างคลาสลูกขึ้นมาก่อนอื่นมันจะดูเมธอด __init__ ในคลาสสุนัขจากนั้นก็ไม่พบจากนั้นมองเข้าไปในคลาสแม่ของสัตว์และพบที่นั่นและเรียกสิ่งนั้นที่นั่น ดังนั้นเมื่อการออกแบบคลาสของเรามีความซับซ้อนเราอาจต้องการเริ่มต้นอินสแตนซ์ในขั้นแรกประมวลผลผ่านตัวสร้างคลาสแม่และจากนั้นผ่านตัวสร้างคลาสลูก
เอาต์พุต
ในตัวอย่างข้างต้น - สัตว์ทุกตัวมีชื่อและสุนัขทุกสายพันธุ์ เราเรียกว่าตัวสร้างคลาสแม่ด้วย super สุนัขจึงมี __init__ เป็นของตัวเอง แต่สิ่งแรกที่เกิดขึ้นคือเราเรียกว่า super Super ถูกสร้างขึ้นในฟังก์ชั่นและได้รับการออกแบบมาเพื่อเชื่อมโยงคลาสกับซุปเปอร์คลาสหรือคลาสพาเรนต์
ในกรณีนี้เราบอกว่ารับคลาส super ของสุนัขและส่งต่ออินสแตนซ์สุนัขไปยังวิธีใดก็ตามที่เราพูดที่นี่ตัวสร้าง __init__ อีกนัยหนึ่งคือเราเรียกคลาสแม่ว่า Animal __init__ ด้วยวัตถุสุนัข คุณอาจถามว่าทำไมเราจะไม่พูดแค่ Animal __init__ กับอินสแตนซ์สุนัขเราสามารถทำได้ แต่ถ้าชื่อคลาสสัตว์มีการเปลี่ยนแปลงในบางครั้งในอนาคต จะเป็นอย่างไรถ้าเราต้องการจัดลำดับชั้นของคลาสใหม่สุนัขก็จะได้รับมรดกจากคลาสอื่น การใช้ super ในกรณีนี้ช่วยให้เราสามารถจัดเก็บสิ่งต่างๆแบบแยกส่วนและง่ายต่อการเปลี่ยนแปลงและบำรุงรักษา
ดังนั้นในตัวอย่างนี้เราสามารถรวมฟังก์ชัน __init__ ทั่วไปเข้ากับฟังก์ชันที่เฉพาะเจาะจงมากขึ้น สิ่งนี้เปิดโอกาสให้เราแยกฟังก์ชันการทำงานทั่วไปออกจากฟังก์ชันเฉพาะซึ่งสามารถกำจัดการทำซ้ำโค้ดและเชื่อมโยงคลาสซึ่งกันและกันในลักษณะที่สะท้อนถึงการออกแบบโดยรวมของระบบ
สรุป
__init__ ก็เหมือนกับวิธีอื่น ๆ สามารถสืบทอดได้
ถ้าคลาสไม่มีตัวสร้าง __init__ Python จะตรวจสอบคลาสพาเรนต์เพื่อดูว่าสามารถหาเจอหรือไม่
ทันทีที่พบ Python เรียกมันและหยุดมอง
เราสามารถใช้ฟังก์ชัน super () เพื่อเรียกใช้เมธอดในคลาสแม่
เราอาจต้องการเริ่มต้นในผู้ปกครองเช่นเดียวกับคลาสของเราเอง
มรดกหลายรายการและแผนผังการค้นหา
ตามชื่อที่ระบุการสืบทอดหลายรายการคือ Python คือเมื่อคลาสสืบทอดมาจากหลายคลาส
ตัวอย่างเช่นเด็กได้รับลักษณะบุคลิกภาพจากทั้งพ่อและแม่ (แม่และพ่อ)
Python Multiple Inheritance Syntax
ในการสร้างคลาสที่สืบทอดมาจากคลาสผู้ปกครองหลายคลาสเราจะเขียนชื่อของคลาสเหล่านี้ไว้ในวงเล็บให้กับคลาสที่ได้รับในขณะที่กำหนด เราแยกชื่อเหล่านี้ด้วยลูกน้ำ
ด้านล่างนี้คือตัวอย่างของสิ่งนั้น -
>>> class Mother:
pass
>>> class Father:
pass
>>> class Child(Mother, Father):
pass
>>> issubclass(Child, Mother) and issubclass(Child, Father)
True
การสืบทอดหลายอย่างหมายถึงความสามารถในการสืบทอดจากสองคลาสหรือมากกว่าสองคลาส ความซับซ้อนเกิดขึ้นเมื่อเด็กได้รับมรดกจากพ่อแม่และผู้ปกครองสืบทอดมาจากชั้นปู่ย่าตายาย Python ปีนต้นไม้ที่สืบทอดมาโดยมองหาแอตทริบิวต์ที่ถูกร้องขอให้อ่านจากวัตถุ มันจะตรวจสอบอินสแตนซ์ภายในคลาสจากนั้นคลาสพาเรนต์และสุดท้ายจากคลาสปู่ย่าตายาย ตอนนี้คำถามเกิดขึ้นในลำดับที่จะค้นหาคลาส - หายใจก่อนหรือลึก - ก่อน ตามค่าเริ่มต้น Python จะไปพร้อมกับความลึกก่อน
นั่นคือเหตุผลที่ในแผนภาพด้านล่าง Python ค้นหาเมธอด dothis () เป็นอันดับแรกในคลาส A ดังนั้นลำดับความละเอียดของเมธอดในตัวอย่างด้านล่างจะเป็น
Mro- D→B→A→C
ดูแผนภาพการสืบทอดหลายรายการด้านล่าง -
มาดูตัวอย่างเพื่อทำความเข้าใจคุณสมบัติ“ mro” ของ Python
เอาต์พุต
ตัวอย่างที่ 3
ลองมาดูอีกตัวอย่างหนึ่งของการสืบทอดหลาย“ รูปทรงเพชร”
แผนภาพด้านบนจะถือว่าไม่ชัดเจน จากตัวอย่างก่อนหน้านี้ของเราทำความเข้าใจ "ลำดับความละเอียดของวิธีการ "ie mro จะเป็น D → B → A → C → A แต่ไม่ใช่ ในการรับ A ที่สองจาก C Python จะละเว้น A. ก่อนหน้าดังนั้น mro ในกรณีนี้จะเป็น D → B → C → A
มาสร้างตัวอย่างตามแผนภาพด้านบน -
เอาต์พุต
กฎง่ายๆในการทำความเข้าใจผลลัพธ์ข้างต้นคือ - ถ้าคลาสเดียวกันปรากฏในลำดับการแก้ปัญหาวิธีการที่ปรากฏก่อนหน้านี้ของคลาสนี้จะถูกลบออกจากลำดับการแก้ปัญหาวิธีการ
โดยสรุป -
ชั้นเรียนใด ๆ สามารถสืบทอดจากหลายชั้นเรียน
โดยปกติ Python จะใช้คำสั่ง "deep-first" เมื่อค้นหาคลาสที่สืบทอดมา
แต่เมื่อสองคลาสสืบทอดมาจากคลาสเดียวกัน Python จะกำจัดการปรากฏครั้งแรกของคลาสนั้นออกจาก mro
นักตกแต่งวิธีการแบบคงที่และแบบคลาส
ฟังก์ชัน (หรือวิธีการ) ถูกสร้างขึ้นโดยคำสั่ง def
แม้ว่าเมธอดจะทำงานในลักษณะเดียวกับฟังก์ชันยกเว้นจุดหนึ่งที่อาร์กิวเมนต์แรกของวิธีการคือวัตถุอินสแตนซ์
เราสามารถจำแนกวิธีการตามพฤติกรรมเช่น
Simple method- กำหนดไว้นอกชั้นเรียน ฟังก์ชันนี้สามารถเข้าถึงแอตทริบิวต์คลาสโดยป้อนอาร์กิวเมนต์อินสแตนซ์:
def outside_func(():
Instance method -
def func(self,)
Class method - หากเราจำเป็นต้องใช้แอตทริบิวต์คลาส
@classmethod
def cfunc(cls,)
Static method - ไม่มีข้อมูลใด ๆ เกี่ยวกับชั้นเรียน
@staticmethod
def sfoo()
จนถึงตอนนี้เราได้เห็นวิธีการอินสแตนซ์แล้วตอนนี้ถึงเวลาทำความเข้าใจกับอีกสองวิธี
วิธีการเรียน
มัณฑนากร @classmethod เป็นมัณฑนากรฟังก์ชันในตัวที่ได้รับการส่งผ่านคลาสที่เรียกใช้หรือคลาสของอินสแตนซ์ที่เรียกว่าเป็นอาร์กิวเมนต์แรก ผลลัพธ์ของการประเมินนั้นจะสะท้อนนิยามฟังก์ชันของคุณ
ไวยากรณ์
class C(object):
@classmethod
def fun(cls, arg1, arg2, ...):
....
fun: function that needs to be converted into a class method
returns: a class method for function
พวกเขามีสิทธิ์เข้าถึงอาร์กิวเมนต์ cls นี้ไม่สามารถแก้ไขสถานะอินสแตนซ์วัตถุได้ ที่ต้องการเข้าถึงตนเอง
มันถูกผูกไว้กับคลาสไม่ใช่อ็อบเจ็กต์ของคลาส
เมธอดคลาสยังคงสามารถแก้ไขสถานะคลาสที่ใช้กับอินสแตนซ์ทั้งหมดของคลาสได้
วิธีคงที่
วิธีการคงที่จะไม่ใช้พารามิเตอร์ self หรือ cls (class) แต่สามารถยอมรับพารามิเตอร์อื่น ๆ ได้ตามอำเภอใจ
syntax
class C(object):
@staticmethod
def fun(arg1, arg2, ...):
...
returns: a static method for function funself.
- วิธีการแบบคงที่ไม่สามารถแก้ไขสถานะวัตถุหรือสถานะคลาสได้
- พวกเขาถูก จำกัด ในข้อมูลที่พวกเขาสามารถเข้าถึงได้
เมื่อใดควรใช้อะไร
โดยทั่วไปเราใช้ class method เพื่อสร้างวิธีการโรงงาน เมธอดของโรงงานส่งคืนคลาสอ็อบเจ็กต์ (คล้ายกับคอนสตรัคเตอร์) สำหรับกรณีการใช้งานที่แตกต่างกัน
โดยทั่วไปเราใช้วิธีการแบบคงที่เพื่อสร้างฟังก์ชันยูทิลิตี้