You are on page 1of 13

XIII ლექცია

მრავლობითი მემკვიდრეობითობა

gachechiladze_lela@yahoo.com
რას გულისხმობს მრავლობითი
მემკვიდრეობითობა?
როგორც ცნობილია, ობიექტზე ორიენტირებული დაპროგრამების ერთ-ერთ
ფუნდამენტურ პრინციპს მემკვიდრეობითობა წარმოადგენს.
პითონში შესაძლებელია არა მხოლოდ მარტივი მემკვიდრეობითობის, არამედ
მრავლობითი მემკვიდრეობითობის განხორციელებაც, რაც იმ ფაქტს გულისხმობს,
რომ შვილობილ კლასს შესაძლებლობა აქვს ფუნქციონალი მიიღოს არა მხოლოდ
ერთი, არამედ რამდენიმე მშობელი კლასისგან. აღნიშნულის საილუსტრაციოდ
შემდეგი პროგრამული კოდი განვიხილოთ:
class Doctor:
def can_cure(self):
print("მე ვარ ექიმი და ვმკურნალობ პაციენტებს.")

class Builder:
def can_build(self):
print("მე ვარ მშენებელი და ვაშენებ სახლებს.") შედეგები:

class Person(Doctor, Builder):


pass
p=Person()
p.can_cure()
p.can_build()

gachechiladze_lela@yahoo.com 2
მე-2 სლაიდზე წარმოდგენილი კოდის
ანალიზი
წინა (მე-2) სლაიდზე წარმოდგენილ პროგრამულ კოდში ჩვენ შევქმენით სამი
კლასი: Doctor, Builder და Person კლასები. ამ უკანასკნელმა (Person ) კლასმა მემ-
კვიდრეობით მიიღო წინა ორი (Doctor დაBuilder) კლასების, როგორც მისი მშობელი
კლასების, ფუნქციონალი - მეთოდები: can_cure() და can_build(). რაც ითვალისწი-
ნებს იმ ფაქტს, რომ Person კლასის ობიექტს შეუძლია მიმართოს (გამოიყენოს)
თავის მშობელ კლასებში განსაზღვრულ ზემოაღნიშნულ მეთოდებს.
ამგვარად, მემკვიდრეობით კლასებს შეუძლიათ გამოიყენონ მშობელი კლასების
მეთოდები. მაგრამ, თუ რამდენიმე მშობელს ერთნაირი მეთოდები აქვს? რომელ
მეთოდს გამოიყენებს ამ შემთხვევაში მემკვიდრე კლასი?

gachechiladze_lela@yahoo.com 3
მრავლობითი მემკვიდრეობითობის რეალიზება
Method Resolution Order / MRO
განვიხილოთ შემდეგი პროგრამული კოდი:
class A:
def hi(self):
print("Class A")
class B(A):
def hi(self): შედეგი:
print("Class B")
class C(A):
def hi(self):
print("Class C")
class D(B, C):
pass
d = D()
d.hi()
აღნიშნულ შემთხვევას რომბისებური მემკვიდრეობითობა (diamond problem)
ეწოდება და ის მეთოდების გამოძახების (რეალიზების) რიგის გათვალისწინებით
წყდება. პითონში აღნიშნული რიგის განსაზღვრის მიზნით სიგანეში ძებნის ალგო-
რითმი გამოიყენება, რაც ნიშნავს, რომ ინტერპრეტატორი hi მეთოდს ჯერ D კლასში
ეძებს, და რადგან ის არ მოიცავს აღნიშნულ მეთოდს, ძებნას აგრძელებს ჯერ B
კლასში (რამეთუ, ის მემკვიდრე კლასების სიაში პირველი - მარცხნივ დგას) და შემ-
დეგ C კლასში (იმ შემთხვევაში, თუ B კლასი ამ მეთოდს არ მოიცავს) და სულ
ბოლოს - A კლასში. gachechiladze_lela@yahoo.com 4
მეთოდი mro()

