ebSkola

11.5 Polimorfisms un dunder metodes

Stundas uzdevums: Izprast polimorfismu un Python speciālās ("dunder") metodes objektu pielāgošanai.

SR 2.4.18. Lieto OOP pamatus SR 2.4.11. Standartizētas bibliotēkas un API

70 min plāns: Teorija un paraugs (~10 min) · 1. uzdevums (~15 min) - pārraksti vienu metodi vairākās klasēs · 2. uzdevums (~25 min) - izsauc tās vienā ciklā · 3. uzdevums (~20 min) - pievieno __str__ un __repr__. Papildu uzdevumu sāc tikai tad, ja pārējie trīs ir gatavi.

Pirms sāc: atver savas 11.4 stundas klases Dalibnieks, Kapteinis un Prezentetajs.

Teorija: Polimorfisms un dunder (__metode__)

Polimorfisms = daudzas formas. Dažādas klases ar to pašu metodes nosaukumu, bet atšķirīgu uzvedību.

class Dalibnieks:
    def runa(self): print("Dalibnieks runā vispārīgi.")

class Prezentetajs(Dalibnieks):
    def runa(self): print("Slaids ir gatavs, un neviens nepaniko!")

class Kapteinis(Dalibnieks):
    def runa(self): print("Komanda gatava, marķieris atrasts!")

# Polimorfisms - vienots interfeiss, dažāda uzvedība
for v in [Dalibnieks(), Prezentetajs(), Kapteinis()]:
    v.runa()

Dunder metodes (double underscore) ir iebūvētie āķi, kas ļauj klasei darboties ar Python operatoriem un funkcijām:

MetodeAktivizē
__str__str(o) un print(o)
__repr__repr(o), REPL izvade
__eq__o1 == o2
__lt__, __gt__<, > (sortēšana)
__add__o1 + o2
__len__len(o)
__contains__x in o

Praktiskie uzdevumi

1. uzdevums -

Pārraksti vienu metodi vairākās klasēs

Beigās vienam metodes nosaukumam būs trīs dažādas uzvedības.

  1. Pievieno klasei Dalibnieks metodi def runa(self): ar vispārīgu tekstu.
  2. Pievieno klasei Kapteinis tādu pašu metodi ar citu tekstu.
  3. Pievieno klasei Prezentetajs vēl vienu variantu.
  4. Izveido pa vienam objektam no katras klases.
  5. Izsauc katram runa() atsevišķi.
  6. Pieraksti, kura klase noteica, kurš teksts izdrukājās.

Gatavs, kad: viens metodes nosaukums dod trīs dažādas izvades atkarībā no objekta klases.

2. uzdevums -

Izsauc tās vienā ciklā

Beigās viens cikls apkalpos jebkuru lomu skaitu.

  1. Izveido sarakstu ar visiem trim objektiem.
  2. Uzraksti ciklu for d in dalibnieki:.
  3. Izsauc ciklā d.runa().
  4. Palaid un pārbaudi, ka izdrukājas trīs dažādi teksti.
  5. Pievieno sarakstam vēl vienu jaunu lomu.
  6. Palaid vēlreiz un pārbaudi, vai cikls bija jāmaina.
  7. Pieraksti vienu secinājumu: kāpēc te nevajag if pēc klases nosaukuma.

Gatavs, kad: pievienojot ceturto lomu, cikls strādā bez izmaiņām.

3. uzdevums -

Pievieno __str__ un __repr__

Beigās objekts pats zinās, kā izskatīties izdrukā.

  1. Izdrukā objektu bez papildu metodēm un pieraksti rezultātu.
  2. Pievieno klasei def __str__(self):, kas atgriež vārdu un enerģiju.
  3. Izdrukā objektu vēlreiz un salīdzini.
  4. Pievieno def __repr__(self): ar tehnisku pierakstu.
  5. Izdrukā sarakstu ar objektiem un pieraksti, kura metode nostrādāja.
  6. Pieraksti, kur lieto __str__ un kur __repr__.
  7. Pārbaudi, ka print(objekts) un print([objekts]) dod dažādu rezultātu.

Gatavs, kad: atsevišķi izdrukāts objekts rāda __str__, bet sarakstā - __repr__.

Papildu uzdevums - Pievieno salīdzināšanu

Ja pamatdarbs ir gatavs, ļauj kārtot dalībniekus pēc enerģijas.

  1. Pievieno klasei def __lt__(self, cits):.
  2. Atgriez tajā return self.energija < cits.energija.
  3. Izsauc sorted(dalibnieki).
  4. Izdrukā sakārtoto sarakstu.
  5. Pieraksti, kāpēc bez __lt__ kārtošana neizdevās.

Gatavs, kad: sorted() sakārto dalībniekus pēc enerģijas, nevis met TypeError.

Biežākās kļūdas

  • __str__ atgriež ne-string: Vienmēr atgriež str, citādi TypeError.
  • __eq__ bez __hash__: Ja klase salīdzināma, bet maināma - definē __hash__ = None.
  • Aizmirsts atgriezt vērtību: __lt__, __eq__ - vienmēr return True/False.

Koda piemērs

class Dalibnieks:
    def __init__(self, vards, energija): self.vards = vards; self.energija = energija
    def __str__(self): return f"{self.vards} ({self.energija} enerģija)"
    def __repr__(self): return f"Dalibnieks({self.vards!r}, energija={self.energija})"
    def __lt__(self, other): return self.energija < other.energija
    def __eq__(self, other): return self.energija == other.energija

dalibnieki = [Dalibnieks("Anna", 100), Dalibnieks("Jānis", 80), Dalibnieks("Eva", 120)]
for v in sorted(dalibnieki):
    print(v)
Jānis (80 enerģija)
Anna (100 enerģija)
Eva (120 enerģija)