Asosiy qismga o'tish

Meros, kompozitsiya va polimorfizm

17-bob 12 kod bloki 2099 so'z

Bu bobda

  • mavjud klassdan yangi klass yasashni — meros (inheritance)
  • super() nima qilishini
  • metodni qayta yozishni (override)
  • obyekt ichida boshqa obyektni saqlashni — kompozitsiya
  • har xil obyektlar bilan bir xil ishlashni — polimorfizm

Meros: "bu ham o'sha, faqat qo'shimchasi bor"

Elektromobil — bu ham mashina: markasi, modeli, yili, probegi bor. Faqat qo'shimcha xususiyati bor — batareya. Mashina klassini qaytadan yozmaymiz, undan meros olamiz.

Avval asosiy (ota) klass — 16-bobdagi Mashina:

python15 qator
class Mashina:
    def __init__(self, marka, model, yil):
        self.marka = marka
        self.model = model
        self.yil = yil
        self.probeg = 0

    def tavsif(self):
        return f"{self.yil} {self.marka} {self.model}".title()

    def probegni_oqi(self):
        print(f"Probeg: {self.probeg:,} km")

    def yoqilgi_quy(self):
        print("Bak to'ldirildi.")

Endi bola klass. Qavs ichida — ota klass nomi:

python10 qator
class Elektromobil(Mashina):
    def __init__(self, marka, model, yil):
        super().__init__(marka, model, yil)
        self.batareya_kvt = 75


tesla = Elektromobil("tesla", "model y", 2025)
print(tesla.tavsif())
tesla.probegni_oqi()
print(f"Batareya: {tesla.batareya_kvt} kVt·soat")
Natija
2025 Tesla Model Y
Probeg: 0 km
Batareya: 75 kVt·soat

Elektromobil da tavsif() va probegni_oqi() yozilmagan, lekin ishladi — ular otadan meros qoldi.

super().__init__(marka, model, yil) — "ota klassning konstruktorini chaqir". U marka, model, yil, probeg atributlarini o'rnatadi. Usiz bola klassda bu atributlar umuman bo'lmaydi:

super().__init__() ni unutish

python7 qator
class Elektromobil(Mashina):
    def __init__(self, marka, model, yil):
        self.batareya_kvt = 75


tesla = Elektromobil("tesla", "model y", 2025)
print(tesla.tavsif())
Xato xabari
AttributeError: 'Elektromobil' object has no attribute 'yil'

Bola klass o'zining __init__ ini yozdi va otanikini almashtirib qo'ydi. self.yil hech qachon o'rnatilmadi.

Metodni qayta yozish (override)

Elektromobilga benzin quyib bo'lmaydi. Ota metodini bola klassda xuddi shu nom bilan qayta yozamiz:

python11 qator
class Elektromobil(Mashina):
    def __init__(self, marka, model, yil):
        super().__init__(marka, model, yil)
        self.batareya_kvt = 75

    def yoqilgi_quy(self):
        print("Elektromobilga yoqilg'i kerak emas — quvvatlang!")


Mashina("chevrolet", "cobalt", 2024).yoqilgi_quy()
Elektromobil("byd", "song plus", 2025).yoqilgi_quy()
Natija
Bak to'ldirildi.
Elektromobilga yoqilg'i kerak emas — quvvatlang!

Python metodni avval obyektning o'z klassida qidiradi, topilmasa — otasida.

Ota metodini to'liq almashtirmasdan to'ldirish ham mumkin — ichida super() chaqiriladi:

python10 qator
class Elektromobil(Mashina):
    def __init__(self, marka, model, yil):
        super().__init__(marka, model, yil)
        self.batareya_kvt = 75

    def tavsif(self):
        return super().tavsif() + f" ({self.batareya_kvt} kVt·soat)"


print(Elektromobil("byd", "song plus", 2025).tavsif())
Natija
2025 Byd Song Plus (75 kVt·soat)

isinstance: bu qaysi klassdan?

python5 qator
cobalt = Mashina("chevrolet", "cobalt", 2024)
song = Elektromobil("byd", "song plus", 2025)
print(isinstance(song, Elektromobil))
print(isinstance(song, Mashina))
print(isinstance(cobalt, Elektromobil))
Natija
True
True
False

Elektromobil — bu ham mashina (True), lekin har qanday mashina elektromobil emas.

Kompozitsiya: obyekt ichida obyekt

Batareyaning o'zi ham murakkab narsa: hajmi bor, quvvat zahirasi bor, uni tavsiflash kerak. Bularni Elektromobil ga tiqib tashlash o'rniga, alohida Batareya klassini yozamiz va elektromobil ichida saqlaymiz. Bu kompozitsiya: "elektromobil batareyaga ega".

