15-bo‘lim

OOP asoslari - klass va obyekt

Obyektga yo'naltirilgan dasturlashga kirish: klass yaratish, __init__ konstruktori, atributlar, metodlar va self nima ekanligi.

🕑 9 daqiqa o‘qish 📄 467 so‘z 👁 6 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Muammo: ma'lumot tarqoq
  2. Klass va obyekt
  3. Birinchi klass
  4. __init__ va self
  5. Metodlar
  6. Klass atributlari
  7. Maxsus metodlar (dunder)
  8. @property - hisoblanadigan atribut
  9. Amaliy misol: bank hisobi
  10. Xulosa

Shu paytgacha biz ma'lumot va uni qayta ishlaydigan funksiyalarni alohida saqladik. Obyektga yo'naltirilgan dasturlash (OOP) ularni bitta joyga birlashtiradi.

Muammo: ma'lumot tarqoq #

Python
# Uchta talaba - oltita o'zgaruvchi
talaba1_ism = "Husanboy"
talaba1_baholar = [85, 92]
talaba2_ism = "Sardor"
talaba2_baholar = [78, 80]

def ortacha(baholar):
    return sum(baholar) / len(baholar)

print(f"{talaba1_ism}: {ortacha(talaba1_baholar)}")

Talabalar soni oshgani sari bu yondashuv chidab bo'lmas holga keladi. Yechim - klass yaratish.

Klass va obyekt #

KLASS (chizma) class Talaba: ism baholar ortacha() hisobot() yaratish OBYEKT 1 ism = "Husanboy" baholar = [85, 92] OBYEKT 2 ism = "Sardor" baholar = [78, 80] Har bir obyekt o'z ma'lumotiga ega, lekin metodlar umumiy
Klass - bu chizma, obyekt - shu chizma bo'yicha qurilgan bino
Hayotiy o'xshatish

Klass - uy loyihasi (chizma). Unda xonalar soni, eshiklar joyi ko'rsatilgan. Obyekt - shu loyiha bo'yicha qurilgan aniq uy. Bitta loyihadan yuzta uy qurish mumkin va har birining o'z rangi, egasi bo'ladi.

Birinchi klass #

Python
class Talaba:
    """Talaba haqidagi ma'lumotni saqlaydigan klass."""

    def __init__(self, ism, yosh, shahar):
        """Yangi talaba obyektini yaratadi."""
        self.ism = ism
        self.yosh = yosh
        self.shahar = shahar
        self.baholar = []


# Obyekt yaratish
birinchi = Talaba("Husanboy Qodirov", 25, "Namangan")
ikkinchi = Talaba("Sardor Aliyev", 25, "Toshkent")

print(birinchi.ism)
print(ikkinchi.shahar)
print(birinchi.baholar)
Natija
Husanboy Qodirov
Toshkent
[]

__init__ va self #

ElementMa'nosi
class Talaba:Yangi klass e'lon qilinadi (PascalCase)
__init__Konstruktor - obyekt yaratilganda avtomatik chaqiriladi
selfYaratilayotgan obyektning o'ziga havola
self.ism = ismObyektga atribut biriktiriladi
self nima?

self - bu "shu obyektning o'zi". Python uni avtomatik uzatadi:

Python
birinchi.baholar          # aslida Talaba.baholar(birinchi) kabi ishlaydi

Har bir metodning birinchi parametri self bo'lishi kerak. Uni yozishni unutish - eng ko'p uchraydigan xatolardan biri.

Metodlar #

Metod - klass ichidagi funksiya.

Python
class Talaba:
    """Talaba ma'lumotlari va baholari bilan ishlaydi."""

    def __init__(self, ism, yosh, shahar):
        self.ism = ism
        self.yosh = yosh
        self.shahar = shahar
        self.baholar = []

    def baho_qosh(self, baho):
        """Yangi baho qo'shadi."""
        if 0 <= baho <= 100:
            self.baholar.append(baho)
        else:
            raise ValueError("Baho 0 va 100 orasida bo'lishi kerak")

    def ortacha(self):
        """O'rtacha bahoni qaytaradi."""
        if not self.baholar:
            return 0.0
        return sum(self.baholar) / len(self.baholar)

    def harfli_baho(self):
        """O'rtachani harfli bahoga aylantiradi."""
        ball = self.ortacha()
        if ball >= 90:
            return "A"
        if ball >= 80:
            return "B"
        if ball >= 70:
            return "C"
        return "F"

    def hisobot(self):
        """Talaba haqida qisqacha hisobot chiqaradi."""
        print(f"{self.ism} ({self.yosh} yosh, {self.shahar})")
        print(f"  Baholar:  {self.baholar}")
        print(f"  O'rtacha: {self.ortacha():.1f}")
        print(f"  Baho:     {self.harfli_baho()}")


