IlmHamroh
Python kursi/OOP1/20-dars32 daqiqa
Mundarija (21)

8.1-dars: OOP nima va nega kerak

8-QISM — OBYEKTGA YO'NALTIRILGAN DASTURLASH · 1-dars


1. Kirish va motivatsiya

Bank hisobini funksiyalar bilan yozamiz:

python
def hisob_yarat(egasi, balans=0):
    return {"egasi": egasi, "balans": balans, "tarix": []}

def qoshish(hisob, summa):
    hisob["balans"] += summa
    hisob["tarix"].append(("+", summa))

def yechish(hisob, summa):
    hisob["balans"] -= summa
    hisob["tarix"].append(("-", summa))

Ishlaydi. Lekin:

python
h = hisob_yarat("Aziz", 100)
yechish(h, 1000)
h["balans"]                     # -900 ⚠️ manfiy balans!

h["balans"] = 999999            # ⚠️ hech kim to'smaydi
h["blans"] = 50                 # ⚠️ xato yozilgan kalit — xato yo'q
del h["tarix"]                  # ⚠️ tuzilma buzildi

qoshish({"a": 1}, 50)           # ⚠️ KeyError, lekin faqat ish vaqtida

Muammolar:

  • Ma'lumot va uni o'zgartiruvchi kod ajralgan — birga ushlab turadigan narsa yo'q
  • Qoidalarni majburlash yo'q — balans manfiy bo'lishi mumkin
  • Ichki tuzilma ochiq — har kim buzishi mumkin
  • Turlar aralashib ketadi — lug'at lug'atdan farq qilmaydi

OOP shu to'rt muammoni hal qiladi:

python
class Hisob:
    def __init__(self, egasi, balans=0):
        self.egasi = egasi
        self._balans = balans
        self._tarix = []

    def yechish(self, summa):
        if summa > self._balans:
            raise ValueError("Mablag' yetarli emas")
        self._balans -= summa
        self._tarix.append(("-", summa))

Bu darsda:

  • OOP nima — to'rt ustun
  • Nega u paydo bo'lgan, qanday muammoni hal qiladi
  • Pythonda hamma narsa obyekt
  • Qachon OOP kerak, qachon kerak emas
  • Boshqa paradigmalar bilan solishtirish

2. Nazariya — chuqur tushuntirish

2.1. Paradigma nima

Dasturlash paradigmasi — muammoni qanday bo'laklarga bo'lish haqidagi yondashuv.

Paradigma Asosiy birlik Savol
Protsedura Funksiya "Qanday qadamlar bajariladi?"
Obyektga yo'naltirilgan Obyekt "Qanday narsalar bor va ular nima qiladi?"
Funksional Sof funksiya "Kirishdan chiqishga qanday almashtirish?"
Deklarativ Tavsif "Natija qanday ko'rinishi kerak?"

Python — ko'p paradigmali til. U to'rttasini ham qo'llab-quvvatlaydi:

python
# Protsedura
natija = []
for x in sonlar:
    if x > 0:
        natija.append(x * 2)

# Funksional
natija = list(map(lambda x: x * 2, filter(lambda x: x > 0, sonlar)))

# Deklarativ (comprehension)
natija = [x * 2 for x in sonlar if x > 0]

# OOP
natija = Sonlar(sonlar).musbatlar().kopaytir(2).royxat()

OOP — vosita, din emas. Har muammoga sinf yozish — xato.

2.2. OOP ning to'rt ustuni

1 Kapsulatsiya (encapsulation)

Ma'lumot va u bilan ishlaydigan kod bir joyda; ichki tafsilotlar yashiringan.

python
class Hisob:
    def __init__(self, balans):
        self._balans = balans           # ichki

    @property
    def balans(self):                   # nazorat ostida o'qish
        return self._balans

    def qoshish(self, summa):
        if summa <= 0:
            raise ValueError("Musbat bo'lsin")
        self._balans += summa

Foyda: invariant (doim rost bo'ladigan qoida) saqlanadi. Bu yerda — balans faqat tekshirilgan usulda o'zgaradi.

2 Abstraksiya (abstraction)

Foydalanuvchi nima qilishini biladi, qanday qilishini emas.

python
fayl.read()                     # qanday o'qiydi — bizga farqi yo'q
royxat.sort()                   # Timsort? bizga farqi yo'q

3 Meros (inheritance)

Yangi sinf mavjudining xatti-harakatini oladi va kengaytiradi.

python
class Hayvon:
    def ovqatlanish(self): ...

class It(Hayvon):               # It — Hayvon
    def vovullash(self): ...

4 Polimorfizm (polymorphism)

Bir xil interfeys — turli amalga oshirish.

python
for shakl in [Doira(5), Kvadrat(3), Uchburchak(3, 4, 5)]:
    print(shakl.yuza())         # har biri o'zicha hisoblaydi

Pythonda polimorfizm merosni TALAB QILMAYDI — duck typing yetadi:

python
class Doira:
    def yuza(self): return 3.14 * self.r ** 2

class Kvadrat:                  # meros yo'q
    def yuza(self): return self.a ** 2

# Ikkalasi ham ishlaydi

2.3. Pythonda hamma narsa obyekt

python
type(42)                        # <class 'int'>
type("a")                       # <class 'str'>
type([1])                       # <class 'list'>
type(print)                     # <class 'builtin_function_or_method'>
type(int)                       # <class 'type'>      ← sinf ham obyekt!
type(type)                      # <class 'type'>      ← o'zi-o'ziga

Har obyektning uch xususiyati bor:

Xususiyat Nima Qanday olish
Identifikator Xotiradagi joyi id(x)
Tur Qanday sinfdan type(x)
Qiymat Ma'lumoti x
python
x = 42
id(x), type(x), x

Shuning uchun:

python
(42).bit_length()               # 6 — int ning metodi
"abc".upper()                   # 'ABC'
[].append                       # <built-in method append of list>
(5).__add__(3)                  # 8 — 5 + 3 aslida shu

Siz OOP dan birinchi darsdan beri foydalanyapsiz — shunchaki bilmagansiz.

2.4. Sinf va obyekt

Sinf — chizma. Obyekt (nusxa) — chizmaga ko'ra qurilgan narsa.

      Sinf: Uy                    Obyektlar
  ┌────────────────┐         ┌──────────────┐
  │ xonalar: int   │  ────►  │ uy1: 3 xona  │
  │ rang: str      │  ────►  │ uy2: 5 xona  │
  │                │  ────►  │ uy3: 2 xona  │
  │ bo'yash()      │         └──────────────┘
  └────────────────┘
python
class Uy:                       # chizma
    def __init__(self, xonalar):
        self.xonalar = xonalar

uy1 = Uy(3)                     # nusxa
uy2 = Uy(5)                     # boshqa nusxa

uy1 is uy2                      # False — alohida obyektlar
type(uy1) is type(uy2)          # True — bir sinf

2.5. Nega OOP paydo bo'lgan

Tarix:

Yil Voqea
1962 Simula 67 (Norvegiya) — birinchi sinf va obyekt
1972 Smalltalk (Alan Kay) — "obyekt" atamasi, xabar almashish
1983 C++ — OOP asosiy tillarga kirdi
1995 Java — "hamma narsa sinf ichida"
1991 Python — OOP bor, lekin majburiy emas

Muammo: 1960-70-larda dasturlar kattalashdi. goto va global o'zgaruvchilar bilan 10 000 qatordan keyin hech kim tushunmasdi.

Yechim: kodni mustaqil, chegaralangan bo'laklarga bo'lish. Har bo'lak o'z ma'lumotini boshqaradi.

Alan Kay ning asl g'oyasi (u "object-oriented" atamasini o'ylab topgan):

"OOP menda faqat xabar almashish, lokal saqlash va himoya, va hamma narsani kech bog'lash degani edi."

Ko'p tillar (Java, C++) merosga urg'u berdi — Kay aytmagan narsaga. Bu — keyingi darslarda ko'radigan muammolarning sababi.

2.6. Qachon OOP kerak — va qachon kerak emas

