Meros, kompozitsiya va polimorfizm
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:
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:
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")
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
class Elektromobil(Mashina): def __init__(self, marka, model, yil): self.batareya_kvt = 75 tesla = Elektromobil("tesla", "model y", 2025) print(tesla.tavsif())
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:
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()
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:
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())
2025 Byd Song Plus (75 kVt·soat)
isinstance: bu qaysi klassdan?
cobalt = Mashina("chevrolet", "cobalt", 2024) song = Elektromobil("byd", "song plus", 2025) print(isinstance(song, Elektromobil)) print(isinstance(song, Mashina)) print(isinstance(cobalt, Elektromobil))
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".
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()
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:
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()
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:
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))
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 —Batteryklassi).
Xulosa
class Bola(Ota):— meros; ota metodlari bolaga o'tadi.- Bola
__init__idasuper().__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
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.
| Kirish | Kutilgan natija |
|---|---|
| 3, doira 1, tortburchak 3 4, uchburchak 6 2 | 21.14 |
| 1, doira 2 | 12.57 |
Yechimni ko'rish
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}")
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.
| Kirish | Kutilgan natija |
|---|---|
| 3, xodim Ali 5000000, rahbar Vali 8000000 2000000, xodim Sarvinoz 6000000 | 21000000 |
| 1, rahbar A 100 50 | 150 |
Yechimni ko'rish
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)
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.
| Kirish | Kutilgan natija |
|---|---|
| it:Rex mushuk:Mosh sigir:Malla | Rex: Vov Mosh: Miyov Malla: Muu |
| ot:Bo'z | Bo'z: ... |
Yechimni ko'rish
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.