0%

🏗️ Objektorientētā programmēšana

OOP ļauj modelēt reālo pasauli ar objektiem – kastēm, kurās glabājas dati (atribūti) un uzvedība (metodes). Python OOP pamati: klases, mantojamība un speciālās metodes.

python

Klases un objekti

Teksts
# Klases definēšana
class Autos:
    # Klases atribūts (kopīgs visiem objektiem)
    kategōrija = "Transportlīdzeklis"

    # __init__ – konstruktors (izsauc, veidojot objektu)
    def __init__(self, marka, modelis, gads):
        # Objekta atribūti (katram objektam savi)
        self.marka = marka
        self.modelis = modelis
        self.gads = gads
        self._ātrums = 0   # Konvencija: _ = "privāts"

    # Metode
    def apraksts(self):
        return f"{self.gads}. g. {self.marka} {self.modelis}"

    def paātrināt(self, daudzums):
        self._ātrums += daudzums
        print(f"Ātrums: {self._ātrums} km/h")

    def bremzēt(self):
        self._ātrums = max(0, self._ātrums - 10)

# Objektu izveide
audi = Autos("Audi", "A4", 2022)
bmw  = Autos("BMW",  "X5", 2023)

print(audi.apraksts())    # 2022. g. Audi A4
print(bmw.marka)          # BMW

audi.paātrināt(50)        # Ātrums: 50 km/h
audi.paātrināt(30)        # Ātrums: 80 km/h

# Klases atribūts pieejams caur klasi vai objektu
print(Autos.kategōrija)   # Transportlīdzeklis
print(audi.kategōrija)    # Transportlīdzeklis

Mantojamība

Teksts
# Bāzes klase
class Dzīvnieks:
    def __init__(self, vārds, suga):
        self.vārds = vārds
        self.suga = suga

    def runāt(self):
        print(f"{self.vārds} runā")

    def __str__(self):
        return f"{self.suga}: {self.vārds}"

# Apakšklase
class Suns(Dzīvnieks):
    def __init__(self, vārds, šķirne):
        super().__init__(vārds, "Suns")  # Izsauc vecāku __init__
        self.šķirne = šķirne

    def runāt(self):     # Override
        print(f"{self.vārds} rej: Vau!")

    def nest(self, priekšmets):
        print(f"{self.vārds} nes {priekšmets}")

class Kaķis(Dzīvnieks):
    def runāt(self):
        print(f"{self.vārds} saka: Māu!")

# Izmantošana
suns = Suns("Reks", "Labradoru retrivers")
kaķis = Kaķis("Minca", "Persiešu kaķis")

suns.runāt()     # Reks rej: Vau!
kaķis.runāt()    # Minca saka: Māu!
suns.nest("bumbu")  # Reks nes bumbu

print(suns)      # Suns: Reks
print(isinstance(suns, Suns))       # True
print(isinstance(suns, Dzīvnieks))  # True – mantojamība!
print(issubclass(Suns, Dzīvnieks))  # True

@property, @classmethod, @staticmethod

Teksts
class Temparatūra:
    def __init__(self, celsius=0):
        self._celsius = celsius   # Privāts atribūts

    # @property – piekļuve kā atribūtam, bet ar loģiku
    @property
    def celsius(self):
        return self._celsius

    @celsius.setter
    def celsius(self, vērtība):
        if vērtība < -273.15:
            raise ValueError("Temp nevar būt zemāka par absolūto nulli!")
        self._celsius = vērtība

    @property
    def fahrenheit(self):
        return self._celsius * 9/5 + 32

    # @classmethod – alternatīvi konstruktori
    @classmethod
    def no_fahrenheit(cls, fahrenheit):
        celsius = (fahrenheit - 32) * 5/9
        return cls(celsius)

    # @staticmethod – utilīta, nav piesaistīta objektam
    @staticmethod
    def ir_auksts(celsius):
        return celsius < 10

# @property izmantošana
t = Temparatūra(25)
print(t.celsius)      # 25
print(t.fahrenheit)   # 77.0

t.celsius = 100
print(t.fahrenheit)   # 212.0

# t.celsius = -300    # ValueError!

# @classmethod
t_no_f = Temparatūra.no_fahrenheit(212)
print(t_no_f.celsius)   # 100.0

# @staticmethod
print(Temparatūra.ir_auksts(5))    # True
print(Temparatūra.ir_auksts(20))   # False

Speciālās metodes (Dunders)

Metodes ar dubultsīkstiniem __ ļauj objektiem "saprast" Python operatorus.

💡 Dataclasses – ātrāks veids

Python 3.7+ piedāvā @dataclass dekoratoru, kas automātiski ģenerē __init__, __repr__, __eq__.

Teksts
class Vektors:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f"Vektors({self.x}, {self.y})"

    def __repr__(self):
        return f"Vektors(x={self.x}, y={self.y})"

    def __len__(self):
        return 2   # 2-dimensiju vektors

    def __add__(self, cits):
        return Vektors(self.x + cits.x, self.y + cits.y)

    def __sub__(self, cits):
        return Vektors(self.x - cits.x, self.y - cits.y)

    def __mul__(self, skalārs):
        return Vektors(self.x * skalārs, self.y * skalārs)

    def __eq__(self, cits):
        return self.x == cits.x and self.y == cits.y

    def __abs__(self):
        return (self.x**2 + self.y**2) ** 0.5

v1 = Vektors(1, 2)
v2 = Vektors(3, 4)

print(v1)           # Vektors(1, 2)
print(repr(v1))     # Vektors(x=1, y=2)
print(len(v1))      # 2

print(v1 + v2)      # Vektors(4, 6)
print(v1 * 3)       # Vektors(3, 6)
print(abs(v2))      # 5.0
print(v1 == Vektors(1, 2))  # True

# Biežāk lietotie dunders:
# __init__    – konstruktors
# __str__     – cilvēkam lasāms teksts
# __repr__    – izstrādātājam paredzēts
# __len__     – len()
# __getitem__ – obj[indekss]
# __contains__ – in operators
# __iter__    – for cilpā
# __enter__/__exit__ – with blokā

from dataclasses import dataclass, field

@dataclass
class Persona:
    vārds: str
    vecums: int
    hobiji: list = field(default_factory=list)

    def prezentēt(self):
        return f"{self.vārds} ({self.vecums} g.)"

p = Persona("Anna", 25, ["lasīšana", "peldēšana"])
p2 = Persona("Anna", 25, ["lasīšana", "peldēšana"])

print(p)             # Persona(vārds="Anna", vecums=25, hobiji=["lasīšana", "peldēšana"])
print(p.prezentēt()) # Anna (25 g.)
print(p == p2)       # True – automātiski salīdzina laukus