Obyekt va sinf nima?
Atrofingizga qarang: telefon, maşina, bank kartasi, televizor... Har bir narsaning xususiyatlari (rangi, markasi, balansi) va qila oladigan işlari (qönğiroq qiliş, yuriş, pul yeçiş) bor.
Obyektga yönaltirilgan dasturlaş (OOP) aynan şu ğoyaga asoslanadi: maʼlumot va u bilan işlaydigan funksiyalarni bitta "quti" içiga birlaştiramiz.
- Sinf (
class) — çizma yoki andoza. Masalan, "Avtomobil" çizmasi: uning markasi, rangi, tezligi böladi, u yura oladi. - Obyekt (
object,instance) — çizma asosida yasalgan aniq narsa: "oq rangliCobalt", "qoraMalibu".
Bitta sinfdan istalgança obyekt yaratiş mumkin, xuddi bitta çizma asosida köplab uy qurilgani kabi.
Aslida siz OOP bilan allaqaçon tanişsiz: Pythonda hamma narsa obyekt. "salom".upper() yozganingizda str sinfining obyektida upper metodini çaqirasiz.
ism = "dilnoza"
sonlar = [3, 1, 2]
print(type(ism), type(sonlar))
print(ism.capitalize()) # str sinfining metodi
sonlar.sort() # list sinfining metodi
print(sonlar)
Natija:
<class 'str'> <class 'list'>
Dilnoza
[1, 2, 3]
Birinçi sinf: class kalit sözi
Sinf class kalit sözi bilan eʼlon qilinadi. Sinf nomlari odatda KattaHarfBilan yoziladi (PascalCase uslubi).
class Mushuk:
pass
barsik = Mushuk()
mosh = Mushuk()
print(type(barsik))
print(barsik is mosh) # ikki xil obyekt
Natija:
<class '__main__.Mushuk'>
False
Mushuk() — sinfni xuddi funksiya kabi çaqiriş yangi obyekt yaratadi. Hozirça bu obyektlar böş. Keling, ularga maʼlumot beramiz.
__init__ va atributlar
__init__ — maxsus metod, u obyekt yaratilgan zahoti avtomatik çaqiriladi. Uning vazifasi — obyektning boşlanğiç holatini örnatiş. Birinçi parametr self — yaratilayotgan obyektning özi.
class Talaba:
def __init__(self, ism: str, kurs: int):
self.ism = ism # atribut
self.kurs = kurs
self.baholar = [] # har bir talabaning öz röyxati
aziz = Talaba("Aziz", 2)
malika = Talaba("Malika", 3)
aziz.baholar.append(90)
print(aziz.ism, aziz.kurs, aziz.baholar)
print(malika.ism, malika.kurs, malika.baholar)
Natija:
Aziz 2 [90]
Malika 3 []
self.ism = ism — bu "şu obyektning ism atributiga qiymat ber" degani. Har bir obyekt öz atributlarini alohida saqlaydi: Azizning baholari Malikaga taʼsir qilmaydi.
Sinf atributlari va obyekt atributlari
self. orqali beriladigan atributlar har bir obyektga tegişli. Sinf tanasida töğridan-töğri yozilgan atributlar esa barça obyektlar uçun umumiy.
class Talaba:
universitet = "Milliy universitet" # sinf atributi — hammaga umumiy
soni = 0
def __init__(self, ism):
self.ism = ism # obyekt atributi — har biriga alohida
Talaba.soni += 1
a = Talaba("Aziz")
b = Talaba("Bekzod")
print(a.universitet, "|", b.universitet)
print("Jami talabalar:", Talaba.soni)
Talaba.universitet = "Texnika universiteti"
print(a.universitet) # özgariş hammaga tegdi
Natija:
Milliy universitet | Milliy universitet
Jami talabalar: 2
Texnika universiteti
Metodlar
Metod — bu sinf içida yozilgan funksiya. U obyektning maʼlumotlari bilan işlaydi va birinçi parametr sifatida doim self ni oladi.
class Talaba:
def __init__(self, ism):
self.ism = ism
self.baholar = []
def baho_qosh(self, baho: int):
self.baholar.append(baho)
def ortacha(self) -> float:
if not self.baholar:
return 0.0
return sum(self.baholar) / len(self.baholar)
def tavsif(self) -> str:
return f"{self.ism}: {len(self.baholar)} ta baho, örtaça {self.ortacha():.1f}"
t = Talaba("Gulnora")
for b in [88, 95, 79]:
t.baho_qosh(b)
print(t.tavsif())
Natija:
Gulnora: 3 ta baho, örtaça 87.3
t.baho_qosh(88) yozganingizda Python uni aslida Talaba.baho_qosh(t, 88) deb çaqiradi — self örniga t ning özi uzatiladi.
Amaliyot: bank hisobi
Endi foydali sinf yozamiz. Hisob pul qöyiş va yeçişga ruxsat beradi, lekin balansdan köp pul yeçişga yöl qöymaydi.
class BankHisobi:
def __init__(self, egasi: str, balans: int = 0):
self.egasi = egasi
self.balans = balans
self.tarix = []
def qoyish(self, summa: int):
if summa <= 0:
raise ValueError("Summa musbat bölişi kerak")
self.balans += summa
self.tarix.append(f"+{summa}")
def yechish(self, summa: int):
if summa > self.balans:
raise ValueError(f"Mablağ yetarli emas (balans: {self.balans})")
self.balans -= summa
self.tarix.append(f"-{summa}")
hisob = BankHisobi("Sardor", 100_000)
hisob.qoyish(250_000)
hisob.yechish(80_000)
try:
hisob.yechish(1_000_000)
except ValueError as e:
print("Rad etildi:", e)
print(f"{hisob.egasi}ning balansi: {hisob.balans:,} söm")
print("Amallar tarixi:", hisob.tarix)
Natija:
Rad etildi: Mablağ yetarli emas (balans: 270000)
Sardorning balansi: 270,000 söm
Amallar tarixi: ['+250000', '-80000']
Sinf içidagi tekşiruvlar tufayli balans heç qaçon manfiy bölmaydi. Maʼlumot va qoidalarni bitta joyda saqlaş — inkapsulyatsiya deb ataladi va bu OOP ning asosiy foydalaridan biri.
Maxsus (dunder) metodlar
Nomi ikki pastki çiziq bilan boşlanib tugaydigan metodlar (__init__, __str__...) maxsus yoki dunder (double underscore) metodlar deyiladi. Python ularni maʼlum vaziyatlarda özi çaqiradi:
| Metod | Qaçon çaqiriladi |
|---|---|
__str__ | print(obj) va str(obj) — foydalanuvçi uçun çiroyli matn |
__repr__ | Konsolda va röyxat içida — dasturçi uçun aniq tavsif |
__len__ | len(obj) |
__eq__ | obj1 == obj2 |
__add__ | obj1 + obj2 |
__lt__ | obj1 < obj2 (va saralaş) |
class Savat:
def __init__(self, egasi):
self.egasi = egasi
self.mahsulotlar = {}
def qosh(self, nomi, narx):
self.mahsulotlar[nomi] = narx
def __len__(self):
return len(self.mahsulotlar)
def __str__(self):
jami = sum(self.mahsulotlar.values())
return f"{self.egasi}ning savati: {len(self)} ta mahsulot, jami {jami} söm"
def __repr__(self):
return f"Savat({self.egasi!r}, {self.mahsulotlar!r})"
s = Savat("Nilufar")
s.qosh("non", 4000)
s.qosh("qatiq", 9000)
print(s)
print(len(s))
print([s]) # röyxat içida __repr__ işlatiladi
Natija:
Nilufarning savati: 2 ta mahsulot, jami 13000 söm
2
[Savat('Nilufar', {'non': 4000, 'qatiq': 9000})]
__eq__ va __add__
Standart holatda == ikki obyekt bir xil obyekt ekanini tekşiradi. Agar qiymatlar böyiça soliştirmoqçi bölsangiz, __eq__ ni yozing. __add__ esa + belgisiga maʼno beradi.
class Pul:
def __init__(self, miqdor: int, valyuta: str = "UZS"):
self.miqdor = miqdor
self.valyuta = valyuta
def __add__(self, boshqa):
if self.valyuta != boshqa.valyuta:
raise ValueError("Turli valyutalarni qöşib bölmaydi")
return Pul(self.miqdor + boshqa.miqdor, self.valyuta)
def __eq__(self, boshqa):
return self.miqdor == boshqa.miqdor and self.valyuta == boshqa.valyuta
def __repr__(self):
return f"{self.miqdor:,} {self.valyuta}"
oylik = Pul(6_500_000)
bonus = Pul(1_500_000)
print(oylik + bonus)
print(Pul(100, "USD") == Pul(100, "USD"))
print(Pul(100, "USD") == Pul(100, "EUR"))
Natija:
8,000,000 UZS
True
False
Amaliyot: televizor pulti
Obyekt öz holatini eslab qoladi. Televizorni olaylik: u yoqilgan yoki öçirilgan, hozirgi kanal va ovoz balandligi bor. Pult tugmalari esa şu holatni özgartiradi.
class Televizor:
MAX_OVOZ = 100
def __init__(self, kanallar: list[str]):
self.kanallar = kanallar
self.yoqilgan = False
self.kanal = 0
self.ovoz = 20
def quvvat(self):
self.yoqilgan = not self.yoqilgan
print("📺 Yoqildi" if self.yoqilgan else "📺 Öçirildi")
def keyingi_kanal(self):
if self.yoqilgan:
self.kanal = (self.kanal + 1) % len(self.kanallar)
def ovoz_qosh(self, qadam: int = 10):
if self.yoqilgan:
self.ovoz = min(self.ovoz + qadam, self.MAX_OVOZ)
def __str__(self):
if not self.yoqilgan:
return "Televizor öçiq"
return f"Kanal: {self.kanallar[self.kanal]} | Ovoz: {self.ovoz}"
tv = Televizor(["Yangiliklar", "Sport", "Kino", "Bolalar"])
tv.keyingi_kanal() # öçiq paytda heç narsa bölmaydi
print(tv)
tv.quvvat()
for _ in range(5):
tv.keyingi_kanal() # 4 ta kanal: oxiridan keyin boşiga qaytadi
for _ in range(10):
tv.ovoz_qosh() # 100 dan oşmaydi
print(tv)
tv.quvvat()
Natija:
Televizor öçiq
📺 Yoqildi
Kanal: Sport | Ovoz: 100
📺 Öçirildi
Meros (inheritance)
Baʼzan bir sinf boşqasining "kengaytirilgan" körinişi böladi. Masalan, menejer ham xodim: uning ismi, maoşi bor, lekin qöşimça ravişda jamoasi bor. Hamma narsani qaytadan yoziş örniga, meros olamiz.
class Xodim:
def __init__(self, ism: str, maosh: int):
self.ism = ism
self.maosh = maosh
def tanishtir(self):
return f"Men {self.ism}, maoşim {self.maosh:,} söm"
def yillik_daromad(self):
return self.maosh * 12
class Menejer(Xodim): # Menejer — Xodim ning vorisi
pass
m = Menejer("Kamola", 12_000_000)
print(m.tanishtir()) # metod ota sinfdan keldi
print(isinstance(m, Xodim))
Natija:
Men Kamola, maoşim 12,000,000 söm
True
Menejer(Xodim) yozuvi "Menejer sinfi Xodim dan meros oladi" degani. Xodim — ota sinf (parent), Menejer — voris sinf (child).
Metodni qayta yoziş va super()
Voris sinf ota sinf metodini qayta yozişi (override) mumkin. Ota sinfning asl versiyasini çaqiriş uçun super() işlatiladi — bu takrorlanişdan saqlaydi.
class Xodim:
def __init__(self, ism: str, maosh: int):
self.ism = ism
self.maosh = maosh
def tanishtir(self):
return f"Men {self.ism}, maoşim {self.maosh:,} söm"
def yillik_daromad(self):
return self.maosh * 12
class Menejer(Xodim):
def __init__(self, ism: str, maosh: int, bonus_foiz: int):
super().__init__(ism, maosh) # ota sinf işini bajaradi
self.bonus_foiz = bonus_foiz
self.jamoa: list[Xodim] = []
def jamoaga_qosh(self, xodim: Xodim):
self.jamoa.append(xodim)
def tanishtir(self): # qayta yozilgan metod
asosiy = super().tanishtir()
return f"{asosiy}. Jamoamda {len(self.jamoa)} kişi bor"
def yillik_daromad(self):
return super().yillik_daromad() * (100 + self.bonus_foiz) // 100
ali = Xodim("Ali", 7_000_000)
vali = Xodim("Vali", 8_000_000)
kamola = Menejer("Kamola", 12_000_000, bonus_foiz=20)
kamola.jamoaga_qosh(ali)
kamola.jamoaga_qosh(vali)
for odam in [ali, vali, kamola]:
print(odam.tanishtir())
print(f" Yillik: {odam.yillik_daromad():,} söm")
Natija:
Men Ali, maoşim 7,000,000 söm
Yillik: 84,000,000 söm
Men Vali, maoşim 8,000,000 söm
Yillik: 96,000,000 söm
Men Kamola, maoşim 12,000,000 söm. Jamoamda 2 kişi bor
Yillik: 172,800,000 söm
Eʼtibor bering: for tsiklida biz tanishtir() ni bir xil çaqirdik, lekin Python har bir obyekt uçun öz sinfidagi versiyani tanladi. Bu polimorfizm deb ataladi.
@property — metodni atribut kabi işlatiş
Baʼzan atributga qiymat berişni nazorat qiliş kerak (masalan, harorat absolyut noldan past bölmasin) yoki qiymat boşqa atributlardan hisoblanadi. @property dekoratori metodni oddiy atribut kabi körsatadi.
class Harorat:
def __init__(self, selsiy: float):
self.selsiy = selsiy # bu yerda ham setter işlaydi
@property
def selsiy(self):
return self._selsiy
@selsiy.setter
def selsiy(self, qiymat):
if qiymat < -273.15:
raise ValueError("Absolyut noldan past harorat bölmaydi")
self._selsiy = qiymat
@property
def farengeyt(self): # faqat öqiş uçun, hisoblanadigan
return self.selsiy * 9 / 5 + 32
h = Harorat(36.6)
print(h.selsiy, "°C =", round(h.farengeyt, 1), "°F")
h.selsiy = 40 # qavssiz — xuddi atribut kabi
print(h.farengeyt)
try:
h.selsiy = -300
except ValueError as e:
print("Xato:", e)
Natija:
36.6 °C = 97.9 °F
104.0
Xato: Absolyut noldan past harorat bölmaydi
Nomning boşidagi pastki çiziq (_selsiy) — "bu içki atribut, taşqaridan bevosita özgartirmang" degan kelişuv.
@classmethod va @staticmethod
@classmethod— birinçi parametr sifatida obyektni emas, sinfning özini (cls) oladi. Köpinça obyekt yaratişning muqobil usullari uçun işlatiladi.@staticmethod— na obyektni, na sinfni oladi. Bu şunçaki sinf içiga mantiqan joylaştirilgan oddiy funksiya.
class Sana:
def __init__(self, kun: int, oy: int, yil: int):
self.kun, self.oy, self.yil = kun, oy, yil
@classmethod
def matndan(cls, matn: str):
kun, oy, yil = map(int, matn.split("."))
return cls(kun, oy, yil)
@staticmethod
def kabisa(yil: int) -> bool:
return yil % 4 == 0 and (yil % 100 != 0 or yil % 400 == 0)
def __str__(self):
return f"{self.yil}-{self.oy:02}-{self.kun:02}"
navruz = Sana.matndan("21.03.2024")
print(navruz)
print("2024 kabisa yilimi?", Sana.kabisa(2024))
print("1900 kabisa yilimi?", Sana.kabisa(1900))
Natija:
2024-03-21
2024 kabisa yilimi? True
1900 kabisa yilimi? False
dataclass — kamroq kod, köproq foyda
Köp sinflar asosan maʼlumot saqlaş uçun yoziladi. Ular uçun har safar __init__, __repr__, __eq__ yoziş zerikarli. dataclasses moduli bu metodlarni avtomatik yaratadi — siz faqat maydonlar va ularning turlarini körsatasiz.
from dataclasses import dataclass, field
@dataclass
class Kitob:
nomi: str
muallif: str
narx: int
teglar: list[str] = field(default_factory=list)
def chegirma(self, foiz: int) -> int:
return self.narx * (100 - foiz) // 100
k1 = Kitob("Ufq", "Said Ahmad", 92_000, ["roman"])
k2 = Kitob("Ufq", "Said Ahmad", 92_000, ["roman"])
print(k1) # __repr__ avtomatik
print(k1 == k2) # __eq__ avtomatik
print("Çegirma bilan:", k1.chegirma(15))
Natija:
Kitob(nomi='Ufq', muallif='Said Ahmad', narx=92000, teglar=['roman'])
True
Çegirma bilan: 78200
field(default_factory=list) — har bir obyekt uçun yangi böş röyxat yaratadi. Oddiy teglar: list = [] yoziş xato, çunki röyxat barça obyektlar orasida umumiy bölib qolardi.
Xulosa
- Sinf — andoza, obyekt — şu andoza asosida yaratilgan aniq nusxa;
classbilan eʼlon qilinadi. __init__obyektning boşlanğiç holatini örnatadi;self— joriy obyekt.- Obyekt atributlari har bir nusxaga alohida, sinf atributlari esa hammaga umumiy.
- Maxsus metodlar (
__str__,__repr__,__len__,__eq__,__add__) obyektingizni Pythonning öz turlari kabi işlatişga imkon beradi. - Meros kodni qayta işlatadi;
super()ota sinf metodini çaqiradi, qayta yozilgan metodlar polimorfizmni taʼminlaydi. @propertyatributni nazorat qiladi,@classmethod/@staticmethodsinf darajasidagi metodlar uçun,@dataclassesa maʼlumot sinflarini qisqa yoziş uçun.
Maşqlar
- Törtburçakni ifodalovçi
Turtburchaksinfini yozing:enivaboyiatributlari,yuza()vaperimetr()metodlari hamda__str__bölsin.3 x 5uçun sinab köring.
Yeçim
class Turtburchak:
def __init__(self, eni: float, boyi: float):
self.eni = eni
self.boyi = boyi
def yuza(self):
return self.eni * self.boyi
def perimetr(self):
return 2 * (self.eni + self.boyi)
def __str__(self):
return f"Törtburçak {self.eni}x{self.boyi}"
t = Turtburchak(3, 5)
print(t, "| yuza:", t.yuza(), "| perimetr:", t.perimetr())
BankHisobisinfigaotkazma(boshqa_hisob, summa)metodini qöşing: u bu hisobdan pul yeçib, boşqa hisobga qöyadi. Ikki hisob orasida 50 000 söm ötkazib, balanslarni çiqaring.
Yeçim
class BankHisobi:
def __init__(self, egasi, balans=0):
self.egasi = egasi
self.balans = balans
def qoyish(self, summa):
self.balans += summa
def yechish(self, summa):
if summa > self.balans:
raise ValueError("Mablağ yetarli emas")
self.balans -= summa
def otkazma(self, boshqa, summa):
self.yechish(summa)
boshqa.qoyish(summa)
a = BankHisobi("Anvar", 200_000)
b = BankHisobi("Barno", 30_000)
a.otkazma(b, 50_000)
print(a.egasi, a.balans, "|", b.egasi, b.balans)
Vaqtsinfini yozing (soat,daqiqa).__add__ikki vaqtni qöşsin (daqiqa 60 dan oşsa soatga ötsin),__str__esa"02:05"körinişida çiqarsin.1:45 + 2:30ni hisoblang.
Yeçim
class Vaqt:
def __init__(self, soat: int, daqiqa: int):
jami = soat * 60 + daqiqa
self.soat, self.daqiqa = divmod(jami, 60)
def __add__(self, boshqa):
return Vaqt(self.soat + boshqa.soat, self.daqiqa + boshqa.daqiqa)
def __str__(self):
return f"{self.soat:02}:{self.daqiqa:02}"
print(Vaqt(1, 45) + Vaqt(2, 30))
Hayvonota sinfini (ism,ovoz()metodi"..."qaytaradi) va undan meros oluvçiIthamdaMushuksinflarini yozing. Har biriovoz()ni qayta yozsin. Röyxatdagi hayvonlarni aylanib, har birining ovozini çiqaring.
Yeçim
class Hayvon:
def __init__(self, ism):
self.ism = ism
def ovoz(self):
return "..."
class It(Hayvon):
def ovoz(self):
return "Vov-vov!"
class Mushuk(Hayvon):
def ovoz(self):
return "Miyov!"
for h in [It("Böribosar"), Mushuk("Momiq"), Hayvon("Baliq")]:
print(f"{h.ism}: {h.ovoz()}")
@dataclassyordamidaMahsulot(nomi,narx,soni) sinfini yarating vajamidegan@propertyqöşing (narx * soni). Bir neçta mahsulotnijamiböyiça kamayiş tartibida saralab çiqaring.
Yeçim
from dataclasses import dataclass
@dataclass
class Mahsulot:
nomi: str
narx: int
soni: int
@property
def jami(self) -> int:
return self.narx * self.soni
ombor = [Mahsulot("guruç", 18_000, 10), Mahsulot("yoğ", 25_000, 3), Mahsulot("çoy", 30_000, 7)]
for m in sorted(ombor, key=lambda m: m.jami, reverse=True):
print(f"{m.nomi:<8} {m.jami:>8}")