OOP mos keladi:

python
# 1. Holat + xatti-harakat birga
class Ulanish:
    def __init__(self, url):
        self._soket = ulan(url)
    def sorov(self, yol): ...
    def yop(self): ...

# 2. Bir necha o'xshash turlar
class ToleForma: ...
class Karta(ToleForma): ...
class Naqd(ToleForma): ...

# 3. Invariant saqlash kerak
class Sana:
    def __init__(self, kun, oy):
        if not 1 <= oy <= 12:
            raise ValueError(...)

# 4. Resurs boshqaruvi
class Fayl:
    def __enter__(self): ...
    def __exit__(self, *_): ...

OOP ortiqcha:

python
# 1. Faqat bitta metod → funksiya yetadi
class Hisoblagich:                          # ⚠️
    def hisobla(self, x): return x * 2

def hisobla(x): return x * 2                # ✅

# 2. Faqat ma'lumot → dataclass yoki NamedTuple
class Nuqta:                                # ⚠️ ko'p yozuv
    def __init__(self, x, y):
        self.x, self.y = x, y

@dataclass                                  # ✅
class Nuqta:
    x: float
    y: float

# 3. "Menejer", "Ishlovchi", "Yordamchi" sinflari
class MalumotIshlovchiMenejer:              # ⚠️ ot emas, fe'l
    def qayta_ishla(self, d): ...

def qayta_ishla(d): ...                     # ✅

# 4. Global holatni yashirish
class Sozlamalar:                           # ⚠️ singleton — global
    _nusxa = None

Oddiy mezon: agar sinfda faqat __init__ va bitta metod bo'lsa — bu funksiya bo'lishi kerak.

2.7. OOP tanqidi

OOP — mukammal emas. Ma'lum muammolari:

1. Meros — mo'rt bog'lanish

python
class A:
    def f(self): self.g()
    def g(self): print("A.g")

class B(A):
    def g(self): print("B.g")   # A.f xatti-harakati o'zgardi

B().f()                         # "B.g" — kutilmagan

Bu — mo'rt asosiy sinf muammosi (fragile base class). Ota-sinf o'zgarsa — barcha avlodlar buzilishi mumkin.

2. O'zgaruvchan holat — bir vaqtli ish uchun xavfli

python
class Hisoblagich:
    def __init__(self): self.n = 0
    def oshir(self): self.n += 1    # ⚠️ thread-safe emas

3. Ortiqcha abstraksiya

Java dunyosidagi mashhur hazil: AbstractSingletonProxyFactoryBean — haqiqiy Spring sinfi.

4. "Milliard dollarlik xato" ga yaqin

Ba'zi tanqidchilar (Joe Armstrong, Erlang muallifi):

"OOP muammosi shundaki, siz banan so'ragan edingiz, lekin bananni ushlab turgan gorilla va butun o'rmonni oldingiz."

Pythonning javobi: OOP — ixtiyoriy. Funksiya yetsa — funksiya yozing. Sinf kerak bo'lsa — sinf. Aralashtirish ham mumkin.


3. Tez ma'lumotnoma

To'rt ustun

Kapsulatsiya   ma'lumot + kod birga, ichkarisi yashirin
Abstraksiya    "nima" ko'rinadi, "qanday" yashirin
Meros          yangi sinf mavjudini kengaytiradi
Polimorfizm    bir interfeys — turli amalga oshirish

Sinf va obyekt

python
class Nom:                      # chizma
    def __init__(self, x):      # konstruktor
        self.x = x              # nusxa atributi

    def metod(self):            # xatti-harakat
        return self.x

obyekt = Nom(5)                 # nusxa yaratish
obyekt.metod()                  # metod chaqirish

Hamma narsa obyekt

python
type(42)        int
type(int)       type            ← sinf ham obyekt
type(type)      type

id(x)           identifikator
type(x)         tur
x               qiymat

Qachon sinf

✅ holat + xatti-harakat birga
✅ bir necha o'xshash tur
✅ invariant saqlash
✅ resurs boshqaruvi

❌ faqat bitta metod       → funksiya
❌ faqat ma'lumot          → dataclass / NamedTuple
❌ "Menejer", "Ishlovchi"  → funksiya
❌ global holat            → aniq uzatish

4. Batafsil misollar

Misol 1 — Bir muammo, to'rt yondashuv

python
"""Bir vazifa — turli paradigmalarda."""

from dataclasses import dataclass, field
from functools import reduce
from typing import NamedTuple

print("=== VAZIFA: talabalar bahosini boshqarish ===\n")

MALUMOT = [
    ("Aziz", [90, 85, 78]),
    ("Malika", [95, 92, 88]),
    ("Bobur", [65, 70, 72]),
    ("Dilnoza", [88, 91, 94]),
]


print("=== 1. Protsedura yondashuvi ===\n")

talabalar_p = []

def talaba_qosh(ism, baholar):
    talabalar_p.append({"ism": ism, "baholar": list(baholar)})

def ortacha(talaba):
    b = talaba["baholar"]
    return sum(b) / len(b) if b else 0.0

def baho_qosh(talaba, baho):
    talaba["baholar"].append(baho)

def daraja(talaba):
    o = ortacha(talaba)
    return "A" if o >= 90 else "B" if o >= 80 else "C" if o >= 70 else "D"

for ism, baholar in MALUMOT:
    talaba_qosh(ism, baholar)

for t in talabalar_p:
    print(f"  {t['ism']:<10} {ortacha(t):>6.1f}  {daraja(t)}")

print(f"""
  ✅ Sodda, tez yozildi
  ⚠️ Ma'lumot va funksiya ajralgan
  ⚠️ t["blans"] kabi xato kalit — xato bermaydi
  ⚠️ baho_qosh(t, -50) — hech kim to'smaydi
  ⚠️ Global royxat (talabalar_p)
""")

# Muammo namoyishi
notogri = {"ism": "X", "bholar": [1]}       # xato yozilgan kalit
try:
    ortacha(notogri)
except KeyError as e:
    print(f"  Xato faqat ISH VAQTIDA: KeyError({e})\n")


print("=== 2. Funksional yondashuv ===\n")

class TalabaF(NamedTuple):
    """O'zgarmas — funksional uslub."""
    ism: str
    baholar: tuple[int, ...]


def ortacha_f(t: TalabaF) -> float:
    return sum(t.baholar) / len(t.baholar) if t.baholar else 0.0


def baho_qosh_f(t: TalabaF, baho: int) -> TalabaF:
    """YANGI obyekt qaytaradi — eskisini o'zgartirmaydi."""
    return t._replace(baholar=t.baholar + (baho,))


def daraja_f(o: float) -> str:
    return next(d for chegara, d in
                [(90, "A"), (80, "B"), (70, "C"), (0, "D")] if o >= chegara)


talabalar_f = tuple(TalabaF(ism, tuple(b)) for ism, b in MALUMOT)

for t in talabalar_f:
    print(f"  {t.ism:<10} {ortacha_f(t):>6.1f}  {daraja_f(ortacha_f(t))}")

eski = talabalar_f[0]
yangi = baho_qosh_f(eski, 100)
print(f"""
  O'zgarmaslik:
    eski.baholar  = {eski.baholar}
    yangi.baholar = {yangi.baholar}
    eski o'zgardimi? {'❌ yo`q' if eski.baholar == tuple(MALUMOT[0][1]) else 'ha'}

  ✅ Yon ta'sir yo'q, thread-safe
  ✅ Tur xavfsizligi (t.blans → AttributeError)
  ⚠️ Har o'zgarishda yangi obyekt (xotira)
  ⚠️ Invariant tekshiruvi yo'q
""")


print("=== 3. OOP yondashuvi ===\n")

