Բազմակի ժառանգում

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-ներում սահմանված ցանկացած ատրիբուտ կամ մեթոդ: Այսպիսով, selfA.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 ատրիբուտ, որը պետք է նշվի օբյեկտի ստեղծման ժամանակ:
Կանչի ժամանակ բոլոր մեթոդները պետք է տպեն համապատասխան հաղորդագրություն, որը նշում է գործողության և տեսակների անվանումը (ըստ ստորև բերված օրինակի):
Մուտք
Ելք
goldfish=Fish('Goldfish'); goldfish.swim(); goldfish.live_in_water(); frog=Frog('Frog'); frog.live_in_water(); frog.live_on_land();
The Goldfish is swimming. The Goldfish is living in the water. The Frog is living in the water. The Frog is living on land.
 

Constraints

Time limit: 2 seconds

Memory limit: 512 MB

Output limit: 1 MB

To check your solution you need to sign in
Sign in to continue