იმის დასადგენად, თუ რა თანმიმდევრობით განიხილება იერარქიულ სტრუქტუ-


რაში კლასები, mro() მეთოდი გამოიყენება.
lass A:
def hi(self):
print("Class A")
class B(A):
def hi(self):
print("Class B")
class C(A):
def hi(self):
print("Class C")
class D(B, C):
pass
d = D()
d.hi()
print(D.mro())

შედეგები:

gachechiladze_lela@yahoo.com 5
მე-4 სლაიდზე წარმოდგენილი კოდის მოდიფიკაცია

თუ ჩვენ გვსურს, გამოვიყენოთ კონკრეტულ მშობელ კლასში არსებული


მეთოდი, რომლის სახელი და სიგნატურა სხვა მშობელ ან შვილობილ კლასებში
განსაზღვრული მეთოდების სახელსა და სიგნატურას ემთხვევა, საჭიროა ის ცხადი
სახით გამოვიძახოთ კლასის სახელით, წერტილის ოპერატორით და აუცილებლად
self პარამეტრით.
class A:
შედეგი:
def hi(self):
print("Class A")

class B(A):
def hi(self):
print("Class B")

class C(A):
def hi(self):
print("Class C")

class D(B, C):


def call_hi(self):
C.hi(self)

d = D()
d.call_hi()
gachechiladze_lela@yahoo.com 6
კონფლიქტური სიტუაციები
დავუშვათ, მე-2 სლაიდზე წარმოდგენილ კოდში Person კლასსაც გააჩნია მეთო-
დი სახელწოდებით can_build(). ამ შემთხვევაში, თუ ჩვენ შვილობილი (Person )
კლასის ობიექტით მივმართავთ აღნიშნულ მეთოდს, ცხადია, ის თავის კლასში გან-
საზღვრულ მეთოდს გამოიძახებს და არა Builder კლასში განსაზღვრულ მეთოდს.
კერძოდ:
class Doctor:
def can_cure(self):
print("მე ვარ ექიმი და ვმკურნალობ პაციენტებს.")

class Builder:
def can_build(self):
print("მე ვარ მშენებელი და ვაშენებ სახლებს.")

class Person(Doctor, Builder):


def can_build(self):
print("მე ვარ ადამიანი და მეც ვაშენებ სახლებს.") შედეგი:

p=Person()
p.can_build()
gachechiladze_lela@yahoo.com 7
კონფლიქტური სიტუაციები (გაგრძელება)
ახლა დავუშვათ, რომ can_biuld() მეთოდი Doctor კლასსაც გააჩნია და Builder
კლასსაც, ხოლო Person კლასს - არა. ანუ, გვაქვს შემდეგი სიტუაცია:
class Doctor:
def can_cure(self):
print("მე ვარ ექიმი და ვმკურნალობ პაციენტებს.")
def can_build(self):
print("მე ვარ ექიმი და მეც ვაშენებ სახლებს, თუმცა, არც ისე კარგად :(")
class Builder:
def can_build(self):
print("მე ვარ მშენებელი და ვაშენებ სახლებს.")

class Person(Doctor, Builder):


pass შედეგი:
p=Person()
p.can_build()

აღნიშნული შედეგი იმიტომ მიიღება, რომ Person კლასი can_biuld() მეთოდს არ


მოიცავს, მაგრამ, ვინაიდან მშობელი კლასების ჩამონათვალში Doctor კლასი მარცხ-
ნივ პირველი წერია, ამიტომ ამ კლასში არსებული can_biuld() მეთოდი გამოიძახე-
ბა და არა Builder კლასში არსებული იმავე სახელის მეთოდი.

gachechiladze_lela@yahoo.com 8
კონფლიქტური სიტუაციები (გაგრძელება)
თუ წინა (მე-8) სლაიდზე წარმოდგენილ კოდში მშობელი კლასების ჩამო-
ნათვალში გადავაადგილებთ Doctor და Builder კლასებს, შემდეგ სურათს მივიღებთ:
class Doctor:
def can_cure(self):
print("მე ვარ ექიმი და ვმკურნალობ პაციენტებს.")
def can_build(self):
print("მე ვარ ექიმი და მეც ვაშენებ სახლებს, თუმცა, არც ისე კარგად :(")
class Builder:
def can_build(self):
print("მე ვარ მშენებელი და ვაშენებ სახლებს.")