class Talaba:
    """Baholarni boshqaradi va invariantni saqlaydi."""

    ENG_KAM = 0
    ENG_KOP = 100

    def __init__(self, ism: str, baholar: list[int] | None = None):
        if not ism.strip():
            raise ValueError("Ism bo'sh bo'lmasin")
        self.ism = ism
        self._baholar: list[int] = []
        for b in (baholar or []):
            self.baho_qosh(b)               # tekshiruvdan o'tkazamiz

    def baho_qosh(self, baho: int) -> None:
        if not self.ENG_KAM <= baho <= self.ENG_KOP:
            raise ValueError(
                f"Baho {self.ENG_KAM}–{self.ENG_KOP} oralig'ida bo'lsin: {baho}"
            )
        self._baholar.append(baho)

    @property
    def baholar(self) -> tuple[int, ...]:
        """Nusxa qaytaradi — tashqaridan o'zgartirib bo'lmaydi."""
        return tuple(self._baholar)

    @property
    def ortacha(self) -> float:
        return sum(self._baholar) / len(self._baholar) if self._baholar else 0.0

    @property
    def daraja(self) -> str:
        o = self.ortacha
        return "A" if o >= 90 else "B" if o >= 80 else "C" if o >= 70 else "D"

    def __repr__(self) -> str:
        return f"Talaba({self.ism!r}, {self._baholar})"

    def __str__(self) -> str:
        return f"{self.ism}: {self.ortacha:.1f} ({self.daraja})"


talabalar_o = [Talaba(ism, b) for ism, b in MALUMOT]

for t in talabalar_o:
    print(f"  {t}")

print(f"\n  Himoya sinovi:")
t = talabalar_o[0]

SINOVLAR = [
    ("t.baho_qosh(150)", lambda: t.baho_qosh(150)),
    ("t.baho_qosh(-10)", lambda: t.baho_qosh(-10)),
    ("t.baholar.append(999)", lambda: t.baholar.append(999)),
    ("Talaba('')", lambda: Talaba("")),
    ("t.ortacha = 100", lambda: setattr(t, "ortacha", 100)),
]

for kod, f in SINOVLAR:
    try:
        f()
        natija = "⚠️ o'tdi (himoya yo'q)"
    except Exception as e:
        natija = f"✅ {type(e).__name__}"
    print(f"    {kod:<26} {natija}")

print(f"""
  ✅ Invariant kafolatlangan (baho 0–100)
  ✅ Ichki ro'yxat himoyalangan
  ✅ Ma'lumot + xatti-harakat birga
  ⚠️ Ko'proq kod
""")


print("\n=== 4. dataclass — o'rta yo'l ===\n")

@dataclass
class TalabaD:
    """Kam kod, lekin sinf imkoniyatlari."""
    ism: str
    baholar: list[int] = field(default_factory=list)

    @property
    def ortacha(self) -> float:
        return sum(self.baholar) / len(self.baholar) if self.baholar else 0.0


talabalar_d = [TalabaD(ism, list(b)) for ism, b in MALUMOT]

for t in talabalar_d:
    print(f"  {t.ism:<10} {t.ortacha:>6.1f}")

print(f"\n  Bepul olingan:")
print(f"    repr:  {talabalar_d[0]}")
print(f"    eq:    {TalabaD('A', [1]) == TalabaD('A', [1])}")

print(f"""
  ✅ __init__, __repr__, __eq__ avtomatik
  ✅ Tur ko'rsatkichlari
  ⚠️ Invariant tekshiruvi yo'q (__post_init__ kerak)
""")


print("=== 5. Solishtirish ===\n")

print("""
  ┌──────────────┬────────┬───────────┬────────┬───────────┐
  │ Mezon        │ Protse.│ Funksional│ OOP    │ dataclass │
  ├──────────────┼────────┼───────────┼────────┼───────────┤
  │ Kod hajmi    │ kam    │ o'rta     │ ko'p   │ kam       │
  │ Invariant    │ ❌     │ ❌        │ ✅     │ ⚠️        │
  │ Tur xavfsiz. │ ❌     │ ✅        │ ✅     │ ✅        │
  │ Thread-safe  │ ❌     │ ✅        │ ❌     │ ❌        │
  │ Kengaytirish │ ❌     │ ⚠️        │ ✅     │ ✅        │
  │ Test qilish  │ ⚠️     │ ✅        │ ⚠️     │ ✅        │
  │ IDE yordami  │ ❌     │ ✅        │ ✅     │ ✅        │
  └──────────────┴────────┴───────────┴────────┴───────────┘

  ⭐ TANLASH:
     Bir martalik skript          → protsedura
     Ma'lumot uzatish             → NamedTuple / dataclass
     Qoidalar va holat            → sinf
     Bir vaqtli ish, hisoblash    → funksional
""")

Natijaning muhim qismi:

text
=== 1. Protsedura yondashuvi ===

  Aziz         84.3  B
  Malika       91.7  A
  Bobur        69.0  D

  Xato faqat ISH VAQTIDA: KeyError('baholar')

=== 3. OOP yondashuvi ===

  Aziz: 84.3 (B)
  Malika: 91.7 (A)

  Himoya sinovi:
    t.baho_qosh(150)           ✅ ValueError
    t.baho_qosh(-10)           ✅ ValueError
    t.baholar.append(999)      ✅ AttributeError
    Talaba('')                 ✅ ValueError
    t.ortacha = 100            ✅ AttributeError

Nima ko'rsatdi: 2.1, 2.2, 2.6-bo'limlar.

Misol 2 — Hamma narsa obyekt

python
"""Pythonda hamma narsa obyekt ekanining isboti."""

import sys
import types

print("=== 1. Har narsaning turi bor ===\n")

NARSALAR = [
    ("son", 42),
    ("float", 3.14),
    ("satr", "abc"),
    ("ro'yxat", [1, 2]),
    ("lug'at", {"a": 1}),
    ("to'plam", {1, 2}),
    ("tuple", (1, 2)),
    ("None", None),
    ("bool", True),
    ("funksiya", len),
    ("lambda", lambda x: x),
    ("sinf", int),
    ("modul", sys),
    ("tur", type),
    ("generator", (x for x in [1])),
    ("range", range(3)),
]

print(f"  {'Nima':<12} {'type()':<32} {'id() bor':<10} {'metodlar'}")
print("  " + "─" * 68)
for nom, obj in NARSALAR:
    tur = type(obj).__name__
    metodlar = len([a for a in dir(obj) if not a.startswith("_")])
    print(f"  {nom:<12} {tur:<32} {'✅':<10} {metodlar}")


print("\n=== 2. Sonlar ham obyekt ===\n")

x = 42

AMALLAR = [
    ("x.bit_length()",      lambda: x.bit_length()),
    ("x.to_bytes(2, 'big')", lambda: x.to_bytes(2, "big")),
    ("x.__add__(8)",        lambda: x.__add__(8)),
    ("x.__str__()",         lambda: x.__str__()),
    ("x.real, x.imag",      lambda: (x.real, x.imag)),
    ("x.numerator",         lambda: x.numerator),
    ("3.5-bob.is_integer()",  lambda: (3.5).is_integer()),
    ("3.5-bob.hex()",         lambda: (3.5).hex()),
    ("0.75-bob.as_integer_ratio()", lambda: (0.75).as_integer_ratio()),
]

for kod, f in AMALLAR:
    print(f"  {kod:<30} → {f()!r}")

print(f"""
  ⭐ 5 + 3 aslida:
     (5).__add__(3) = {(5).__add__(3)}

  ⚠️ Lekin to'g'ridan-to'g'ri yozmang:
     a + b  ✅       a.__add__(b)  ❌
     (chunki + qo'shimcha qoidalarni ham bajaradi — 8.13-dars)
""")


print("=== 3. Funksiyalar ham obyekt ===\n")

def salom(ism: str) -> str:
    """Salomlashadi."""
    return f"Salom, {ism}!"


ATRIBUTLAR = [
    ("__name__",        salom.__name__),
    ("__doc__",         salom.__doc__),
    ("__module__",      salom.__module__),
    ("__annotations__", salom.__annotations__),
    ("__defaults__",    salom.__defaults__),
    ("__code__.co_varnames", salom.__code__.co_varnames),
    ("__code__.co_argcount", salom.__code__.co_argcount),
]

