Python-ում բազմակի ժառանգումը բավական հզոր գործիք է, որի շնորհիվ class-ը կարող է ժառանգել ատրիբուտներ և մեթոդներ՝ մեկից ավելի ծնող class-ներից: Այն թույլ է տալիս ստեղծել class, որը միավորում է բազմաթիվ այլ class-ներից ստացված բնութագրերը կամ ատրիբուտները: Սակայն հզոր գործիքի հետ աշխատելն ունի իր բարդությունը, ուստի բազմակի ժառանգումը պետք է կիրառվի խելամտորեն։
Բազմակի ժառանգումը հասկանալու համար եկեք դիտարկենք մուլտիմեդիա ֆայլային համակարգի օրինակ: Ենթադրենք՝ ունենք Video class և Audio class: Դիցուք, ցանկանում ենք class ստեղծել մուլտիմեդիա ֆայլերի համար, որոնք ունեն և՛ տեսանյութեր, և՛ ձայնագրություններ: Մենք դա կարող ենք անել՝ կիրառելով բազմակի ժառանգումը.
class Video: # Define a class named 'Video'
def __init__(self):
self.video_codec = 'H.264'
def play_video(self):
return 'Playing video...'
class Audio: # Define a class named 'Audio'
def __init__(self):
self.audio_codec = 'AAC'
def play_audio(self):
return 'Playing audio...'
class Multimedia(Video, Audio): # Define a subclass named 'Multimedia' that inherits from 'Video' and 'Audio'
def __init__(self):
Video.__init__(self) # Call the parent 'Video' class's '__init__' method
Audio.__init__(self) # Call the parent 'Audio' class's '__init__' method
def play(self):
return self.play_video() + ' ' + self.play_audio() # Play both video and audio
multimedia = Multimedia() # Create an instance of the 'Multimedia' class
print(multimedia.play()) # Output: 'Playing video... Playing audio...'
Այս օրինակում Multimedia class-ը ժառանգում է և՛ Video, և՛ Audio class-ներից: Մենք կանչում ենք Video և Audio class-ների կոնստրուկտորներին Multimedia-ի կոնստրուկտորում՝ Multimedia օբյեկտի բոլոր ատրիբուտները ճշտորեն ստեղծելու համար: Multimedia class-ի play() մեթոդը համատեղում է play_video() մեթոդը՝ Video-ից, և play_audio() մեթոդը՝ Audio-ից:
Բազմակի ժառանգումը հնարավորություն է տալիս՝ համատեղելու բազմաթիվ class-ների վարքագիծը: Սակայն այն պետք է օգտագործել զգուշությամբ, քանի որ կարող են բարդություններ ծագել:
🤔
Եթե ծնող class-ներն ունեն նույն անուններով մեթոդներ, ժառանգման հերթականությունը կարևոր է, քանի որ Python-ը մեթոդները կփնտրի այն հերթականությամբ, որով ծնող class-ները նշված են ենթադասերի սահմանման մեջ:
Այս հերթականությունը հայտնի է որպես Method Resolution Order (MRO):
Method Resolution Order
Python-ն օգտագործում է ալգորիթմ, որը կոչվում է C3 linearization, կամ պարզապես C3, որով որոշում է մեթոդի հերթականությունը, երբ class-ները ժառանգում են բազմաթիվ ծնողներից: Նպատակն այն է, որ պահպանվի ենթադասերում հայտարարման կարգը՝ միաժամանակ պահպանելով ծնող class-ների կարգը: Ընդ որում, դուք կարող եք հեշտությամբ ստուգել MRO-ն class-ի համար՝ օգտագործելով mro() մեթոդը (առանց ալգորիթմի բարդությունների մեջ խորանալու).
class A: # Define a class named 'A'
def process(self):
return 'A process'
class B(A): # Define a class named 'B' that inherits from 'A'
def process(self):
return 'B process'
class C(A): # Define a class named 'C' that inherits from 'A'
def process(self):
return 'C process'
class D(B, C): # Define a class named 'D' that inherits from 'B' and 'C'
pass
print(D.mro()) # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
Վերևի օրինակում D class-ի MRO-ն D -> B -> C -> A -> object է: Սա նշանակում է, որ երբ դուք կանչում եք մեթոդ D-ի օբյեկտի վրա, Python-ը նախ նայում է D-ի մեթոդին: Եթե այստեղ չի գտնում այն, ապա անցնում է B, այնուհետև C, իսկ հետո A օբյեկտներին։
Եթե ցանկանում եք կանչել ծնող class-ի մեթոդ, կարող եք ուղղակիորեն կանչել այն՝ օգտագործելով ծնող class-ի անունը: Սակայն սովորաբար խորհուրդ չի տրվում կատարել այս գործողությունը, քանի որ այն կարող է հանգեցնել բարդ կոդի, որի հետ դժվար է աշխատել:
Եկեք փոփոխենք D class-ը՝ A class-ի process մեթոդը կանչելու համար.
class D(B, C): # Define a class named 'D' that inherits from 'B' and 'C'
def process(self):
return A.process(self)
d = D() # Create an instance of the 'D' class
print(d.process()) # A process
Վերոնշյալ օրինակում, թեև D class-ը ժառանգում է B-ից և C-ից (երկուսն էլ ունեն process մեթոդ), մենք հատուկ կանչում ենք process մեթոդ-ը A class-ից: Սա երաշխավորում է A class-ի process մեթոդի կիրառումը՝ անկախ նրանից, թե ինչ է MRO-ն։
Ուշադրություն դարձրեք, թե ինչպես է self-ը փոխանցվում որպես արգումենտ: Python-ում self-ն առնչվում է class-ի ընթացիկ օբյեկտին և օգտագործվում է այդ օբյեկտի հետ կապված փոփոխականներին և մեթոդներին հասանելիություն ստանալու համար։ Այն անուղղակիորեն փոխանցվում է որպես օբյեկտների մեթոդների առաջին արգումենտ: Երբ կանչում ենք A.process(self), մենք ասում ենք «Կանչել A class-ի process մեթոդը կոնկրետ օբյեկտի վրա (ներկայացված է self-ով)»: Թեև մեթոդը սահմանված է A-ում, այն իրականացվում է D class-ի օբյեկտի համատեքստում: Սա նշանակում է, որ նրան հասանելի է D class-ում կամ դրա մայր class-ներում սահմանված ցանկացած ատրիբուտ կամ մեթոդ: Այսպիսով, self-ը A.process-ում թույլ է տալիս մեզ process մեթոդը կանչել A-ից D-ի օբյեկտի վրա:
Բազմակի ժառանգումը կարող է հզոր գործիք լինել Python լեզվով գրված ծրագրերի մեջ բազմակողմանի և բազմակի օգտագործման class-ներ ստեղծելու համար:
Առաջադրանք․ երկկենցաղների դասը
Ծրագրավորման կախարդական աշխարհում կան կենդանիների մի քանի class-ներ՝ Fish, WaterAnimal, և LandAnimal։
Fish - ժառանգում է WaterAnimal-ից և ունի swim() մեթոդ:
WaterAnimal-ն ունի live_in_water() մեթոդ:
LandAnimal-ն ունի live_on_land() մեթոդ։
Ձեր խնդիրն է ստեղծել Frog class, որը ժառանգում է ինչպես WaterAnimal-ից, այնպես էլ LandAnimal-ից: Այս class-ը պետք է կարողանա կանչել իր ծնող դասերի բոլոր մեթոդները:
Յուրաքանչյուր class պետք է ունենա species ատրիբուտ, որը պետք է նշվի օբյեկտի ստեղծման ժամանակ:
Կանչի ժամանակ բոլոր մեթոդները պետք է տպեն համապատասխան հաղորդագրություն, որը նշում է գործողության և տեսակների անվանումը (ըստ ստորև բերված օրինակի):