python36 qator
class Batareya:
    ZAHIRA_KM = {60: 400, 75: 470, 100: 600}

    def __init__(self, hajm=75):
        self.hajm = hajm

    def tavsif(self):
        print(f"Batareya: {self.hajm} kVt·soat")

    def zahira(self):
        km = self.ZAHIRA_KM.get(self.hajm)
        if km is None:
            print(f"{self.hajm} kVt·soat uchun ma'lumot yo'q")
        else:
            print(f"To'liq quvvat bilan taxminan {km} km yuradi")


class Elektromobil(Mashina):
    def __init__(self, marka, model, yil, hajm=75):
        super().__init__(marka, model, yil)
        self.batareya = Batareya(hajm)

    def yoqilgi_quy(self):
        print("Elektromobilga yoqilg'i kerak emas — quvvatlang!")


tesla = Elektromobil("tesla", "model y", 2025)
print(tesla.tavsif())
tesla.batareya.tavsif()
tesla.batareya.zahira()

katta = Elektromobil("tesla", "model s", 2025, hajm=100)
katta.batareya.zahira()

notanish = Elektromobil("zeekr", "001", 2025, hajm=90)
notanish.batareya.zahira()
Natija
2025 Tesla Model Y
Batareya: 75 kVt·soat
To'liq quvvat bilan taxminan 470 km yuradi
To'liq quvvat bilan taxminan 600 km yuradi
90 kVt·soat uchun ma'lumot yo'q

tesla.batareya.zahira() — "teslaning batareyasining zahira metodi". Nuqtalar zanjiri obyektlar ichiga kirib boradi.

Hamma holat hisobga olinmagan if-elif

Batareya zahirasini birinchi bo'lib bunday yozish oson:

python13 qator
class Batareya:
    def __init__(self, hajm=75):
        self.hajm = hajm

    def zahira(self):
        if self.hajm == 75:
            km = 470
        elif self.hajm == 100:
            km = 600
        print(f"Taxminan {km} km")


Batareya(90).zahira()
Xato xabari
UnboundLocalError: local variable 'km' referenced before assignment

90 uchun hech bir shart bajarilmadi, km yaratilmadi va xabar chiqarish yiqildi. Yuqoridagi yaxshi variantda bu hol lug'at va get() bilan aniq ko'rib chiqilgan. Yana bir maslahat: o'zgaruvchiga range, list, sum kabi Pythonning o'z nomlarini bermang — keyin o'sha funksiyalar ishlamay qoladi (1-bob).

Meros yoki kompozitsiya?

  • "X — bu Y" (elektromobil — bu mashina) → meros.
  • "X da Y bor" (elektromobilda batareya bor) → kompozitsiya.

Shubha bo'lsa, kompozitsiyani tanlang: u soddaroq va o'zgartirishga osonroq.

Polimorfizm: bir xil chaqiruv — har xil xatti-harakat

Har xil klassli obyektlarda bir xil nomli metod bo'lsa, ularni bir xil usulda ishlatish mumkin:

python34 qator
class Shakl:
    def yuza(self):
        return 0

    def nomi(self):
        return type(self).__name__


class Doira(Shakl):
    def __init__(self, r):
        self.r = r

    def yuza(self):
        return 3.141592653589793 * self.r ** 2


class Tortburchak(Shakl):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def yuza(self):
        return self.a * self.b


class Kvadrat(Tortburchak):
    def __init__(self, a):
        super().__init__(a, a)


shakllar = [Doira(1), Tortburchak(3, 4), Kvadrat(5)]
for s in shakllar:
    print(f"{s.nomi():<12}{s.yuza():>8.2f}")
print("Jami yuza:", round(sum(s.yuza() for s in shakllar), 2))
Natija
Doira           3.14
Tortburchak    12.00
Kvadrat        25.00
Jami yuza: 40.14

for sikli qaysi shakl kelayotganini bilmaydi va so'ramaydi — har biri yuza() ni o'zicha hisoblaydi. Yangi shakl qo'shsangiz (masalan, Uchburchak), siklni o'zgartirish shart emas. Bu polimorfizm ("ko'p shakllilik").

Kvadrat esa Tortburchak dan meros oldi va faqat konstruktorini soddalashtirdi: kvadrat — tomonlari teng to'rtburchak.