for nom, qiymat in ATRIBUTLAR:
    print(f"  salom.{nom:<24} {qiymat!r}")

salom.chaqirilgan = 0                       # ⭐ atribut qo'shish mumkin
salom.chaqirilgan += 1
print(f"\n  salom.chaqirilgan = {salom.chaqirilgan}   ← o'zimiz qo'shdik")

print(f"  isinstance(salom, object) = {isinstance(salom, object)}")


print("\n=== 4. Sinflar ham obyekt ===\n")

print(f"  type(int)        = {type(int)}")
print(f"  type(str)        = {type(str)}")
print(f"  type(type)       = {type(type)}      ← o'zi-o'ziga")
print(f"  int.__name__     = {int.__name__!r}")
print(f"  int.__bases__    = {int.__bases__}")
print(f"  int.__mro__      = {int.__mro__}")

# Sinfni o'zgaruvchiga solish
T = int
print(f"\n  T = int; T('42') = {T('42')!r}")

# Sinfni funksiyaga uzatish
def yarat(sinf, *args):
    return sinf(*args)

print(f"  yarat(list, [1,2]) = {yarat(list, [1, 2])}")
print(f"  yarat(dict, [('a',1)]) = {yarat(dict, [('a', 1)])}")

# Sinfni ish vaqtida yaratish
Nuqta = type("Nuqta", (), {"x": 0, "y": 0,
                           "masofa": lambda self: (self.x**2 + self.y**2)**0.5})
n = Nuqta()
n.x, n.y = 3, 4
print(f"\n  type() bilan yaratilgan sinf:")
print(f"    Nuqta = type('Nuqta', (), {{...}})")
print(f"    n.masofa() = {n.masofa()}")


print("\n=== 5. Uch xususiyat ===\n")

a = [1, 2, 3]
b = a
c = [1, 2, 3]

print(f"  a = [1, 2, 3]")
print(f"  b = a")
print(f"  c = [1, 2, 3]\n")

print(f"  {'':<6} {'id()':<18} {'type()':<10} {'qiymat'}")
print("  " + "─" * 48)
for nom, obj in [("a", a), ("b", b), ("c", c)]:
    print(f"  {nom:<6} {id(obj):<18} {type(obj).__name__:<10} {obj}")

print(f"""
  a is b  = {a is b}    ← bir xil identifikator
  a is c  = {a is c}   ← boshqa obyekt
  a == c  = {a == c}    ← bir xil qiymat

  ⭐ is  → identifikator (id)
     ==  → qiymat (__eq__)
""")


print("=== 6. object — hamma narsaning otasi ===\n")

TURLAR = [int, float, str, list, dict, set, tuple, bool, type, object]

print(f"  {'Tur':<10} {'object dan meros':<20} {'MRO uzunligi'}")
print("  " + "─" * 46)
for t in TURLAR:
    meros = "✅" if issubclass(t, object) else "❌"
    print(f"  {t.__name__:<10} {meros:<20} {len(t.__mro__)}")

print(f"""
  bool.__mro__ = {bool.__mro__}
  ⭐ bool — int dan meros! Shuning uchun:
     True + True = {True + True}
     isinstance(True, int) = {isinstance(True, int)}
""")

print(f"  object da nechta atribut: {len(dir(object))}")
print(f"  Ular: {', '.join(sorted(dir(object))[:8])}, ...")

Natijaning muhim qismi:

text
=== 1. Har narsaning turi bor ===

  Nima         type()                           id() bor   metodlar
  ────────────────────────────────────────────────────────────────────
  son          int                              ✅          11
  satr         str                              ✅          47
  sinf         type                             ✅          11
  modul        module                           ✅          79
  tur          type                             ✅          1

=== 4. Sinflar ham obyekt ===

  type(int)        = <class 'type'>
  type(type)       = <class 'type'>      ← o'zi-o'ziga
  int.__mro__      = (<class 'int'>, <class 'object'>)

  type() bilan yaratilgan sinf:
    n.masofa() = 5.0

=== 6. object — hamma narsaning otasi ===

  bool.__mro__ = (<class 'bool'>, <class 'int'>, <class 'object'>)
  ⭐ bool — int dan meros!
     True + True = 2

Nima ko'rsatdi: 2.3-bo'lim.

Misol 3 — Qachon sinf kerak emas

python
"""OOP ni ortiqcha ishlatish belgilari va tuzatishlar."""

from dataclasses import dataclass
from typing import NamedTuple
import math

print("=== ⚠️ ANTIPATTERN 1: bitta metodli sinf ===\n")

print("""  ❌ Yomon:

     class SalomBeruvchi:
         def __init__(self, ism):
             self.ism = ism
         def salom(self):
             return f"Salom, {self.ism}!"

     SalomBeruvchi("Aziz").salom()

  ✅ Yaxshi:

     def salom(ism):
         return f"Salom, {ism}!"

     salom("Aziz")

  ⭐ MEZON: sinfda faqat __init__ va bitta metod bo'lsa —
     bu funksiya bo'lishi kerak.
""")


class HisobKitobchi:                            # ❌
    def __init__(self, foiz):
        self.foiz = foiz

    def hisobla(self, summa):
        return summa * (1 + self.foiz / 100)


def foiz_qosh(summa, foiz):                     # ✅
    return summa * (1 + foiz / 100)


print(f"  Sinf:     HisobKitobchi(10).hisobla(100) = "
      f"{HisobKitobchi(10).hisobla(100)}")
print(f"  Funksiya: foiz_qosh(100, 10)            = {foiz_qosh(100, 10)}")

print(f"""
  ⚠️ Istisno: agar sozlama BIR MARTA berilib,
     KO'P MARTA ishlatilsa — yopilma yoki partial yaxshiroq:

     from functools import partial
     ozbek_foizi = partial(foiz_qosh, foiz=10)
     ozbek_foizi(100)  →  {math.floor(foiz_qosh(100, 10))}
""")


print("=== ⚠️ ANTIPATTERN 2: getter/setter sinfi ===\n")

class NuqtaYomon:                               # ❌
    def __init__(self, x, y):
        self._x = x
        self._y = y

    def get_x(self): return self._x
    def set_x(self, v): self._x = v
    def get_y(self): return self._y
    def set_y(self, v): self._y = v


@dataclass                                       # ✅
class Nuqta:
    x: float
    y: float


class NuqtaNT(NamedTuple):                       # ✅ o'zgarmas
    x: float
    y: float


print(f"  ❌ NuqtaYomon: 4 metod, hech qanday mantiq — 12 qator")
print(f"  ✅ dataclass:  2 qator, __repr__ va __eq__ bepul")
print(f"  ✅ NamedTuple: 2 qator, o'zgarmas, tuple kabi ishlaydi\n")

p1, p2 = Nuqta(1, 2), Nuqta(1, 2)
n1 = NuqtaNT(3, 4)

print(f"    Nuqta(1,2) == Nuqta(1,2)  → {p1 == p2}")
print(f"    repr: {p1}")
print(f"    NamedTuple ochish: x, y = n1 → {tuple(n1)}")

print(f"""
  ⭐ Pythonda getter/setter KERAK EMAS:
     • Ochiq atribut yozing
     • Keyin nazorat kerak bo'lsa — @property qo'shasiz
     • Chaqiruvchi kod O'ZGARMAYDI

     class Nuqta:
         @property
         def x(self): return self._x    # keyin qo'shildi

     p.x   ← bir xil ishlatiladi
""")


print("=== ⚠️ ANTIPATTERN 3: 'Menejer' sinflari ===\n")

print("""  ❌ Yomon (nomi FE'L — bu funksiya belgisi):

     class MalumotIshlovchi:
     class FaylOquvchi:
     class HisobotYaratuvchi:
     class SozlamaBoshqaruvchi:
     class ValidatsiyaMenejeri:

  ✅ Yaxshi (nomi OT — haqiqiy narsa):

     class Hujjat:
     class Ulanish:
     class Buyurtma:
     class Sana:

  ⭐ TEST: sinf nomini ot deb ayta olasizmi?
     "Bir dona MalumotIshlovchi"  ⚠️ g'alati
     "Bir dona Hujjat"            ✅ tabiiy

  Fe'l nomli sinflar odatda modul bo'lishi kerak:

     # malumot_ishlash.py
     def yukla(yol): ...
     def tozala(m): ...
     def saqla(m, yol): ...
""")


