การถ่ายทอดทางพันธุกรรมและความหลากหลาย

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

  • โดยทั่วไปเราใช้วิธีการแบบคงที่เพื่อสร้างฟังก์ชันยูทิลิตี้