Kitoblarda

  • Python asoslari: sinflarda vorislik (meros) 106–112-betlar.
  • Python Crash Course: 9-bob, Inheritance 167–173-betlar (ElectricCar, super(), Overriding Methods, Instances as Attributes — Battery klassi).

Xulosa

  • class Bola(Ota): — meros; ota metodlari bolaga o'tadi.
  • Bola __init__ ida super().__init__(...) ni chaqiring.
  • Bir xil nomli metod yozish — override; super().metod() — otanikini to'ldirish.
  • "X — bu Y" → meros, "X da Y bor" → kompozitsiya (self.batareya = Batareya()).
  • Polimorfizm: har xil obyektlar, bir xil metod nomi, bitta sikl.

Mashqlar

17.1

Shakl klassidan meros oluvchi Doira(r), Tortburchak(a, b) va Uchburchak(a, h) (asos va balandlik) klasslarini yozing, har birida yuza(). Kiritish: birinchi qatorda shakllar soni N, keyin N qatorda doira 2, tortburchak 3 4 yoki uchburchak 6 2. Jami yuzani 2 xona bilan chiqaring. π = math.pi.

KirishKutilgan natija
3, doira 1, tortburchak 3 4, uchburchak 6 221.14
1, doira 212.57
Yechimni ko'rish
python38 qator
import math


class Shakl:
    def yuza(self):
        return 0


class Doira(Shakl):
    def __init__(self, r):
        self.r = r

    def yuza(self):
        return math.pi * self.r ** 2


class Tortburchak(Shakl):
    def __init__(self, a, b):
        self.a, self.b = a, b

    def yuza(self):
        return self.a * self.b


class Uchburchak(Shakl):
    def __init__(self, a, h):
        self.a, self.h = a, h

    def yuza(self):
        return self.a * self.h / 2


KLASSLAR = {"doira": Doira, "tortburchak": Tortburchak, "uchburchak": Uchburchak}
jami = 0
for _ in range(int(input())):
    nom, *sonlar = input().split()
    jami += KLASSLAR[nom](*[float(s) for s in sonlar]).yuza()
print(f"{jami:.2f}")
17.2

Xodim(ism, maosh) klassini va undan meros oluvchi Rahbar(ism, maosh, bonus) klassini yozing. Ikkalasida oylik() metodi: xodimniki — maosh, rahbarniki — maosh + bonus. Birinchi qatorda N, keyin N qatorda xodim Ali 5000000 yoki rahbar Vali 8000000 2000000. Jami oylik fondini chiqaring.

KirishKutilgan natija
3, xodim Ali 5000000, rahbar Vali 8000000 2000000, xodim Sarvinoz 600000021000000
1, rahbar A 100 50150
Yechimni ko'rish
python25 qator
class Xodim:
    def __init__(self, ism, maosh):
        self.ism = ism
        self.maosh = maosh

    def oylik(self):
        return self.maosh


class Rahbar(Xodim):
    def __init__(self, ism, maosh, bonus):
        super().__init__(ism, maosh)
        self.bonus = bonus

    def oylik(self):
        return super().oylik() + self.bonus


jami = 0
for _ in range(int(input())):
    tur, ism, *pul = input().split()
    pul = [int(p) for p in pul]
    xodim = Rahbar(ism, *pul) if tur == "rahbar" else Xodim(ism, *pul)
    jami += xodim.oylik()
print(jami)
17.3

Hayvon(ism) klassida ovoz() metodi ... qaytaradi. Undan meros oluvchi It (Vov), Mushuk (Miyov), Sigir (Muu) klasslarini yozing. Bitta qatorda tur:ism juftlari berilgan; har bir hayvon uchun Ism: ovoz ni alohida qatorda chiqaring. Noma'lum tur — oddiy Hayvon.

KirishKutilgan natija
it:Rex mushuk:Mosh sigir:MallaRex: Vov Mosh: Miyov Malla: Muu
ot:Bo'zBo'z: ...
Yechimni ko'rish
python28 qator
class Hayvon:
    def __init__(self, ism):
        self.ism = ism

    def ovoz(self):
        return "..."


class It(Hayvon):
    def ovoz(self):
        return "Vov"


class Mushuk(Hayvon):
    def ovoz(self):
        return "Miyov"


class Sigir(Hayvon):
    def ovoz(self):
        return "Muu"


TURLAR = {"it": It, "mushuk": Mushuk, "sigir": Sigir}
for juft in input().split():
    tur, ism = juft.split(":")
    h = TURLAR.get(tur, Hayvon)(ism)
    print(f"{h.ism}: {h.ovoz()}")

Bu bobni bepul o'qidingiz.

Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.

Telegramda yozish Narxlar