class Person(Builder, Doctor):


pass შედეგი:
p=Person()
p.can_build()

კლასებში მეთოდების ძებნის ამ მეთოდს MRO (Method Resolution Order) ეწო-


დება, რომელიც გვიჩვენებს, თუ როგორია კლასების იერარქიულ სტრუქტურებში
კლასების წარმოდგენის რიგი.

gachechiladze_lela@yahoo.com 9
მეთოდი super()
წინა (მე-9) სლაიდზე წარმოდგენილ კოდში სამივე კლასში დავამატოთ ერთი და
იმავე სახელის მქონე მეთოდი graduate() და შვილობილ კლასში შევეცადოთ super()
მეთოდის გამოყენებით გამოვიძახოთ ეს მეთოდი. საინტერესოა, რომელი სუპერ-
კლასის მეთოდი იმუშავებს - Doctor თუ Builder კლასის?

class Doctor: შედეგი:


def graduate(self):
print("მე გავხდი ექიმი.")

class Builder:
def graduate(self):
print("მე გავხდი მშენებელი.")

class Person(Doctor, Builder):


def graduate(self):
print("საინტერესოა, რა პროფესიის ვარ მე?")
super().graduate()
p=Person()
p.graduate()

ალბათ, ადვილი მისახვედრია, თუ რატომ მივიღეთ ეს შედეგი.  საინტერესოა,


როგორ გამოვიძახოთ ორივე კლასის graduate() მეთოდი ?

gachechiladze_lela@yahoo.com 10
მეთოდი super()
თუ წინა (მე-10) სლაიდზე წარმოდგენილ კოდში მემკვიდრე კლასის graduate()
მეთოდში დავამატებთ ბრძანებას: Builder.graduate(self), რომელსაც წინ უსწრებს
ბრძანება: super().graduate(), მაშინ ცხადია, ჩვენ ორივე მშობელ კლასში განსაზღვ-
რულ მეთოდს გამოვიძახებთ:
class Doctor: შედეგები:
def graduate(self):
print("მე გავხდი ექიმი.")
class Builder:
def graduate(self):
print("მე გავხდი მშენებელი.")

class Person(Doctor, Builder):


def graduate(self):
print("საინტერესოა, რა პროფესიის ვარ მე?")
super().graduate()
Builder.graduate(self)
p=Person()
p.graduate()

gachechiladze_lela@yahoo.com 11
__init__ მეთოდი და მრავლობითი მემკვიდრეობითობა
მე-11 სლაიდზე წარმოდგენილ პროგრამულ კოდში ყველა კლასში ჩავამატოთ
პარამეტრებიანი კონსტრუქტორი (__init__) მეთოდი და ვნახოთ, როგორ ხდება
მათი გამოძახება მემკვიდრე კლასიდან.
class Doctor:
def __init__(self, degree):
self.degree=degree

def graduate(self): შედეგები:


print("მე გავხდი ექიმი.")

class Builder:
def __init__(self, rank):
self.rank=rank

def graduate(self):
print("მე გავხდი მშენებელი.")

class Person(Doctor, Builder):


def __init__(self, degree, rank):
super().__init__(degree) #Doctor კლასის კონსტრუქტორის გამოძახება
Builder.__init__(self, rank) #Builder კლასის კონსტრუქტორის გამოძახება
def graduate(self):
print("საინტერესოა, რა პროფესიის ვარ მე?")
super().graduate()
Builder.graduate(self)

p=Person("Spec", 5)
p.graduate() gachechiladze_lela@yahoo.com 12
გისურვებთ წარმატებულ სწავლას!

gachechiladze_lela@yahoo.com 13

You might also like