print("=== ⚠️ ANTIPATTERN 4: sinf ichida global holat ===\n")

class SozlamalarYomon:                          # ❌ singleton
    _nusxa = None
    _malumot = {}

    def __new__(cls):
        if cls._nusxa is None:
            cls._nusxa = super().__new__(cls)
        return cls._nusxa

    def olish(self, kalit):
        return self._malumot.get(kalit)


s1 = SozlamalarYomon()
s2 = SozlamalarYomon()
print(f"  s1 is s2 = {s1 is s2}   ← har doim bir obyekt")

print("""
  ⚠️ Muammolar:
     • Bu — chiroyli qadoqlangan GLOBAL o'zgaruvchi
     • Testlarda holat testdan testga o'tadi
     • Bir vaqtli ishda xavfli
     • Bog'liqlik yashirin (kim ishlatayotgani ko'rinmaydi)

  ✅ Yaxshi — aniq uzatish:

     @dataclass(frozen=True)
     class Sozlamalar:
         url: str
         chegara: int = 100

     def ishla(malumot, sozlamalar: Sozlamalar):
         ...

     # Testda:
     ishla(m, Sozlamalar(url="test://", chegara=5))
""")


print("=== ⚠️ ANTIPATTERN 5: chuqur meros ===\n")

print("""  ❌ Yomon:

     Obyekt → Jonzot → Hayvon → Sutemizuvchi → Yirtqich
            → Mushuksimon → Katta → Sher

     • 7 daraja — self.f() qayerdan kelganini topib bo'lmaydi
     • Ota-sinf o'zgarsa — hammasi buziladi
     • Yangi holat mos kelmasa (uchadigan sher?) — qayta yozish

  ✅ Yaxshi — kompozitsiya:

     @dataclass
     class Hayvon:
         nom: str
         ovqatlanish: OvqatlanishUsuli
         harakat: HarakatUsuli

     sher = Hayvon("Sher", Yirtqich(), Yugurish())
     burgut = Hayvon("Burgut", Yirtqich(), Uchish())

  ⭐ QOIDA: meros chuqurligi ≤ 2–3 daraja.
     Bundan chuqur bo'lsa — kompozitsiyani ko'rib chiqing (8.20-dars).
""")


print("=== ✅ QACHON SINF TO'G'RI ===\n")

class Sana:
    """✅ Invariant + xatti-harakat + turlararo amallar."""

    KUNLAR = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)

    def __init__(self, kun: int, oy: int, yil: int):
        if not 1 <= oy <= 12:
            raise ValueError(f"Oy 1–12: {oy}")
        maks = self.KUNLAR[oy - 1] + (
            1 if oy == 2 and self._kabisa(yil) else 0)
        if not 1 <= kun <= maks:
            raise ValueError(f"{oy}-oyda {maks} kun bor: {kun}")
        self.kun, self.oy, self.yil = kun, oy, yil

    @staticmethod
    def _kabisa(yil: int) -> bool:
        return yil % 4 == 0 and (yil % 100 != 0 or yil % 400 == 0)

    def __repr__(self) -> str:
        return f"Sana({self.kun}, {self.oy}, {self.yil})"

    def __str__(self) -> str:
        return f"{self.kun:02d}.{self.oy:02d}.{self.yil}"

    def __eq__(self, boshqa) -> bool:
        if not isinstance(boshqa, Sana):
            return NotImplemented
        return (self.yil, self.oy, self.kun) == \
               (boshqa.yil, boshqa.oy, boshqa.kun)

    def __lt__(self, boshqa) -> bool:
        if not isinstance(boshqa, Sana):
            return NotImplemented
        return (self.yil, self.oy, self.kun) < \
               (boshqa.yil, boshqa.oy, boshqa.kun)


SINOVLAR = [
    ("Sana(15, 3, 2026)",   lambda: Sana(15, 3, 2026)),
    ("Sana(31, 2, 2026)",   lambda: Sana(31, 2, 2026)),
    ("Sana(29, 2, 2024)",   lambda: Sana(29, 2, 2024)),
    ("Sana(29, 2, 2026)",   lambda: Sana(29, 2, 2026)),
    ("Sana(1, 13, 2026)",   lambda: Sana(1, 13, 2026)),
]

for kod, f in SINOVLAR:
    try:
        natija = f"✅ {f()}"
    except ValueError as e:
        natija = f"❌ {e}"
    print(f"  {kod:<24} {natija}")

sanalar = [Sana(15, 3, 2026), Sana(1, 1, 2026), Sana(31, 12, 2025)]
print(f"\n  Saralash (__lt__ tufayli): "
      f"{[str(s) for s in sorted(sanalar)]}")

print("""
  ⭐ Bu sinf O'RINLI, chunki:
     1. Invariant bor (kun oyga mos bo'lishi kerak)
     2. Xatti-harakat bor (taqqoslash, formatlash)
     3. Bir necha metod ma'noli bog'langan
     4. Tur o'zi ma'no beradi (Sana ≠ tuple)
""")

Natijaning muhim qismi:

text
=== ⚠️ ANTIPATTERN 1: bitta metodli sinf ===

  Sinf:     HisobKitobchi(10).hisobla(100) = 110.00000000000001
  Funksiya: foiz_qosh(100, 10)            = 110.00000000000001

=== ⚠️ ANTIPATTERN 4: sinf ichida global holat ===

  s1 is s2 = True   ← har doim bir obyekt

=== ✅ QACHON SINF TO'G'RI ===

  Sana(15, 3, 2026)        ✅ 15.03.2026
  Sana(31, 2, 2026)        ❌ 2-oyda 28 kun bor: 31
  Sana(29, 2, 2024)        ✅ 29.02.2024
  Sana(29, 2, 2026)        ❌ 2-oyda 28 kun bor: 29
  Sana(1, 13, 2026)        ❌ Oy 1–12: 13

  Saralash (__lt__ tufayli): ['31.12.2025', '01.01.2026', '15.03.2026']

Nima ko'rsatdi: 2.6, 2.7-bo'limlar.

Misol 4 — To'rt ustunni ko'rish

python
"""Kapsulatsiya, abstraksiya, meros, polimorfizm — bir misolda."""

from abc import ABC, abstractmethod
from dataclasses import dataclass
import math

print("=== 1️⃣ KAPSULATSIYA ===\n")

class Termostat:
    """Harorat nazorati — ichki holat himoyalangan."""

    MIN, MAKS = 5.0, 35.0

    def __init__(self, boshlangich: float = 20.0):
        self._harorat = 0.0
        self._tarix: list[float] = []
        self.orn(boshlangich)               # tekshiruvdan o'tadi

    def orn(self, qiymat: float) -> None:
        """Haroratni o'rnatadi (chegaralar ichida)."""
        if not self.MIN <= qiymat <= self.MAKS:
            raise ValueError(
                f"Harorat {self.MIN}–{self.MAKS}°C oralig'ida: {qiymat}"
            )
        self._harorat = qiymat
        self._tarix.append(qiymat)

    def oshir(self, daraja: float = 1.0) -> None:
        self.orn(min(self._harorat + daraja, self.MAKS))

    def pasaytir(self, daraja: float = 1.0) -> None:
        self.orn(max(self._harorat - daraja, self.MIN))

    @property
    def harorat(self) -> float:
        return self._harorat

    @property
    def tarix(self) -> tuple[float, ...]:
        return tuple(self._tarix)           # nusxa — buzib bo'lmaydi


t = Termostat(22)
t.oshir(3)
t.pasaytir(1)
t.oshir(50)                                 # MAKS da to'xtaydi

print(f"  Joriy harorat: {t.harorat}°C")
print(f"  Tarix: {t.tarix}")