talaba = Talaba("Husanboy Qodirov", 25, "Namangan")
talaba.baho_qosh(85)
talaba.baho_qosh(92)
talaba.baho_qosh(78)
talaba.hisobot()
Natija
Husanboy Qodirov (25 yosh, Namangan)
  Baholar:  [85, 92, 78]
  O'rtacha: 85.0
  Baho:     B

Klass atributlari #

Obyekt atributi har bir obyektga xos, klass atributi esa hammaga umumiy:

Python
class Talaba:
    # Klass atributi - barcha obyektlar uchun bitta
    universitet = "Toshkent Axborot Texnologiyalari Universiteti"
    talabalar_soni = 0

    def __init__(self, ism):
        self.ism = ism                  # obyekt atributi
        Talaba.talabalar_soni += 1


birinchi = Talaba("Husanboy")
ikkinchi = Talaba("Sardor")
uchinchi = Talaba("Malika")

print(birinchi.universitet)
print(ikkinchi.universitet)
print(f"Jami talabalar: {Talaba.talabalar_soni}")
Natija
Toshkent Axborot Texnologiyalari Universiteti
Toshkent Axborot Texnologiyalari Universiteti
Jami talabalar: 3

Maxsus metodlar (dunder) #

Ikki tomondan pastki chiziq bilan yoziladigan metodlar Python'ga obyekt bilan qanday ishlashni o'rgatadi.

Python
class Mahsulot:
    def __init__(self, nomi, narxi, soni=1):
        self.nomi = nomi
        self.narxi = narxi
        self.soni = soni

    def __str__(self):
        """print() chaqirilganda ko'rinadigan matn."""
        return f"{self.nomi} x{self.soni} - {self.narxi * self.soni:,} so'm"

    def __repr__(self):
        """Nosozlikni tuzatishda ko'rinadigan matn."""
        return f"Mahsulot('{self.nomi}', {self.narxi}, {self.soni})"

    def __len__(self):
        """len() chaqirilganda."""
        return self.soni

    def __eq__(self, boshqa):
        """== operatori uchun."""
        return self.nomi == boshqa.nomi and self.narxi == boshqa.narxi

    def __lt__(self, boshqa):
        """< operatori uchun (saralashda kerak)."""
        return self.narxi < boshqa.narxi


klaviatura = Mahsulot("Klaviatura", 185_000, 2)
sichqoncha = Mahsulot("Sichqoncha", 95_000)

print(klaviatura)                 # __str__
print(repr(sichqoncha))           # __repr__
print(len(klaviatura))            # __len__
print(klaviatura == sichqoncha)   # __eq__
print(sichqoncha < klaviatura)    # __lt__

savat = [klaviatura, sichqoncha, Mahsulot("Monitor", 2_450_000)]
for mahsulot in sorted(savat):
    print(" ", mahsulot)
Natija
Klaviatura x2 - 370,000 so'm
Mahsulot('Sichqoncha', 95000, 1)
2
False
True
  Sichqoncha x1 - 95,000 so'm
  Klaviatura x2 - 370,000 so'm
  Monitor x1 - 2,450,000 so'm
MetodQachon chaqiriladi
__init__Obyekt yaratilganda
__str__print(obyekt), str(obyekt)
__repr__REPL'da, repr(obyekt)
__len__len(obyekt)
__eq__obyekt1 == obyekt2
__lt__, __gt__<, > va saralash
__add__obyekt1 + obyekt2
__contains__x in obyekt
__getitem__obyekt[i]
__str__ ni har doim yozing

__str__ bo'lmasa print(obyekt) shunday narsa chiqaradi: <__main__.Mahsulot object at 0x000001F8A2B3C4D0> - bu hech kimga foyda bermaydi.

@property - hisoblanadigan atribut #

Python
class Aylana:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        """Radiusni qaytaradi."""
        return self._radius

    @radius.setter
    def radius(self, qiymat):
        """Radiusni tekshirib o'rnatadi."""
        if qiymat <= 0:
            raise ValueError("Radius musbat bo'lishi kerak")
        self._radius = qiymat

    @property
    def yuza(self):
        """Yuzani hisoblab qaytaradi (metod emas, atribut kabi ishlatiladi)."""
        return 3.14159 * self._radius ** 2

    @property
    def uzunlik(self):
        return 2 * 3.14159 * self._radius


aylana = Aylana(5)
print(f"Radius:  {aylana.radius}")
print(f"Yuza:    {aylana.yuza:.2f}")        # qavssiz!
print(f"Uzunlik: {aylana.uzunlik:.2f}")

aylana.radius = 10
print(f"Yangi yuza: {aylana.yuza:.2f}")

try:
    aylana.radius = -3
except ValueError as xato:
    print(f"Xato: {xato}")
