Python-ում բազմակի ժառանգությունը գործիք է, որտեղ կլասը կարող է ժառանգել ատրիբուտներ և մեթոդներ մեկից ավելի ծնող կլասերից: Այն թույլ է տալիս ստեղծել կլաս, որը միավորում է վարքագծերը կամ ատրիբուտները բազմաթիվ այլ կլասերից, ինչը կարող են բավականին հզոր բան լինել: Այնուամենայնիվ, իշխանության հետ գալիս է բարդությունը, և բազմակի ժառանգությունը պետք է խելամիտ օգտագործվի:
Բազմակի ժառանգությունը հասկանալու համար եկեք դիտարկենք մուլտիմեդիա ֆայլային համակարգի օրինակ: Ենթադրենք՝ ունենք Video և Audio կլաս: Այժմ մենք ցանկանում ենք կլաս ստեղծել մուլտիմեդիա ֆայլերի համար, որոնք ունեն և՛ վիդեո, և՛ աուդիո: Մենք կարող ենք հասնել դրան՝ օգտագործելով բազմակի ժառանգությունը.
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 կլասը ժառանգում է և՛ Video, և՛ Audio կլասերից: Մենք կանչում ենք Video և Audio կլասերի կոնստրուկտորներին Multimedia-ի կոնստրուկտորում՝ Multimedia օբյեկտի բոլոր ատրիբուտները պատշաճ կերպով սկզբնավորելու համար: Multimedia կլասի play() մեթոդը համատեղում է play_video() մեթոդը Video-ից և play_audio() մեթոդը Audio-ից:
Բազմակի ժառանգությունը հնարավորություն է տալիս համատեղել բազմաթիվ կլասերի վարքագիծը: Այնուամենայնիվ, այն պետք է զգույշ օգտագործվի, քանի որ դա կարող է հանգեցնել որոշ բարդությունների:
🤔
Եթե ծնող կլասերն ունեն նույն անուններով մեթոդներ, ժառանգության կարգը կարևոր է, քանի որ Python-ը մեթոդներ կփնտրի ենթակլասերի սահմանման մեջ նշված ծնող կլասերի հերթականությամբ:
Սա հայտնի է որպես Method Resolution Order (MRO):
Method Resolution Order
Python-ը օգտագործում է մի ալգորիթմ, որը կոչվում է C3 linearization, կամ պարզապես C3, որոշելու մեթոդի կարգը, երբ կլասերը ժառանգում են բազմաթիվ ծնողներից: Գաղափարն այն է, որ պահպանվի ենթակլասերում հայտարարման կարգը, միաժամանակ պահպանելով ծնող կլասերի կարգը: Այնուամենայնիվ, առանց ալգորիթմի բարդությունների մեջ մտնելու, կարող եք հեշտությամբ ստուգել MRO-ն կլասի համար՝ օգտագործելով 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 կլասի MRO-ն D -> B -> C -> A -> object է: Սա նշանակում է, որ երբ դուք կանչում եք մեթոդ D-ի օբյեկտի վրա, Python-ը նախ նայում է D-ի մեթոդին: Եթե այն այնտեղ չի գտնում, այն անցնում է B, այնուհետև C, իսկ հետո A:
Եթե ցանկանում եք զանգահարել կանչել ծնող կլասի մեթոդ, կարող եք ուղղակիորեն կանչել այն՝ օգտագործելով ծնող կլասի անունը: Այնուամենայնիվ, դա սովորաբար խորհուրդ չի տրվում, քանի որ դա կարող է հանգեցնել կոդի, որի հետ դժվար է աշխատել:
Եկեք փոփոխենք D կլասը՝ A կլասի 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 կլասը ժառանգում է B-ից և C-ից (երկուսն էլ ունեն process մեթոդ), մենք հատուկ կանչում ենք process մեթոդ-ը A կլասից: Սա երաշխավորում է, որ անկախ նրանից, թե ինչ է MRO-ն, A կլասի process մեթոդն օգտագործվում է: .
Ուշադրություն դարձրեք, թե ինչպես է self-ը բացահայտորեն փոխանցվում որպես արգումենտ: Python-ում self-ը հղում է կլասի ընթացիկ օբյեկտին և օգտագործվում է այդ օբյեկտի հետ կապված փոփոխականներին և մեթոդներին հասանելիություն ստանալու համար։ Այն անուղղակիորեն փոխանցվում է որպես օբյեկտների մեթոդների առաջին արգումենտ: Երբ մենք կանչում ենք A.process(self), մենք ասում ենք «Կանչել A կլասի process մեթոդը այս կոնկրետ օբյեկտի վրա (ներկայացված է self-ով)»: Թեև մեթոդը սահմանված է A-ում, այն իրականացվում է D կլասի օբյեկտի համատեքստում: Սա նշանակում է, որ նրան հասանելի են D կլասում կամ դրա մայր կլասերում սահմանված ցանկացած ատրիբուտի կամ մեթոդ: Մի խոսքով, self-ը A.process-ում թույլ է տալիս մեզ կանչել process մեթոդը A-ից D-ի օբյեկտի վրա:
Բազմակի ժառանգությունը կարող է հզոր գործիք լինել ձեր Python ծրագրերում բազմակողմանի և բազմակի օգտագործման կլասեր ստեղծելու համար:
Առաջադրանք:
Ծրագրավորման կախարդական աշխարհում կան կենդանիների մի քանի կլասեր՝ Fish, WaterAnimal, և LandAnimal.
Fish, որը ժառանգում է WaterAnimal-ից և ունի swim() մեթոդ:
WaterAnimal ունի live_in_water() մեթոդ:
LandAnimal ունի live_on_land() մեթոդ.
Ձեր խնդիրն է ստեղծել Frog կլաս, որը ժառանգում է ինչպես WaterAnimal-ից, այնպես էլ LandAnimal-ից: Այս կլասը պետք է կարողանա կանչել իր ծնող դասերի բոլոր մեթոդները:
Յուրաքանչյուր կլաս պետք է ունենա species ատրիբուտ, որը պետք է նշվի օբյեկտի ստեղծման ժամանակ:
Բոլոր մեթոդները, երբ կանչվում են, պետք է տպեն համապատասխան հաղորդագրություն, որը նշում է գործողության և տեսակների անվանումը (տես ձևաչափի համար ստորև բերված օրինակը):