print(f"\n  Himoya:")
for kod, f in [
    ("t.orn(100)", lambda: t.orn(100)),
    ("t.orn(-5)", lambda: t.orn(-5)),
    ("t.tarix.append(99)", lambda: t.tarix.append(99)),
    ("t.harorat = 99", lambda: setattr(t, "harorat", 99)),
]:
    try:
        f(); n = "⚠️ o'tdi"
    except Exception as e:
        n = f"✅ {type(e).__name__}"
    print(f"    {kod:<22} {n}")

print(f"""
  ⭐ Kapsulatsiya bergan kafolat:
     _harorat DOIM {Termostat.MIN}–{Termostat.MAKS} oralig'ida.
     Bu — INVARIANT. Sinf tashqarisidagi hech qanday kod
     uni buza olmaydi.
""")


print("=== 2️⃣ ABSTRAKSIYA ===\n")

class Ombor(ABC):
    """Ma'lumot saqlash interfeysi — QANDAY saqlanishi muhim emas."""

    @abstractmethod
    def saqla(self, kalit: str, qiymat: str) -> None: ...

    @abstractmethod
    def olish(self, kalit: str) -> str | None: ...

    def olish_yoki(self, kalit: str, sukut: str) -> str:
        """Umumiy mantiq — bir marta yoziladi."""
        q = self.olish(kalit)
        return sukut if q is None else q


class XotiraOmbor(Ombor):
    def __init__(self):
        self._m: dict[str, str] = {}

    def saqla(self, kalit, qiymat):
        self._m[kalit] = qiymat

    def olish(self, kalit):
        return self._m.get(kalit)


class JurnalliOmbor(Ombor):
    """Har amalni yozib boradi."""

    def __init__(self, ichki: Ombor):
        self._ichki = ichki
        self.jurnal: list[str] = []

    def saqla(self, kalit, qiymat):
        self.jurnal.append(f"SAQLA {kalit}={qiymat}")
        self._ichki.saqla(kalit, qiymat)

    def olish(self, kalit):
        self.jurnal.append(f"OLISH {kalit}")
        return self._ichki.olish(kalit)


def foydalanuvchi_ishi(ombor: Ombor) -> str:
    """⭐ Bu funksiya QANDAY omborni bilmaydi."""
    ombor.saqla("til", "python")
    ombor.saqla("versiya", "3.12")
    return f"{ombor.olish('til')} {ombor.olish_yoki('versiya', '?')}"


x = XotiraOmbor()
j = JurnalliOmbor(XotiraOmbor())

print(f"  XotiraOmbor:   {foydalanuvchi_ishi(x)}")
print(f"  JurnalliOmbor: {foydalanuvchi_ishi(j)}")
print(f"\n  Jurnal:")
for q in j.jurnal:
    print(f"    {q}")

print(f"""
  ⭐ foydalanuvchi_ishi() o'zgarmadi, lekin xatti-harakat
     butunlay boshqacha. Bu — abstraksiya kuchi.
""")


print("=== 3️⃣ MEROS ===\n")

class Xodim:
    def __init__(self, ism: str, maosh: float):
        self.ism = ism
        self.maosh = maosh

    def oylik(self) -> float:
        return self.maosh

    def tavsif(self) -> str:
        return f"{self.ism} ({type(self).__name__})"


class Menejer(Xodim):
    def __init__(self, ism, maosh, jamoa: int):
        super().__init__(ism, maosh)        # ota-konstruktor
        self.jamoa = jamoa

    def oylik(self) -> float:
        return super().oylik() + self.jamoa * 50_000    # ustama


class Sotuvchi(Xodim):
    def __init__(self, ism, maosh, sotuv: float, foiz: float = 5):
        super().__init__(ism, maosh)
        self.sotuv, self.foiz = sotuv, foiz

    def oylik(self) -> float:
        return super().oylik() + self.sotuv * self.foiz / 100


class Stajyor(Xodim):
    def oylik(self) -> float:
        return self.maosh * 0.5


XODIMLAR = [
    Xodim("Aziz", 5_000_000),
    Menejer("Malika", 8_000_000, jamoa=6),
    Sotuvchi("Bobur", 4_000_000, sotuv=30_000_000),
    Stajyor("Dilnoza", 3_000_000),
]

print(f"  {'Xodim':<28} {'Asosiy':>14} {'Oylik':>14}")
print("  " + "─" * 58)
for x in XODIMLAR:
    print(f"  {x.tavsif():<28} {x.maosh:>14,.0f} {x.oylik():>14,.0f}")

print(f"\n  Meros zanjiri:")
for sinf in [Xodim, Menejer, Sotuvchi, Stajyor]:
    zanjir = " → ".join(c.__name__ for c in sinf.__mro__)
    print(f"    {zanjir}")

print(f"""
  ⭐ tavsif() faqat BIR MARTA yozilgan (Xodim da),
     lekin to'rt sinfda ham ishlaydi.

  ⭐ super().oylik() ota-sinf mantiqini QAYTA ISHLATADI.
""")


print("=== 4️⃣ POLIMORFIZM ===\n")

@dataclass
class Doira:
    r: float
    def yuza(self) -> float: return math.pi * self.r ** 2
    def perimetr(self) -> float: return 2 * math.pi * self.r


@dataclass
class Togriturtburchak:
    a: float
    b: float
    def yuza(self) -> float: return self.a * self.b
    def perimetr(self) -> float: return 2 * (self.a + self.b)


@dataclass
class Uchburchak:
    a: float
    b: float
    c: float
    def yuza(self) -> float:
        p = (self.a + self.b + self.c) / 2
        return math.sqrt(p * (p-self.a) * (p-self.b) * (p-self.c))
    def perimetr(self) -> float: return self.a + self.b + self.c


SHAKLLAR = [Doira(5), Togriturtburchak(4, 6), Uchburchak(3, 4, 5)]

print(f"  {'Shakl':<32} {'Yuza':>10} {'Perimetr':>10}")
print("  " + "─" * 54)
for s in SHAKLLAR:
    print(f"  {str(s):<32} {s.yuza():>10.2f} {s.perimetr():>10.2f}")

jami = sum(s.yuza() for s in SHAKLLAR)
eng_katta = max(SHAKLLAR, key=lambda s: s.yuza())
print(f"\n  Jami yuza:  {jami:.2f}")
print(f"  Eng katta:  {eng_katta}")

print(f"""
  ⭐ MUHIM: bu uch sinf HECH NARSADAN meros olmagan!

     Polimorfizm Pythonda MEROS talab qilmaydi —
     bir xil metod nomi yetadi. Bu — DUCK TYPING.

  ⭐ O'rnatilgan polimorfizm misollari:
     len()     — str, list, dict, set, ... hammasida
     +         — son, satr, ro'yxat, ...
     for       — har qanday iterable
     print()   — har qanday obyekt (__str__)
""")

print(f"  len() polimorfizmi:")
for x in ["abcde", [1, 2, 3], {"a": 1}, {1, 2}, (1,), range(7), b"xy"]:
    print(f"    len({x!r:<16}) = {len(x)}   ({type(x).__name__})")

print(f"\n  + polimorfizmi:")
for a, b in [(1, 2), (1.5, 2.5), ("ab", "cd"), ([1], [2]), ((1,), (2,))]:
    print(f"    {a!r:<8} + {b!r:<8} = {a + b!r}")


print("\n=== YAKUN: to'rt ustun birga ===\n")
print("""
  ┌─────────────────┬──────────────────────────────────────────┐
  │ Ustun           │ Nima beradi                              │
  ├─────────────────┼──────────────────────────────────────────┤
  │ Kapsulatsiya    │ Invariant kafolati, xavfsiz o'zgartirish │
  │ Abstraksiya     │ Amalga oshirishni almashtirish erkinligi │
  │ Meros           │ Kodni qayta ishlatish, umumiy shartnoma  │
  │ Polimorfizm     │ Bir kod — ko'p tur bilan ishlaydi        │
  └─────────────────┴──────────────────────────────────────────┘

  ⚠️ PYTHONDA:
     • Kapsulatsiya — kelishuv (_ va __), majburlash emas
     • Meros — foydali, lekin kompozitsiya ko'pincha yaxshiroq
     • Polimorfizm — duck typing orqali, merossiz ham
     • Abstraksiya — ABC yoki Protocol bilan
""")