Natija
Radius:  5
Yuza:    78.54
Uzunlik: 31.42
Yangi yuza: 314.16
Xato: Radius musbat bo'lishi kerak

Amaliy misol: bank hisobi #

Python
# ============================================
# Bank hisobi klassi
# ============================================

from datetime import datetime


class BankHisobi:
    """Oddiy bank hisobi: to'ldirish, yechish va tarix."""

    bank_nomi = "Softromeda Bank"
    minimal_qoldiq = 10_000

    def __init__(self, egasi, boshlangich_balans=0):
        self.egasi = egasi
        self._balans = boshlangich_balans
        self.tarix = []
        self.ochilgan_sana = datetime.now()

    @property
    def balans(self):
        """Balansni faqat o'qish uchun ochamiz."""
        return self._balans

    def toldirish(self, summa):
        if summa <= 0:
            raise ValueError("Summa musbat bo'lishi kerak")
        self._balans += summa
        self._qayd("To'ldirish", summa)
        return self._balans

    def yechish(self, summa):
        if summa <= 0:
            raise ValueError("Summa musbat bo'lishi kerak")
        if self._balans - summa < self.minimal_qoldiq:
            raise ValueError(
                f"Mablag' yetarli emas. Minimal qoldiq: {self.minimal_qoldiq:,} so'm"
            )
        self._balans -= summa
        self._qayd("Yechish", summa)
        return self._balans

    def _qayd(self, turi, summa):
        """Ichki metod - amalni tarixga yozadi."""
        self.tarix.append({
            "turi": turi,
            "summa": summa,
            "balans": self._balans,
            "vaqt": datetime.now().strftime("%H:%M:%S"),
        })

    def kochirma(self):
        """Hisob ko'chirmasini chiqaradi."""
        print("=" * 50)
        print(f"{self.bank_nomi:^50}")
        print(f"{'Hisob egasi: ' + self.egasi:^50}")
        print("=" * 50)
        print(f"{'Vaqt':<12}{'Amal':<16}{'Summa':>10}{'Balans':>12}")
        print("-" * 50)
        for amal in self.tarix:
            belgi = "+" if amal["turi"] == "To'ldirish" else "-"
            print(f"{amal['vaqt']:<12}{amal['turi']:<16}"
                  f"{belgi + format(amal['summa'], ','):>10}"
                  f"{amal['balans']:>12,}")
        print("=" * 50)
        print(f"{'Joriy balans:':<38}{self._balans:>12,}")

    def __str__(self):
        return f"{self.egasi}: {self._balans:,} so'm"


hisob = BankHisobi("Husanboy Qodirov", 500_000)
hisob.toldirish(250_000)
hisob.yechish(100_000)
hisob.toldirish(75_000)

hisob.kochirma()

print()
try:
    hisob.yechish(10_000_000)
except ValueError as xato:
    print(f"Amal rad etildi: {xato}")

print(hisob)
Natija
==================================================
                 Softromeda Bank                  
          Hisob egasi: Husanboy Qodirov           
==================================================
Vaqt        Amal                 Summa      Balans
--------------------------------------------------
14:52:10    To'ldirish        +250,000     750,000
14:52:10    Yechish           -100,000     650,000
14:52:10    To'ldirish         +75,000     725,000
==================================================
Joriy balans:                          725,000

Amal rad etildi: Mablag' yetarli emas. Minimal qoldiq: 10,000 so'm
Husanboy Qodirov: 725,000 so'm
Amaliy topshiriq

Kitob klassini yarating:

  1. Atributlar: nomi, muallif, yil, sahifalar, oqilgan_sahifa.
  2. oqish(sahifalar_soni) metodi - o'qilgan sahifani oshirsin (kitob oxiridan oshib ketmasin).
  3. @property foiz - necha foiz o'qilganini qaytarsin.
  4. __str__ metodi - "Nomi (muallif, yil) - 45% o'qilgan" ko'rinishida qaytarsin.
  5. Uchta kitob obyekti yaratib, ularni foiz bo'yicha saralang.

Xulosa #

  • Klass - chizma, obyekt - shu chizma bo'yicha yaratilgan nusxa.
  • __init__ konstruktor bo'lib, obyekt yaratilganda avtomatik ishlaydi.
  • self har bir metodning birinchi parametri - obyektning o'ziga havola.
  • Klass atributi barcha obyektlarga umumiy, obyekt atributi har biriga xos.
  • __str__, __eq__, __lt__ kabi dunder metodlar obyektni Python bilan integratsiya qiladi.
  • @property metodni atribut kabi ishlatish imkonini beradi.

Keyingi bo'limda OOP ning uchta asosiy tamoyilini - meros, inkapsulyatsiya va polimorfizmni o'rganamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.