Natijaning muhim qismi:

text
=== 1️⃣ KAPSULATSIYA ===

  Joriy harorat: 35.0°C
  Tarix: (22, 25, 24, 35.0)

  Himoya:
    t.orn(100)             ✅ ValueError
    t.tarix.append(99)     ✅ AttributeError
    t.harorat = 99         ✅ AttributeError

=== 3️⃣ MEROS ===

  Xodim                Asosiy         Oylik
  ──────────────────────────────────────────
  Aziz (Xodim)       5,000,000     5,000,000
  Malika (Menejer)   8,000,000     8,300,000
  Bobur (Sotuvchi)   4,000,000     5,500,000
  Dilnoza (Stajyor)  3,000,000     1,500,000

=== 4️⃣ POLIMORFIZM ===

  Doira(r=5)                        78.54      31.42
  Togriturtburchak(a=4, b=6)        24.00      20.00
  Uchburchak(a=3, b=4, c=5)          6.00      12.00

Nima ko'rsatdi: 2.2-bo'lim.


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"OOP — eng yaxshi paradigma" Vosita. Muammoga qarab tanlanadi
"Hamma kod sinf ichida bo'lsin" Java qoidasi. Pythonda funksiya ham to'liq huquqli
"Polimorfizm meros talab qiladi" Pythonda duck typing yetadi
"Pythonda OOP yo'q" Bor va to'liq — type, __mro__, metaklasslar
"Sinf — faqat ma'lumot idishi" Ma'lumot uchun dataclass/NamedTuple
"Meros — asosiy OOP vositasi" Kompozitsiya ko'pincha yaxshiroq (8.20)
"private bo'lmasa kapsulatsiya yo'q" Kelishuv (_) amalda yetarli ishlaydi
"OOP sekinroq" Atribut qidiruvi biroz sekin, lekin bu kamdan-kam muhim

6. Keng tarqalgan xatolar va yechimlari

1. Har narsa uchun sinf

python
class Yigindi:                              # ❌
    def hisobla(self, a, b): return a + b

def yigindi(a, b): return a + b             # ✅

2. Fe'l nomli sinflar

python
class MalumotIshlovchi: ...                 # ❌
class Hujjat: ...                           # ✅ ot

3. Getter/setter yozish

python
def get_x(self): return self._x             # ❌ Java uslubi
self.x = x                                  # ✅ keyin @property qo'shasiz

4. Chuqur meros

python
A → B → C → D → E → F                       # ❌ 6 daraja
A → B                                       # ✅ 2 daraja

5. Ma'lumot uchun to'liq sinf

python
class Nuqta:                                # ⚠️ 8 qator
    def __init__(self, x, y): ...
    def __repr__(self): ...
    def __eq__(self, o): ...

@dataclass                                  # ✅ 3 qator
class Nuqta:
    x: float
    y: float

6. Ichki ro'yxatni qaytarish

python
@property
def elementlar(self): return self._el       # ⚠️ tashqaridan o'zgartiriladi

@property
def elementlar(self): return tuple(self._el)  # ✅

7. Konstruktorda tekshirmaslik

python
def __init__(self, yosh):
    self.yosh = yosh                        # ⚠️ -5 ham o'tadi

def __init__(self, yosh):
    if yosh < 0: raise ValueError(...)      # ✅
    self.yosh = yosh

8. Singleton bilan globalni yashirish

python
class Sozlamalar:                           # ⚠️ global
    _nusxa = None

def ishla(m, sozlamalar: Sozlamalar): ...   # ✅ aniq uzatish

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 8.2-8.20-darslar: butun qism shu asosga quriladi
  • 7-qism (o'tilgan): metodlar — bu self oladigan funksiyalar
  • 6-qism: list, dict — bularning hammasi sinf
  • 9-qism: istisnolar ham sinflar (Exception dan meros)
  • 10-qism: dekoratorlar sinflarga ham qo'llanadi
  • 23-qism: ORM (Prisma, SQLAlchemy) — jadval = sinf
  • Kitob: Fluent Python (Luciano Ramalho) — Python obyekt modeli

8. Eng yaxshi amaliyotlar

  1. Sinf — ot, metod — fe'l. Hujjat.saqla(), MalumotIshlovchi.ishla() emas.

  2. Faqat bitta metod bo'lsa — funksiya yozing. Sinf ortiqcha qatlam.

  3. Faqat ma'lumot bo'lsa — dataclass yoki NamedTuple.

  4. Konstruktorda invariantni tekshiring. Noto'g'ri obyekt umuman yaratilmasin.

  5. Getter/setter yozmang. Ochiq atribut → keyin kerak bo'lsa @property.

  6. Meros chuqurligi ≤ 2–3 daraja. Chuqur bo'lsa — kompozitsiya.

  7. Ichki konteynerni nusxa qilib qaytaring. tuple(self._el).

  8. Paradigmani aralashtiring. Pythonda bu — kuch, kamchilik emas.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
1.  print(type(42), type(int), type(type))
2.  print(isinstance(True, int))
3.  print(True + True + True)
4.  print((5).__add__(3))
5.  class A: pass
    a1, a2 = A(), A()
    print(a1 == a2, a1 is a2)
6.  class A:
        x = 1
    print(A.x, A().x)
7.  def f(): pass
    f.n = 5
    print(f.n)
8.  print(int.__mro__)
9.  print(len([a for a in dir(int) if not a.startswith("_")]))
10. class A: pass
    print(A.__bases__)
11. T = type("B", (), {"x": 7})
    print(T().x)
12. print(issubclass(bool, int), issubclass(int, bool))
Javoblar
  1. <class 'int'> <class 'type'> <class 'type'>
  2. True — bool int dan meros
  3. 3 — True = 1
  4. 8
  5. False False — sukut bo'yicha == is kabi ishlaydi, a1 va a2 esa alohida obyektlar
  6. 1 1 — sinf atributi nusxa orqali ham ko'rinadi
  7. 5 — funksiyaga atribut qo'shish mumkin
  8. (<class 'int'>, <class 'object'>)
  9. 11 — metodlar (bit_length, bit_count, to_bytes, from_bytes, as_integer_ratio, is_integer, conjugate) va atributlar (real, imag, numerator, denominator) — int ham to'liq obyekt
  10. (<class 'object'>,)
  11. 7
  12. True False

Vazifa 2: Sinf kerakmi?

Har holat uchun ayting — sinf, funksiya, dataclass yoki modul?

1.  Ikki sonni qo'shish
2.  Bank hisobi (balans, o'tkazmalar, tarix)
3.  RGB rang (r, g, b qiymatlari)
4.  Matn tozalash uchun 10 ta funksiya
5.  Ma'lumotlar bazasi ulanishi (ochish, so'rov, yopish)
6.  Foydalanuvchi ma'lumoti (ism, email, yosh)
7.  Sana (kun, oy, yil + taqqoslash + formatlash)
8.  Faylni JSON ga o'girish
Javoblar
  1. Funksiya — holat yo'q
  2. Sinf — invariant (manfiy balans yo'q) + xatti-harakat
  3. NamedTuple / frozen dataclass — o'zgarmas ma'lumot
  4. Modul — funksiyalar to'plami, umumiy holat yo'q
  5. Sinf — resurs boshqaruvi, __enter__/__exit__
  6. dataclass — asosan ma'lumot
  7. Sinf — invariant + taqqoslash + formatlash
  8. Funksiya — bir amal

Vazifa 3: Refaktoring

Bu kodni sinfga o'giring va invariantni qo'shing:

python
savat = {"mahsulotlar": [], "chegirma": 0}

def qosh(s, nom, narx, soni):
    s["mahsulotlar"].append({"nom": nom, "narx": narx, "soni": soni})

def jami(s):
    j = sum(m["narx"] * m["soni"] for m in s["mahsulotlar"])
    return j * (1 - s["chegirma"] / 100)

Talablar: narx va soni musbat, chegirma 0-100, mahsulotlar tashqaridan o'zgarmasin.

Vazifa 4: To'rt ustun

Kutubxona tizimi yozing:

  1. Kitob — nom, muallif, ISBN (invariant: ISBN 13 raqam)
  2. Kutubxona — kitoblarni saqlaydi (kapsulatsiya)
  3. RaqamliKitob(Kitob) — hajm, format qo'shadi (meros)
  4. Barcha kitob turlarida tavsif() (polimorfizm)
  5. Ombor abstrakt sinfi — xotira va fayl versiyalari (abstraksiya)

Vazifa 5: Antipattern topish

Quyidagilardagi muammoni ayting va tuzating:

python
1.  class StringYordamchi:
        @staticmethod
        def tozala(s): return s.strip()

2.  class Konfiguratsiya:
        _nusxa = None
        def __new__(cls): ...

3.  class Foydalanuvchi:
        def get_ism(self): return self._ism
        def set_ism(self, v): self._ism = v

4.  class A: pass
    class B(A): pass
    class C(B): pass
    class D(C): pass
    class E(D): pass

Vazifa 6: Paradigma solishtirish

Bir vazifani (masalan, matndagi so'zlarni sanash) to'rt usulda yozing:

  1. Protsedura
  2. Funksional
  3. OOP
  4. dataclass bilan

Har birining kod hajmi, o'qilishi va test qilinishini solishtiring.

Vazifa 7: O'ylash

Nega Alan Kay (OOP atamasining muallifi) keyinchalik aytdi: "Men 'obyektlar' deganimda uyaldim, chunki bu ko'pchilikni kichikroq g'oyaga olib bordi"?

Javob

Chunki asosiy g'oya obyektlar emas, xabar almashish edi.

Kay ning asl g'oyasi (Smalltalk, 1970-lar):

Kay biologiyadan ilhomlangan. Uning modeli — hujayralar:

  • Har hujayra o'z ichini to'liq boshqaradi
  • Hujayralar bir-biriga kimyoviy signal yuboradi
  • Hech bir hujayra boshqasining ichiga kira olmaydi
  • Signal olgan hujayra o'zi hal qiladi nima qilishni

Uch tamoyil:

  1. Xabar almashish (messaging) — asosiy narsa
  2. Lokal saqlash va himoya — ichkarisi to'liq yopiq
  3. Hamma narsani kech bog'lash (late binding)

"OOP menda faqat xabar almashish, lokal saqlash va himoya, va hamma narsani kech bog'lash degani edi. Buni Smalltalk va LISP da qilish mumkin. Boshqa tizimlar ham mumkindir, lekin men bilmayman."

Nima noto'g'ri ketdi:

C++ (1983) va Java (1995) OOP ni ommalashtirdi, lekin boshqa narsaga urg'u berdi:

Kay aytgan Sanoat oldi
Xabar almashish Metod chaqirish
Kech bog'lash Erta bog'lash, statik turlar
Hujayra kabi mustaqillik Meros ierarxiyasi
Obyekt — jarayon Obyekt — ma'lumot idishi

Farq nimada?

python
# Metod chaqirish (sanoat OOP)
obyekt.metod(arg)
# → kompilyator/interpretator metod BORLIGINI biladi
# → yo'q bo'lsa xato

# Xabar yuborish (Kay ning g'oyasi)
obyekt.xabar_qabul_qil("metod", arg)
# → obyekt O'ZI hal qiladi nima qilishni
# → tushunmasa — o'zi javob beradi, tizim yiqilmaydi

Smalltalk da doesNotUnderstand: bor edi — obyekt tanimagan xabarni o'zi qayta ishlaydi.

Pythonda bu g'oyaning izlari bor:

python
class Dinamik:
    def __getattr__(self, nom):
        """⭐ Bu — 'doesNotUnderstand:' ning Python versiyasi."""
        def ishlovchi(*args):
            return f"Xabar '{nom}' qabul qilindi: {args}"
        return ishlovchi

d = Dinamik()
d.hech_qachon_yozilmagan_metod(1, 2)
# 'Xabar 'hech_qachon_yozilmagan_metod' qabul qilindi: (1, 2)'

Bu — kech bog'lash. ORM lar (user.filter_by_email()), RPC mijozlari, mock obyektlar shunday ishlaydi.

Meros — Kay aytmagan narsa

Sanoat OOP merosga eng ko'p urg'u berdi. Natija:

  • Chuqur ierarxiyalar
  • Mo'rt asosiy sinf muammosi
  • "Kvadrat — Togriturtburchakmi?" (Liskov muammosi)
  • AbstractSingletonProxyFactoryBean

Kay merosni umuman ta'kidlamagan. Uning uchun muhimi — obyektlar bir-birining ichini bilmasligi edi.

Zamonaviy tasdiq:

Kay ning g'oyasi qayerda tirik qoldi?

Texnologiya Kay ning qaysi g'oyasi
Mikroservislar Mustaqil, xabar (HTTP/queue) orqali muloqot
Erlang/Elixir aktyorlari Aynan xabar almashish, umumiy holat yo'q
React komponentlari Lokal holat, props orqali muloqot
Docker konteynerlari To'liq izolyatsiya, tarmoq orqali

Joe Armstrong (Erlang):

"Erlang — yagona to'g'ri OOP tili bo'lsa kerak."

Chunki Erlang da aktyorlar umumiy xotirasiz, faqat xabar orqali gaplashadi — Kay ning modeliga eng yaqin.

Amaliy xulosa Python uchun:

  1. Interfeysga tayaning, ichki tuzilmaga emas — Protocol, ABC
  2. Merosdan ko'ra kompozitsiya — obyektlarni birlashtiring
  3. Kech bog'lash — foydali — __getattr__, duck typing
  4. Kichik, mustaqil obyektlar — chuqur ierarxiyadan yaxshi
python
# ⚠️ Sanoat OOP — chuqur ierarxiya
class Hayvon: ...
class Sutemizuvchi(Hayvon): ...
class Yirtqich(Sutemizuvchi): ...
class Mushuksimon(Yirtqich): ...
class Sher(Mushuksimon): ...

# ✅ Kay ga yaqin — mustaqil qismlar
@dataclass
class Hayvon:
    nom: str
    ovqatlanish: Ovqatlanish        # alohida obyekt
    harakat: Harakat                # alohida obyekt
    ovoz: Ovoz                      # alohida obyekt

Kay ning uyalishi — atama muvaffaqiyatli bo'lgani, lekin noto'g'ri qism ommalashgani uchun edi.

Nimani mustahkamlaydi: 2.2, 2.5, 2.7-bo'limlar.


Xulosa

Bu darsda OOP ning mohiyatini o'rgandik.

Eng muhim uch fikr:

  1. OOP — ma'lumot va uni o'zgartiruvchi kodni birlashtirish. Buning natijasi — invariant: sinf tashqarisidagi kod obyektni noto'g'ri holatga keltira olmaydi. Kapsulatsiya, abstraksiya, meros va polimorfizm shunga xizmat qiladi.

  2. Pythonda hamma narsa obyekt — sonlar, satrlar, funksiyalar, hatto sinflar va type ning o'zi. 42 ning metodlari bor, int ni o'zgaruvchiga solish mumkin, sinfni ish vaqtida yaratsa bo'ladi. Siz OOP dan birinchi darsdan beri foydalanyapsiz.

  3. OOP — ixtiyoriy vosita. Bitta metodli sinf — funksiya bo'lishi kerak, faqat ma'lumot bo'lsa — dataclass. Sinf invariant, xatti-harakat va holat birga bo'lganda o'rinli. Pythonda paradigmalarni aralashtirish — kuch, kamchilik emas.

Keyingi darsda sinf va obyektni amalda yozamiz: class sintaksisi, nusxa yaratish, atributlar va ular xotirada qanday saqlanishi.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
8.1-dars: OOP nima va nega kerak — IlmHamroh