Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Uch savol
- 2.2. Kompozitsiyaning oltita naqshi
- 2.3. Kombinatsiya portlashi
- 2.4. Uzatish usullari
- 2.5. Meros qachon to'g'ri
- 2.6. Solishtirish
- 2.7. Amaliy qaror daraxti
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Ikki yondashuv yonma-yon
- Misol 2 — Kombinatsiya portlashi
- Misol 3 — Uzatish naqshlari
- Misol 4 — Amaliy: hujjat tizimi (8-qism yakuni)
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
- 8-QISM YAKUNI
8.20-dars: Kompozitsiya vs meros
8-QISM — OBYEKTGA YO'NALTIRILGAN DASTURLASH · 20-dars · 8-QISM YAKUNI
1. Kirish va motivatsiya
Bir vazifa, ikki yechim:
# Meros
class Stack(list):
def push(self, x): self.append(x)
s = Stack()
s.push(1)
s.append(2) # ⚠️ ruxsat berildi
s.insert(0, 3) # ⚠️ stack'ning ma'nosi buzildi
s[0] = 99 # ⚠️
s.sort() # ⚠️
len(dir(s)) # 46 metod — 40 tasi keraksiz# Kompozitsiya
class Stack:
def __init__(self): self._el = []
def push(self, x): self._el.append(x)
def pop(self): return self._el.pop()
def __len__(self): return len(self._el)
s = Stack()
s.push(1)
s.append(2) # ✅ AttributeError — stack'da append yo'q
len(dir(s)) # 8 metod — faqat kerakliMeros hamma narsani beradi; kompozitsiya faqat kerakni.
Bu darsda:
- "is-a" vs "has-a" — qaror mezoni
- Kompozitsiyaning oltita naqshi
- Kombinatsiya portlashi va uning yechimi
- Uzatish (delegation) va
__getattr__ - Qachon meros to'g'ri
- 8-qism yakuni — barcha bilimlarni bog'lash
2. Nazariya — chuqur tushuntirish
2.1. Uch savol
1. "X — bu Y mi?" (is-a)
class ValidationError(Exception): ... # ✅ "ValidationError — bu Exception"
class Admin(Foydalanuvchi): ... # ✅ "Admin — bu Foydalanuvchi"
class Mashina(Dvigatel): ... # ❌ "Mashina — bu Dvigatel"?2. "X da Y bormi?" (has-a)
class Mashina:
def __init__(self):
self.dvigatel = Dvigatel() # ✅ "mashinada dvigatel bor"3. "X ota-sinfning HAR metodini ma'noli qo'llaydimi?"
class Stack(list): ...
# list.sort() → stack uchun ma'nosizmi? ✅ ha
# list.insert() → ma'nosizmi? ✅ ha
# → MEROS NOTO'G'RIUchinchi savol — eng amaliy.
2.2. Kompozitsiyaning oltita naqshi
A) Oddiy egalik:
class Mashina:
def __init__(self):
self.dvigatel = Dvigatel()
self.gildiraklar = [Gildirak() for _ in range(4)]B) Strategiya (Strategy) — ish vaqtida almashtirish:
class Saralovchi:
def __init__(self, algoritm):
self._algoritm = algoritm
def sarala(self, m):
return self._algoritm(m)
Saralovchi(sorted)
Saralovchi(mening_saralashim) # ⭐ ish vaqtida almashtirildiC) Uzatish (delegation) — tanlangan metodlar:
class Stack:
def __init__(self):
self._el = []
def push(self, x): self._el.append(x) # ⭐ uzatiladi
def pop(self): return self._el.pop()
def __len__(self): return len(self._el)
# ⭐ sort, insert, __setitem__ — YO'QD) Bezak (Decorator) — qatlam qo'shish:
class KeshlanganOmbor:
def __init__(self, ichki: Ombor):
self._ichki = ichki
self._kesh = {}
def olish(self, k):
if k not in self._kesh:
self._kesh[k] = self._ichki.olish(k)
return self._kesh[k]E) Adapter — interfeysni moslashtirish:
class EskiAdapter(YangiInterfeys):
def __init__(self, eski):
self._eski = eski
def yangi_metod(self, x):
return self._eski.eski_metod(x) # ⭐ moslashtirildiF) Fasad (Facade) — murakkablikni yashirish:
class Kutubxona:
def __init__(self):
self._db = Baza()
self._kesh = Kesh()
self._jurnal = Jurnal()
def kitob_top(self, isbn): # ⭐ oddiy interfeys
...2.3. Kombinatsiya portlashi
Meros bilan:
class Jonzot: ...
class Uchuvchi(Jonzot): ...
class Suzuvchi(Jonzot): ...
class UchuvchiVaSuzuvchi(Uchuvchi, Suzuvchi): ...
class Zaharli(Jonzot): ...
class ZaharliUchuvchi(Zaharli, Uchuvchi): ...
class ZaharliSuzuvchi(Zaharli, Suzuvchi): ...
class ZaharliUchuvchiVaSuzuvchi(...): ...n xususiyat → 2ⁿ sinf. 10 xususiyat = 1024 sinf.
Kompozitsiya bilan:
@dataclass
class Jonzot:
harakat: list[Harakat]
hujum: Hujum
himoya: Himoya
burgut = Jonzot([Uchish()], Tirnoq(), Patlar())
ilon = Jonzot([Suralish()], Zahar(), Tangalar())
ajdaho = Jonzot([Uchish(), Suzish()], Zahar(), Tangalar())n xususiyat → n sinf. Yangi kombinatsiya — yangi obyekt, yangi sinf emas.
2.4. Uzatish usullari
A) Qo'lda (aniq, tavsiya):
class Stack:
def push(self, x): self._el.append(x)
def pop(self): return self._el.pop() Aniq, IDE tushunadi, mypy tekshiradi.
B) __getattr__ (avtomatik, ehtiyot):
class Oram:
def __init__(self, ichki):
self._ichki = ichki
def __getattr__(self, nom):
return getattr(self._ichki, nom) # ⚠️ HAMMASINI uzatadiMuammolar:
- Dunder metodlar uzatilmaydi (
len(),+,[]) - IDE va
mypybilmaydi - Xato nomlar ham uzatiladi
- Nosozlikni topish qiyin
C) Dinamik yaratish:
def uzat(*nomlar):
def dekorator(cls):
for nom in nomlar:
setattr(cls, nom, _uzatuvchi_yasa(nom))
return cls
return dekorator
@uzat("append", "pop", "__len__")
class Stack: ...Dunder metodlarni ham qamraydi.
2.5. Meros qachon to'g'ri
Beshta holat:
# 1. Haqiqiy "is-a" + bir xil shartnoma
class ValidationError(Exception): ...
# 2. Abstrakt interfeys (ABC/Protocol)
class FaylOmbor(Ombor): ...
# 3. Framework kengaytirish nuqtalari
class MeningKorinishim(django.views.View): ...
class MeningTestim(unittest.TestCase): ...
# 4. Mixin — bitta aniq imkoniyat
class Model(JsonMixin, TenglikMixin, Asos): ...
# 5. Til konstruktsiyalari
class Rang(Enum): ...
@dataclass
class Nuqta: ...
class Nuqta(NamedTuple): ...Naqsh: meros interfeys uchun, kompozitsiya amalga oshirish uchun.
2.6. Solishtirish
| Mezon | Meros | Kompozitsiya |
|---|---|---|
| Bog'lanish | Eng kuchli | Kuchsiz |
| Ish vaqtida o'zgartirish | ||
| Kombinatsiyalar | 2ⁿ sinf | n sinf |
| Kod hajmi | Kam | Ko'proq |
isinstance |
(yoki Protocol) |
|
| Testlash | patch |
Konstruktorga uzatish |
| Ota-sinf o'zgarishi | Buzadi | API bir xil qolsa — yo'q |
| "Bu metod qayerdan?" | MRO qidiruv | Aniq |
2.7. Amaliy qaror daraxti
1. "X — bu Y mi?" — mantiqan to'g'rimi?
❌ → KOMPOZITSIYA
2. Y ning HAR metodi X uchun ma'nolimi?
❌ → KOMPOZITSIYA
3. Ish vaqtida almashtirish kerakmi?
✅ → KOMPOZITSIYA (strategiya)
4. Bir necha mustaqil o'lcham bormi?
✅ → KOMPOZITSIYA
5. Y — abstrakt interfeysmi (ABC/Protocol)?
✅ → MEROS
6. Y — framework kengaytirish nuqtasimi?
✅ → MEROS
7. Y — bitta imkoniyat qo'shadigan mixinmi?
✅ → MEROS
8. Aks holda → KOMPOZITSIYA (sukut)3. Tez ma'lumotnoma
Uch savol
1. "X — bu Y mi?" → meros
2. "X da Y bormi?" → kompozitsiya
3. Y ning HAR metodi ma'nolimi? → yo'q bo'lsa kompozitsiyaKompozitsiya naqshlari
Egalik self.dvigatel = Dvigatel()
Strategiya self._algoritm = f ish vaqtida almashtiriladi
Uzatish def push(self, x): self._el.append(x)
Bezak self._ichki = Ombor() qatlam qo'shadi
Adapter eski → yangi interfeys
Fasad murakkablikni yashiradiKombinatsiya portlashi
Meros: n xususiyat → 2ⁿ sinf
Kompozitsiya: n xususiyat → n sinfMeros to'g'ri bo'lgan 5 holat
1. Haqiqiy "is-a" + bir xil shartnoma
2. ABC / Protocol
3. Framework kengaytirish nuqtasi
4. Mixin (bitta imkoniyat)
5. Enum, dataclass, NamedTuple4. Batafsil misollar
Misol 1 — Ikki yondashuv yonma-yon
"""Bir vazifa — meros va kompozitsiya."""
from __future__ import annotations
print("=== ⚠️ 1. list dan meros ===\n")
class StackMeros(list):
"""⚠️ list ning BARCHA metodlari meros olinadi."""
def push(self, x):
self.append(x)
def top(self):
if not self:
raise IndexError("Stack bo'sh")
return self[-1]
class StackKompozitsiya:
"""✅ Faqat KERAKLI metodlar."""
__slots__ = ("_el",)
def __init__(self, el=()):
self._el = list(el)
def push(self, x) -> None:
self._el.append(x)
def pop(self):
if not self._el:
raise IndexError("Stack bo'sh")
return self._el.pop()
def top(self):
if not self._el:
raise IndexError("Stack bo'sh")
return self._el[-1]
def __len__(self): return len(self._el)
def __bool__(self): return bool(self._el)
def __iter__(self): return reversed(self._el) # ⭐ LIFO tartibi
def __repr__(self): return f"Stack({self._el!r})"
sm, sk = StackMeros(), StackKompozitsiya()
for s in (sm, sk):
s.push(1); s.push(2); s.push(3)
print(f" StackMeros: {sm}")
print(f" StackKompozitsiya: {sk}\n")
print(f" Ommaviy metodlar soni:")
print(f" StackMeros: "
f"{len([m for m in dir(sm) if not m.startswith('_')])}")
print(f" StackKompozitsiya: "
f"{len([m for m in dir(sk) if not m.startswith('_')])}")
print(f"\n ⚠️ StackMeros da ma'nosiz amallar:")
BUZUVCHILAR = [
("sm.insert(0, 99)", lambda: sm.insert(0, 99)),
("sm.sort()", lambda: sm.sort()),
("sm[0] = 999", lambda: sm.__setitem__(0, 999)),
("sm.reverse()", lambda: sm.reverse()),
("sm.remove(2)", lambda: sm.remove(2)),
("del sm[0]", lambda: sm.__delitem__(0)),
("sm.extend([7, 8])", lambda: sm.extend([7, 8])),
]
for kod, f in BUZUVCHILAR:
try:
f()
n = f"⚠️ o'tdi → {list(sm)}"
except Exception as e:
n = f"✅ {type(e).__name__}"
print(f" {kod:<22} {n}")
print(f"\n ✅ StackKompozitsiya da:")
for kod, m in [("sk.insert(0, 99)", "insert"), ("sk.sort()", "sort"),
("sk[0] = 999", "__setitem__"),
("sk.extend([7])", "extend")]:
bor = hasattr(sk, m)
print(f" {kod:<22} {'⚠️ bor' if bor else '✅ AttributeError'}")
print(f"""
⭐ MEZON: "list ning HAR metodi Stack uchun ma'nolimi?"
append ✅ (lekin push nomi yaxshiroq)
pop ✅
insert ❌ stack o'rtasiga qo'shib bo'lmaydi
sort ❌ tartib — stack mohiyati
__setitem__ ❌
reverse ❌
→ Javob YO'Q → KOMPOZITSIYA
""")
print("=== ⭐ 2. LIFO tartibi ===\n")
sm2, sk2 = StackMeros(), StackKompozitsiya()
for s in (sm2, sk2):
s.push("a"); s.push("b"); s.push("c")
print(f" push: a, b, c\n")
print(f" list(StackMeros): {list(sm2)} ⚠️ FIFO")
print(f" list(StackKompozitsiya): {list(sk2)} ✅ LIFO")
print(f"\n for bilan:")
print(f" Meros: ", end="")
print(" → ".join(str(x) for x in sm2))
print(f" Kompozitsiya: ", end="")
print(" → ".join(str(x) for x in sk2))
print(f"""
⭐ Kompozitsiya bilan __iter__ ni STACK MANTIQIGA
moslashtira oldik. Meros bilan list.__iter__
meros olinadi va uni o'zgartirish CHALKASH bo'lardi.
""")
print("=== 3. Uchinchi variant: UserList ===\n")
from collections import UserList
class StackUser(UserList):
"""⚠️ Hali ham list interfeysi."""
def push(self, x): self.data.append(x)
su = StackUser()
su.push(1); su.push(2)
print(f" StackUser: {su}")
print(f" su.sort bor: {hasattr(su, 'sort')} ⚠️")
print(f" su.insert bor: {hasattr(su, 'insert')} ⚠️")
print(f"""
⚠️ UserList ham list interfeysini beradi —
faqat meros MUAMMOSINI (C metodlari) hal qiladi,
ORTIQCHA METODLAR muammosini emas.
⭐ UserList: dict/list ni KENGAYTIRISH uchun
Kompozitsiya: CHEKLASH uchun
""")
print("=== ✅ 4. Meros TO'G'RI bo'lgan holat ===\n")
from collections.abc import MutableSequence
class TekshirilganRoyxat(MutableSequence):
"""✅ Haqiqiy 'is-a' — ro'yxat, lekin tekshiruv bilan."""
def __init__(self, tur: type, el=()):
self._tur = tur
self._el = []
self.extend(el)
def _tekshir(self, x):
if not isinstance(x, self._tur):
raise TypeError(
f"{self._tur.__name__} kutildi, "
f"{type(x).__name__} keldi"
)
return x
def __getitem__(self, i): return self._el[i]
def __len__(self): return len(self._el)
def __delitem__(self, i): del self._el[i]
def __setitem__(self, i, q):
if isinstance(i, slice):
self._el[i] = [self._tekshir(x) for x in q]
else:
self._el[i] = self._tekshir(q)
def insert(self, i, q):
self._el.insert(i, self._tekshir(q))
def __repr__(self):
return f"TekshirilganRoyxat({self._tur.__name__}, {self._el!r})"
t = TekshirilganRoyxat(int, [1, 2, 3])
print(f" {t}\n")
print(f" Barcha list metodlari ishlaydi:")
for kod, f in [
("t.append(4)", lambda: t.append(4)),
("t.insert(0, 0)", lambda: t.insert(0, 0)),
("t.extend([5,6])", lambda: t.extend([5, 6])),
("t[1] = 99", lambda: t.__setitem__(1, 99)),
("t.pop()", lambda: t.pop()),
("t.remove(99)", lambda: t.remove(99)),
("t.reverse()", lambda: t.reverse()),
("3 in t", lambda: 3 in t),
("t.index(2)", lambda: t.index(2)),
]:
natija = f()
korinish = f" → {natija!r}" if natija is not None else ""
print(f" {kod:<20}{korinish:<12} {list(t)}")
print(f"\n Tekshiruv:")
for kod, f in [
("t.append('matn')", lambda: t.append("matn")),
("t[0] = 3.14", lambda: t.__setitem__(0, 3.14)),
("t.insert(0, None)", lambda: t.insert(0, None)),
]:
try:
f(); n = "⚠️ o'tdi"
except TypeError as e:
n = f"✅ TypeError: {e}"
print(f" {kod:<22} {n}")
print(f"""
⭐ NEGA BU YERDA MEROS TO'G'RI:
1. "TekshirilganRoyxat — bu MutableSequence" ✅
2. HAR metod ma'noli (append, insert, sort, ...)
3. Shartnoma buzilmaydi (LSP ✅)
4. Faqat qo'shimcha tekshiruv qo'shildi
5. isinstance(t, MutableSequence) → True (foydali)
⚠️ Stack da esa metodlarning YARMI ma'nosiz edi.
""")
print(f" isinstance tekshiruvi:")
from collections.abc import Sequence
for nom, o in [("StackMeros", sm), ("StackKompozitsiya", sk),
("TekshirilganRoyxat", t)]:
print(f" {nom:<22} Sequence: {isinstance(o, Sequence)}")Natijaning muhim qismi:
=== ⚠️ 1. list dan meros ===
Ommaviy metodlar soni:
StackMeros: 13
StackKompozitsiya: 3
⚠️ StackMeros da ma'nosiz amallar:
sm.insert(0, 99) ⚠️ o'tdi → [99, 1, 2, 3]
sm.sort() ⚠️ o'tdi → [1, 2, 3, 99]
sm[0] = 999 ⚠️ o'tdi → [999, 2, 3, 99]
✅ StackKompozitsiya da:
sk.insert(0, 99) ✅ AttributeError
sk.sort() ✅ AttributeError
=== ⭐ 2. LIFO tartibi ===
list(StackMeros): ['a', 'b', 'c'] ⚠️ FIFO
list(StackKompozitsiya): ['c', 'b', 'a'] ✅ LIFO
=== ✅ 4. Meros TO'G'RI bo'lgan holat ===
t.append('matn') ✅ TypeError: int kutildi, str keldi
t[0] = 3.14 ✅ TypeError: int kutildi, float keldiNima ko'rsatdi: 2.1, 2.2, 2.5-bo'limlar.
Misol 2 — Kombinatsiya portlashi
"""n xususiyat: 2ⁿ sinf vs n sinf."""
from __future__ import annotations
import itertools
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
print("=== ⚠️ 1. Meros bilan portlash ===\n")
class Jonzot:
def __init__(self, nom): self.nom = nom
def tavsif(self): return self.nom
class Uchuvchi(Jonzot):
def uch(self): return f"{self.nom} uchdi"
def tavsif(self): return f"{super().tavsif()} (uchadi)"
class Suzuvchi(Jonzot):
def suz(self): return f"{self.nom} suzdi"
def tavsif(self): return f"{super().tavsif()} (suzadi)"
class Zaharli(Jonzot):
def zahar(self): return f"{self.nom} zaharladi"
def tavsif(self): return f"{super().tavsif()} (zaharli)"
class UchuvchiSuzuvchi(Uchuvchi, Suzuvchi): pass
class ZaharliUchuvchi(Zaharli, Uchuvchi): pass
class ZaharliSuzuvchi(Zaharli, Suzuvchi): pass
class ZaharliUchuvchiSuzuvchi(Zaharli, Uchuvchi, Suzuvchi): pass
SINFLAR = [Jonzot, Uchuvchi, Suzuvchi, Zaharli, UchuvchiSuzuvchi,
ZaharliUchuvchi, ZaharliSuzuvchi, ZaharliUchuvchiSuzuvchi]
print(f" 3 xususiyat → {len(SINFLAR)} sinf\n")
for S in SINFLAR:
print(f" {S.__name__}")
print(f"\n ⚠️ Formula: n xususiyat → 2ⁿ sinf\n")
print(f" {'Xususiyatlar':<16} {'Sinflar':<12} {'Izoh'}")
print(" " + "─" * 46)
for n in range(1, 11):
sinflar = 2 ** n
izoh = ("" if sinflar < 16 else
"⚠️ ko'p" if sinflar < 128 else "❌ boshqarib bo'lmaydi")
print(f" {n:<16} {sinflar:<12} {izoh}")
print(f"\n Yangi xususiyat qo'shsak (masalan, 'Yuguruvchi'):")
print(f" Yana {len(SINFLAR)} ta sinf kerak bo'ladi → "
f"{len(SINFLAR) * 2} ta")
z = ZaharliUchuvchiSuzuvchi("Ajdaho")
print(f"\n ZaharliUchuvchiSuzuvchi('Ajdaho'):")
print(f" tavsif: {z.tavsif()}")
print(f" MRO: {' → '.join(c.__name__ for c in type(z).__mro__[:-1])}")
print("\n\n=== ✅ 2. Kompozitsiya ===\n")
class Harakat(ABC):
@abstractmethod
def harakatlan(self, nom: str) -> str: ...
@property
@abstractmethod
def tezlik(self) -> float: ...
class Uchish(Harakat):
def harakatlan(self, nom): return f"{nom} uchdi"
@property
def tezlik(self): return 50.0
class Suzish(Harakat):
def harakatlan(self, nom): return f"{nom} suzdi"
@property
def tezlik(self): return 15.0
class Yugurish(Harakat):
def harakatlan(self, nom): return f"{nom} yugurdi"
@property
def tezlik(self): return 30.0
class Suralish(Harakat):
def harakatlan(self, nom): return f"{nom} suralib bordi"
@property
def tezlik(self): return 5.0
class Hujum(ABC):
@abstractmethod
def hujum(self, nom: str) -> str: ...
@property
@abstractmethod
def zarar(self) -> int: ...
class Zahar(Hujum):
def hujum(self, nom): return f"{nom} zaharladi"
@property
def zarar(self): return 30
class Tish(Hujum):
def hujum(self, nom): return f"{nom} tishladi"
@property
def zarar(self): return 20
class Tirnoq(Hujum):
def hujum(self, nom): return f"{nom} tirnadi"
@property
def zarar(self): return 15
class HujumYoq(Hujum):
def hujum(self, nom): return f"{nom} qochdi"
@property
def zarar(self): return 0
@dataclass
class Jonzot2:
"""⭐ Xususiyatlar — MAYDONLAR, sinflar emas."""
nom: str
harakatlar: list[Harakat] = field(default_factory=list)
hujum_usuli: Hujum = field(default_factory=HujumYoq)
jon: int = 100
def harakatlan(self) -> list[str]:
return [h.harakatlan(self.nom) for h in self.harakatlar]
def hujum(self) -> str:
return self.hujum_usuli.hujum(self.nom)
@property
def maks_tezlik(self) -> float:
return max((h.tezlik for h in self.harakatlar), default=0.0)
@property
def zarar(self) -> int:
return self.hujum_usuli.zarar
def tavsif(self) -> str:
xus = [type(h).__name__.lower() for h in self.harakatlar]
xus.append(type(self.hujum_usuli).__name__.lower())
return f"{self.nom} ({', '.join(xus)})"
JONZOTLAR = [
Jonzot2("Burgut", [Uchish()], Tirnoq()),
Jonzot2("Ilon", [Suralish()], Zahar()),
Jonzot2("Ajdaho", [Uchish(), Suzish(), Yugurish()], Zahar(), jon=500),
Jonzot2("Quyon", [Yugurish()], HujumYoq(), jon=30),
Jonzot2("O'rdak", [Uchish(), Suzish(), Yugurish()], Tish()),
Jonzot2("Akula", [Suzish()], Tish(), jon=200),
]
print(f" Sinflar soni:")
print(f" Harakat turlari: 4 (Uchish, Suzish, Yugurish, Suralish)")
print(f" Hujum turlari: 4 (Zahar, Tish, Tirnoq, HujumYoq)")
print(f" Jonzot: 1")
print(f" ⭐ JAMI: 9 sinf\n")
print(f" {'Jonzot':<32} {'Tezlik':>8} {'Zarar':>7} {'Jon'}")
print(" " + "─" * 58)
for j in JONZOTLAR:
print(f" {j.tavsif():<32} {j.maks_tezlik:>8.0f} "
f"{j.zarar:>7} {j.jon:>5}")
print(f"\n Amallar:")
for j in JONZOTLAR[:3]:
print(f" {j.nom}:")
for h in j.harakatlan():
print(f" {h}")
print(f" {j.hujum()}")
print(f"""
⭐ MUMKIN BO'LGAN KOMBINATSIYALAR:
Harakatlar: 2^4 - 1 = 15 (bo'sh bo'lmagan to'plamlar)
Hujumlar: 4
⭐ JAMI: 15 × 4 = 60 xil jonzot — 9 SINF bilan
⚠️ Meros bilan: 60 sinf kerak bo'lardi
""")
print(f" Barcha kombinatsiyalar (birinchi 8 tasi):")
HARAKATLAR = [Uchish, Suzish, Yugurish, Suralish]
HUJUMLAR = [Zahar, Tish, Tirnoq, HujumYoq]
kombinatsiyalar = []
for n in range(1, 3):
for h_kombo in itertools.combinations(HARAKATLAR, n):
for hujum in HUJUMLAR:
kombinatsiyalar.append((h_kombo, hujum))
for h_kombo, hujum in kombinatsiyalar[:8]:
j = Jonzot2("Test", [H() for H in h_kombo], hujum())
xus = "+".join(H.__name__ for H in h_kombo)
print(f" {xus:<24} {hujum.__name__:<12} "
f"tezlik={j.maks_tezlik:.0f}, zarar={j.zarar}")
print(f"\n ⭐ Jami mumkin: {len(kombinatsiyalar)}+ kombinatsiya")
print("\n\n=== ⭐ 3. Ish vaqtida o'zgartirish ===\n")
j = Jonzot2("Kuchukcha", [Yugurish()], Tish(), jon=50)
print(f" Boshida: {j.tavsif()}, tezlik={j.maks_tezlik}")
j.harakatlar.append(Suzish())
print(f"\n Suzishni o'rgandi:")
print(f" {j.tavsif()}")
for h in j.harakatlan():
print(f" {h}")
j.hujum_usuli = Zahar()
print(f"\n Zaharli bo'ldi:")
print(f" {j.tavsif()}, zarar={j.zarar}")
j.harakatlar = [Uchish()]
print(f"\n Faqat uchadigan bo'ldi:")
print(f" {j.tavsif()}, tezlik={j.maks_tezlik}")
print(f"""
⚠️ MEROS bilan bu MUMKIN EMAS:
obyekt yaratilgandan keyin sinfini o'zgartirib bo'lmaydi
(__class__ ni o'zgartirish — xavfli hack)
✅ KOMPOZITSIYA bilan — oddiy atribut o'zgarishi
""")
print("=== 4. Yangi xususiyat qo'shish ===\n")
class Kovlash(Harakat):
"""⭐ Yangi harakat — MAVJUD KOD O'ZGARMAYDI."""
def harakatlan(self, nom): return f"{nom} yer kovladi"
@property
def tezlik(self): return 2.0
class Otashnafas(Hujum):
"""⭐ Yangi hujum."""
def hujum(self, nom): return f"{nom} olov purkadi"
@property
def zarar(self): return 80
ajdaho = Jonzot2("Buyuk Ajdaho",
[Uchish(), Suzish(), Kovlash()],
Otashnafas(), jon=1000)
print(f" Ikki yangi sinf qo'shildi: Kovlash, Otashnafas\n")
print(f" {ajdaho.tavsif()}")
print(f" tezlik={ajdaho.maks_tezlik}, zarar={ajdaho.zarar}")
for h in ajdaho.harakatlan():
print(f" {h}")
print(f" {ajdaho.hujum()}")
print(f"""
⭐ QO'SHILDI: 2 sinf
⭐ O'ZGARDI: 0 qator mavjud kod
⭐ YANGI KOMBINATSIYALAR: 2^5 × 5 = 160
⚠️ Meros bilan: 60 → 160 sinf (100 ta yangi)
""")
print("=== 5. Jang simulyatsiyasi ===\n")
def jang(a: Jonzot2, b: Jonzot2, maks_raund: int = 20) -> str:
"""⭐ Aniq turlarni bilmaydi."""
ja, jb = a.jon, b.jon
# Tezroq birinchi hujum qiladi
if b.maks_tezlik > a.maks_tezlik:
a, b = b, a
ja, jb = jb, ja
for raund in range(1, maks_raund + 1):
jb -= a.zarar
if jb <= 0:
return f"{a.nom} g'alaba qozondi ({raund}-raund)"
ja -= b.zarar
if ja <= 0:
return f"{b.nom} g'alaba qozondi ({raund}-raund)"
return f"Durang ({maks_raund} raund)"
JANGLAR = [
(JONZOTLAR[0], JONZOTLAR[1]),
(JONZOTLAR[2], JONZOTLAR[5]),
(JONZOTLAR[3], JONZOTLAR[4]),
(ajdaho, JONZOTLAR[2]),
]
for a, b in JANGLAR:
print(f" {a.nom} (jon={a.jon}, zarar={a.zarar}) vs "
f"{b.nom} (jon={b.jon}, zarar={b.zarar})")
print(f" → {jang(a, b)}")Natijaning muhim qismi:
=== ⚠️ 1. Meros bilan portlash ===
3 xususiyat → 8 sinf
Xususiyatlar Sinflar Izoh
──────────────────────────────────────────────
3 8
5 32 ⚠️ ko'p
10 1024 ❌ boshqarib bo'lmaydi
=== ✅ 2. Kompozitsiya ===
Sinflar soni:
⭐ JAMI: 9 sinf
Jonzot Tezlik Zarar Jon
──────────────────────────────────────────────────────────
Ajdaho (uchish, suzish, ...) 50 30 500
Quyon (yugurish, hujumyoq) 30 0 30
⭐ JAMI: 15 × 4 = 60 xil jonzot — 9 SINF bilan
=== 4. Yangi xususiyat qo'shish ===
⭐ QO'SHILDI: 2 sinf
⭐ O'ZGARDI: 0 qator mavjud kod
⭐ YANGI KOMBINATSIYALAR: 2^5 × 5 = 160Nima ko'rsatdi: 2.2, 2.3-bo'limlar.
Misol 3 — Uzatish naqshlari
"""Kompozitsiyada metodlarni uzatish."""
from __future__ import annotations
import functools
from typing import Any, Callable
print("=== 1. Qo'lda uzatish (tavsiya) ===\n")
class Ombor:
"""Asos — barcha imkoniyatlar."""
def __init__(self):
self._d: dict[str, Any] = {}
def saqla(self, k: str, v: Any) -> None:
self._d[k] = v
def olish(self, k: str) -> Any:
return self._d[k]
def ochir(self, k: str) -> bool:
return self._d.pop(k, None) is not None
def kalitlar(self) -> list[str]:
return list(self._d)
def tozala(self) -> None:
self._d.clear()
def __len__(self): return len(self._d)
def __contains__(self, k): return k in self._d
class OqishOmbor:
"""⭐ FAQAT o'qish metodlari uzatiladi."""
__slots__ = ("_ichki",)
def __init__(self, ichki: Ombor):
self._ichki = ichki
# ⭐ Faqat kerakli metodlar
def olish(self, k: str) -> Any:
return self._ichki.olish(k)
def kalitlar(self) -> list[str]:
return self._ichki.kalitlar()
def __len__(self): return len(self._ichki)
def __contains__(self, k): return k in self._ichki
def __repr__(self):
return f"OqishOmbor({len(self)} element)"
o = Ombor()
o.saqla("a", 1)
o.saqla("b", 2)
oq = OqishOmbor(o)
print(f" Ombor: {sorted(o.kalitlar())}")
print(f" OqishOmbor: {oq}\n")
print(f" {'Amal':<24} {'Ombor':<12} {'OqishOmbor'}")
print(" " + "─" * 50)
for kod, f1, f2 in [
("olish('a')", lambda: o.olish("a"), lambda: oq.olish("a")),
("len()", lambda: len(o), lambda: len(oq)),
("'a' in x", lambda: "a" in o, lambda: "a" in oq),
("kalitlar()", lambda: sorted(o.kalitlar()),
lambda: sorted(oq.kalitlar())),
("saqla('c', 3)", lambda: o.saqla("c", 3), lambda: oq.saqla("c", 3)),
("ochir('a')", lambda: o.ochir("a"), lambda: oq.ochir("a")),
("tozala()", lambda: None, lambda: oq.tozala()),
]:
try:
r1 = repr(f1())
except Exception as e:
r1 = f"❌ {type(e).__name__}"
try:
r2 = repr(f2())
except AttributeError:
r2 = "✅ AttributeError"
print(f" {kod:<24} {r1:<12} {r2}")
print(f"""
⭐ AFZALLIKLARI:
• Aniq — qaysi metodlar bor, ko'rinadi
• IDE avtoto'ldirish ishlaydi
• mypy tekshiradi
• Yozish imkoniyati BUTUNLAY yo'q
⚠️ Kamchiligi: har metodni qo'lda yozish kerak
""")
print("=== ⚠️ 2. __getattr__ bilan avtomatik ===\n")
class AvtoOram:
"""⚠️ HAMMASINI uzatadi."""
def __init__(self, ichki):
self._ichki = ichki
def __getattr__(self, nom):
print(f" [__getattr__({nom!r})]")
return getattr(self._ichki, nom)
a = AvtoOram(o)
o.saqla("a", 1)
print(f" a.olish('a'):")
print(f" → {a.olish('a')}\n")
print(f" a.saqla('z', 99): ⚠️ ham uzatiladi")
a.saqla("z", 99)
print(f" Ombor: {sorted(o.kalitlar())}\n")
print(f" ⚠️ DUNDER METODLAR UZATILMAYDI:")
for kod, f in [
("len(a)", lambda: len(a)),
("'a' in a", lambda: "a" in a),
("a['a']", lambda: a["a"]),
]:
try:
n = f"⚠️ {f()!r}"
except TypeError as e:
n = f"❌ TypeError: {str(e)[:40]}"
print(f" {kod:<16} {n}")
print(f"""
⭐ SABAB: dunder metodlar TUR da qidiriladi,
nusxada emas (8.15-dars, maxsus metod qidiruvi):
len(x) → type(x).__len__(x)
⚠️ __getattr__ ga BORMAYDI
⚠️ BOSHQA MUAMMOLAR:
• IDE va mypy bilmaydi
• Xato nomlar ham uzatiladi (typo aniqlanmaydi)
• Nosozlikni topish qiyin
• Rekursiya xavfi (_ichki dan oldin)
""")
class XavfliOram:
"""⚠️ Rekursiya xavfi."""
def __init__(self, ichki):
self.ichki = ichki # ⚠️ __getattr__ dan oldin
def __getattr__(self, nom):
return getattr(self.ichki, nom) # ⚠️ ichki yo'q bo'lsa...
class XavfsizOram:
"""✅ object.__setattr__ bilan."""
def __init__(self, ichki):
object.__setattr__(self, "_ichki", ichki)
def __getattr__(self, nom):
if nom.startswith("_"):
raise AttributeError(nom) # ⭐ rekursiya himoyasi
return getattr(self._ichki, nom)
x = XavfsizOram(o)
print(f" XavfsizOram:")
print(f" x.olish('a') = {x.olish('a')}")
try:
x._mavjud_emas
except AttributeError as e:
print(f" x._mavjud_emas → ✅ AttributeError: {e}")
print("\n\n=== ⭐ 3. Dinamik uzatuvchi ===\n")
def uzat(ichki_nom: str, *metodlar: str):
"""⭐ Sinf dekoratori — dunder larni ham qamraydi."""
def uzatuvchi_yasa(nom: str):
def uzatuvchi(self, *args, **kwargs):
return getattr(getattr(self, ichki_nom), nom)(*args, **kwargs)
uzatuvchi.__name__ = nom
uzatuvchi.__qualname__ = nom
uzatuvchi.__doc__ = f"{ichki_nom}.{nom} ga uzatiladi."
return uzatuvchi
def dekorator(cls):
for nom in metodlar:
setattr(cls, nom, uzatuvchi_yasa(nom))
return cls
return dekorator
@uzat("_ichki", "olish", "kalitlar", "__len__", "__contains__")
class DinamikOqish:
"""⭐ Uzatiladigan metodlar dekoratorda ko'rinadi."""
__slots__ = ("_ichki",)
def __init__(self, ichki):
self._ichki = ichki
def __repr__(self):
return f"DinamikOqish({len(self)} element)"
d = DinamikOqish(o)
print(f" {d}\n")
for kod, f in [
("d.olish('a')", lambda: d.olish("a")),
("len(d)", lambda: len(d)),
("'a' in d", lambda: "a" in d),
("d.kalitlar()", lambda: sorted(d.kalitlar())),
("d.saqla('x', 1)", lambda: d.saqla("x", 1)),
("d.ochir('a')", lambda: d.ochir("a")),
]:
try:
n = f"✅ {f()!r}"
except AttributeError:
n = "✅ AttributeError (uzatilmagan)"
print(f" {kod:<20} {n}")
print(f"\n Hujjat:")
print(f" DinamikOqish.olish.__doc__ = "
f"{DinamikOqish.olish.__doc__!r}")
print(f"""
⭐ AFZALLIKLARI:
• Dunder metodlar ham uzatiladi
• Ro'yxat DEKORATORDA ko'rinadi
• Kod takrorlanmaydi
⚠️ Kamchiligi: mypy hali ham bilmaydi
""")
print("=== 4. Bezak (Decorator) naqshi ===\n")
class KeshlanganOmbor:
"""⭐ Mavjud omborga QATLAM qo'shadi."""
def __init__(self, ichki: Ombor, maks: int = 100):
self._ichki = ichki
self._kesh: dict[str, Any] = {}
self.maks = maks
self.urish = 0
self.otkazish = 0
def olish(self, k: str) -> Any:
if k in self._kesh:
self.urish += 1
return self._kesh[k]
self.otkazish += 1
v = self._ichki.olish(k)
if len(self._kesh) >= self.maks:
self._kesh.pop(next(iter(self._kesh)))
self._kesh[k] = v
return v
def saqla(self, k: str, v: Any) -> None:
self._ichki.saqla(k, v)
self._kesh[k] = v # ⭐ keshni yangilaydi
def ochir(self, k: str) -> bool:
self._kesh.pop(k, None)
return self._ichki.ochir(k)
def kalitlar(self): return self._ichki.kalitlar()
def __len__(self): return len(self._ichki)
def __contains__(self, k): return k in self._ichki
def statistika(self):
jami = self.urish + self.otkazish
return {"kesh": len(self._kesh), "urish": self.urish,
"otkazish": self.otkazish,
"nisbat": f"{self.urish / jami:.0%}" if jami else "—"}
class JurnalliOmbor:
"""⭐ Yana bir qatlam."""
def __init__(self, ichki):
self._ichki = ichki
self.jurnal: list[str] = []
def olish(self, k):
self.jurnal.append(f"OLISH {k}")
return self._ichki.olish(k)
def saqla(self, k, v):
self.jurnal.append(f"SAQLA {k}")
self._ichki.saqla(k, v)
def ochir(self, k):
self.jurnal.append(f"OCHIR {k}")
return self._ichki.ochir(k)
def kalitlar(self): return self._ichki.kalitlar()
def __len__(self): return len(self._ichki)
def __contains__(self, k): return k in self._ichki
asos = Ombor()
asos.saqla("a", 1)
asos.saqla("b", 2)
# ⭐ Qatlamlarni ISTALGAN tartibda ulash
kesh = KeshlanganOmbor(asos)
toliq = JurnalliOmbor(kesh)
print(f" Qatlamlar: JurnalliOmbor(KeshlanganOmbor(Ombor))\n")
for k in ["a", "b", "a", "a", "b"]:
toliq.olish(k)
print(f" 5 ta o'qish (a, b, a, a, b):")
print(f" Kesh: {kesh.statistika()}")
print(f" Jurnal: {toliq.jurnal}")
print(f"\n ⭐ Tartibni o'zgartirish:")
kesh2 = KeshlanganOmbor(JurnalliOmbor(asos))
for k in ["a", "a", "a"]:
kesh2.olish(k)
print(f" KeshlanganOmbor(JurnalliOmbor(Ombor)):")
print(f" Jurnal: {kesh2._ichki.jurnal} "
f"⭐ faqat 1 marta (kesh to'sdi)")
print(f"""
⭐ BEZAK NAQSHI:
• Har qatlam bir mas'uliyat
• Istalgan tartibda ulanadi
• Tartib xatti-harakatni o'zgartiradi
• Meros bilan bu MUMKIN EMAS (sinf tartibi qotgan)
""")
print("=== 5. Strategiya naqshi ===\n")
class Saralovchi:
"""⭐ Algoritm — ish vaqtida almashtiriladi."""
def __init__(self, algoritm: Callable[[list], list] | None = None):
self.algoritm = algoritm or sorted
self.chaqiruvlar = 0
def sarala(self, m: list) -> list:
self.chaqiruvlar += 1
return self.algoritm(m)
def pufakcha(m: list) -> list:
m = list(m)
for i in range(len(m)):
for j in range(len(m) - i - 1):
if m[j] > m[j + 1]:
m[j], m[j + 1] = m[j + 1], m[j]
return m
def teskari(m: list) -> list:
return sorted(m, reverse=True)
def uzunlik_boyicha(m: list) -> list:
return sorted(m, key=lambda x: (len(str(x)), str(x)))
MALUMOT = [100, 5, 33, 2, 999, 7]
s = Saralovchi()
print(f" Kirish: {MALUMOT}\n")
for nom, alg in [("sorted (sukut)", None), ("pufakcha", pufakcha),
("teskari", teskari),
("uzunlik bo'yicha", uzunlik_boyicha),
("lambda", lambda m: sorted(m, key=lambda x: -x % 10))]:
if alg:
s.algoritm = alg # ⭐ ish vaqtida
print(f" {nom:<20} {s.sarala(MALUMOT)}")
print(f"\n Chaqiruvlar: {s.chaqiruvlar}")
print(f"""
⭐ MEROS BILAN:
class SaralovchiSorted(Saralovchi): ...
class SaralovchiPufakcha(Saralovchi): ...
class SaralovchiTeskari(Saralovchi): ...
⚠️ Har algoritm uchun sinf, ish vaqtida almashtirib bo'lmaydi
✅ KOMPOZITSIYA:
• Bitta sinf
• Funksiya ham, obyekt ham bo'lishi mumkin
• Ish vaqtida almashtiriladi
• Test qilish oson (soxta algoritm)
""")Natijaning muhim qismi:
=== 1. Qo'lda uzatish (tavsiya) ===
Amal Ombor OqishOmbor
──────────────────────────────────────────────────
olish('a') 1 1
len() 2 2
saqla('c', 3) None ✅ AttributeError
tozala() None ✅ AttributeError
=== ⚠️ 2. __getattr__ bilan avtomatik ===
⚠️ DUNDER METODLAR UZATILMAYDI:
len(a) ❌ TypeError: object of type 'AvtoOram' has no len()
a['a'] ❌ TypeError: 'AvtoOram' object is not subscriptable
=== 4. Bezak (Decorator) naqshi ===
5 ta o'qish (a, b, a, a, b):
Kesh: {'kesh': 2, 'urish': 3, 'otkazish': 2, 'nisbat': '60%'}
⭐ Tartibni o'zgartirish:
Jurnal: ['OLISH a'] ⭐ faqat 1 marta (kesh to'sdi)Nima ko'rsatdi: 2.2, 2.4-bo'limlar.
Misol 4 — Amaliy: hujjat tizimi (8-qism yakuni)
"""8-qismning barcha tushunchalari bir loyihada."""
from __future__ import annotations
import inspect
import json
import re
from abc import ABC, abstractmethod
from collections.abc import Sequence
from dataclasses import dataclass, field, replace
from datetime import datetime
from enum import Enum
from functools import cached_property
from typing import Any, ClassVar, Iterator, Protocol, runtime_checkable
print("=== HUJJAT TIZIMI ===\n")
# ═══ 1. ENUM 8.17-bob ═══
class Holat(str, Enum):
QORALAMA = "qoralama"
KORIB_CHIQISHDA = "korib_chiqishda"
NASHR = "nashr"
ARXIV = "arxiv"
def __str__(self): return self.value
# ═══ 2. FROZEN DATACLASS (8.17, 8.19) ═══
@dataclass(frozen=True, slots=True, order=True)
class Versiya:
"""⭐ Meros: dataclass — is-a Versiya."""
katta: int
kichik: int = 0
def keyingi(self, katta: bool = False) -> "Versiya":
return (Versiya(self.katta + 1, 0) if katta
else Versiya(self.katta, self.kichik + 1))
def __str__(self): return f"v{self.katta}.{self.kichik}"
# ═══ 3. PROTOCOL (8.9, 8.18) ═══
@runtime_checkable
class Formatlagich(Protocol):
"""⭐ Tashqi sinflar meros olmasdan mos keladi."""
def formatla(self, matn: str) -> str: ...
@runtime_checkable
class Tekshiruvchi(Protocol):
def tekshir(self, hujjat: "Hujjat") -> list[str]: ...
# ═══ 4. ABC 8.18-bob ═══
class Eksportchi(ABC):
"""⭐ Meros: to'g'ri — har avlod haqiqiy eksportchi."""
KENGAYTMA: ClassVar[str] = ".txt"
MIME: ClassVar[str] = "text/plain"
_royxat: ClassVar[dict[str, type["Eksportchi"]]] = {}
def __init_subclass__(cls, **kw):
super().__init_subclass__(**kw)
# ⚠️ cls.__abstractmethods__ bu yerda hali YO'Q — ABCMeta uni
# __init_subclass__ ishlagandan KEYIN o'rnatadi. inspect.isabstract
# aynan shu holatda abstrakt metodlarni qo'lda tekshiradi.
if not inspect.isabstract(cls): # ⭐ faqat to'liq sinflar
Eksportchi._royxat[cls.KENGAYTMA.lstrip(".")] = cls
@abstractmethod
def _tana(self, hujjat: "Hujjat") -> str:
"""Hujjat tanasini formatlaydi."""
def eksport(self, hujjat: "Hujjat") -> str:
"""⭐ Shablon metod — tartib belgilangan."""
qismlar = [self._sarlavha(hujjat), self._tana(hujjat)]
ostki = self._ostki(hujjat)
if ostki:
qismlar.append(ostki)
return "\n\n".join(q for q in qismlar if q)
def _sarlavha(self, hujjat: "Hujjat") -> str:
return hujjat.sarlavha
def _ostki(self, hujjat: "Hujjat") -> str:
return f"— {hujjat.muallif}, {hujjat.versiya}"
@classmethod
def yarat(cls, kengaytma: str) -> "Eksportchi":
k = kengaytma.lstrip(".")
if k not in cls._royxat:
raise KeyError(
f"Noma'lum format: {k!r}. Mavjud: {sorted(cls._royxat)}"
)
return cls._royxat[k]()
@classmethod
def mavjudlar(cls) -> list[str]:
return sorted(cls._royxat)
class MatnEksportchi(Eksportchi):
KENGAYTMA = ".txt"
def _sarlavha(self, h):
return f"{h.sarlavha}\n{'=' * len(h.sarlavha)}"
def _tana(self, h): return h.matn
class MarkdownEksportchi(Eksportchi):
KENGAYTMA = ".md"
MIME = "text/markdown"
def _sarlavha(self, h): return f"# {h.sarlavha}"
def _tana(self, h):
teglar = " ".join(f"`{t}`" for t in h.teglar)
return f"{teglar}\n\n{h.matn}" if teglar else h.matn
def _ostki(self, h):
return f"---\n*{h.muallif}* · {h.versiya} · {h.holat}"
class JsonEksportchi(Eksportchi):
KENGAYTMA = ".json"
MIME = "application/json"
def _sarlavha(self, h): return ""
def _ostki(self, h): return ""
def _tana(self, h):
return json.dumps({
"sarlavha": h.sarlavha,
"matn": h.matn,
"muallif": h.muallif,
"versiya": str(h.versiya),
"holat": str(h.holat),
"teglar": sorted(h.teglar),
"statistika": h.statistika,
}, ensure_ascii=False, indent=2)
# ═══ 5. ASOSIY SINF (8.3, 8.10, 8.11, 8.15) ═══
class Hujjat:
"""Bitta hujjat.
KOMPOZITSIYA:
• formatlagichlar — ish vaqtida almashtiriladi
• tekshiruvchilar — ro'yxatga qo'shiladi
• eksportchi — kerak bo'lganda yaratiladi
MEROS: yo'q — Hujjat hech narsaning avlodi emas.
"""
MAKS_SARLAVHA: ClassVar[int] = 200
def __init__(self, sarlavha: str, matn: str = "",
muallif: str = "", *,
formatlagichlar: list[Formatlagich] | None = None,
tekshiruvchilar: list[Tekshiruvchi] | None = None):
self._sarlavha = ""
self.sarlavha = sarlavha # ⭐ setter tekshiradi
self._matn = matn
self.muallif = muallif
self._versiya = Versiya(1, 0)
self._holat = Holat.QORALAMA
self._teglar: set[str] = set()
self._tarix: list[tuple[datetime, str]] = [
(datetime.now(), "yaratildi")
]
# ⭐ KOMPOZITSIYA — ish vaqtida almashtiriladi
self.formatlagichlar = list(formatlagichlar or [])
self.tekshiruvchilar = list(tekshiruvchilar or [])
# ── @property 8.15-bob ──
@property
def sarlavha(self) -> str:
return self._sarlavha
@sarlavha.setter
def sarlavha(self, q: str) -> None:
q = q.strip()
if not q:
raise ValueError("Sarlavha bo'sh bo'lmasin")
if len(q) > self.MAKS_SARLAVHA:
raise ValueError(f"Sarlavha {self.MAKS_SARLAVHA} belgidan uzun")
self._sarlavha = q
@property
def matn(self) -> str:
"""⭐ Formatlagichlar QATLAMI qo'llanadi."""
natija = self._matn
for f in self.formatlagichlar:
natija = f.formatla(natija)
return natija
@matn.setter
def matn(self, q: str) -> None:
self._matn = q
self._versiya = self._versiya.keyingi()
self._tarix.append((datetime.now(), "matn o'zgardi"))
self.__dict__.pop("statistika", None) # ⭐ keshni bekor qilish
@property
def xom_matn(self) -> str:
return self._matn
@property
def versiya(self) -> Versiya: return self._versiya
@property
def holat(self) -> Holat: return self._holat
@property
def teglar(self) -> frozenset[str]:
return frozenset(self._teglar) # ⭐ himoyalangan
@property
def tarix(self) -> tuple[tuple[datetime, str], ...]:
return tuple(self._tarix)
@cached_property
def statistika(self) -> dict[str, int]:
"""⭐ Qimmat hisoblash — keshlanadi."""
sozlar = re.findall(r"[^\W\d_]+", self._matn.lower())
return {
"belgilar": len(self._matn),
"sozlar": len(sozlar),
"noyob": len(set(sozlar)),
"qatorlar": self._matn.count("\n") + 1 if self._matn else 0,
}
# ── Amallar ──
def teg_qosh(self, *teglar: str) -> "Hujjat":
for t in teglar:
t = re.sub(r"[^\w-]", "", t.strip().lower())
if t:
self._teglar.add(t)
return self # ⭐ zanjir
def holat_ozgartir(self, yangi: Holat) -> "Hujjat":
OTISHLAR = {
Holat.QORALAMA: {Holat.KORIB_CHIQISHDA, Holat.ARXIV},
Holat.KORIB_CHIQISHDA: {Holat.NASHR, Holat.QORALAMA},
Holat.NASHR: {Holat.ARXIV},
Holat.ARXIV: {Holat.QORALAMA},
}
if yangi not in OTISHLAR[self._holat]:
raise ValueError(
f"{self._holat} → {yangi} mumkin emas. "
f"Ruxsat: {sorted(str(h) for h in OTISHLAR[self._holat])}"
)
if yangi == Holat.NASHR:
xatolar = self.tekshir()
if xatolar:
raise ValueError(f"Nashrdan oldin: {xatolar}")
self._tarix.append((datetime.now(), f"{self._holat} → {yangi}"))
self._holat = yangi
return self
def tekshir(self) -> list[str]:
"""⭐ Barcha tekshiruvchilarni ishga soladi."""
xatolar = []
for t in self.tekshiruvchilar:
xatolar.extend(t.tekshir(self))
return xatolar
def eksport(self, format: str = "txt") -> str:
return Eksportchi.yarat(format).eksport(self)
# ── Dunder (8.11-8.14) ──
def __repr__(self):
return (f"Hujjat({self._sarlavha!r}, {self._versiya}, "
f"{self._holat}, {len(self._teglar)} teg)")
def __str__(self):
return f"{self._sarlavha} ({self._versiya}, {self._holat})"
def __len__(self): return len(self._matn)
def __bool__(self): return bool(self._matn.strip())
def __contains__(self, x):
if isinstance(x, str):
return x.lower() in self._matn.lower() or x.lower() in self._teglar
return False
def __eq__(self, b):
if not isinstance(b, Hujjat):
return NotImplemented
return (self._sarlavha, self._matn) == (b._sarlavha, b._matn)
def __hash__(self):
return hash((self._sarlavha, self._matn))
# ═══ 6. KOMPOZITSIYA QISMLARI ═══
class Katta:
"""⭐ Protocol ga mos — meros YO'Q."""
def formatla(self, matn: str) -> str:
return matn.upper()
class Qisqartir:
def __init__(self, maks: int = 100):
self.maks = maks
def formatla(self, matn: str) -> str:
return (matn if len(matn) <= self.maks
else matn[:self.maks - 3] + "...")
class Almashtir:
def __init__(self, jadval: dict[str, str]):
self.jadval = jadval
def formatla(self, matn: str) -> str:
for a, b in self.jadval.items():
matn = matn.replace(a, b)
return matn
class UzunlikTekshiruvchi:
def __init__(self, eng_kam: int = 10, eng_kop: int = 100_000):
self.eng_kam, self.eng_kop = eng_kam, eng_kop
def tekshir(self, hujjat: Hujjat) -> list[str]:
n = len(hujjat.xom_matn)
if n < self.eng_kam:
return [f"Matn juda qisqa: {n} < {self.eng_kam}"]
if n > self.eng_kop:
return [f"Matn juda uzun: {n} > {self.eng_kop}"]
return []
class TegTekshiruvchi:
def __init__(self, eng_kam: int = 1):
self.eng_kam = eng_kam
def tekshir(self, hujjat: Hujjat) -> list[str]:
if len(hujjat.teglar) < self.eng_kam:
return [f"Kamida {self.eng_kam} teg kerak"]
return []
class MuallifTekshiruvchi:
def tekshir(self, hujjat: Hujjat) -> list[str]:
return [] if hujjat.muallif.strip() else ["Muallif ko'rsatilmagan"]
# ═══ 7. KONTEYNER 8.14-bob ═══
class Kutubxona(Sequence):
"""⭐ Sequence dan meros — is-a to'g'ri.
Ichida list bor (kompozitsiya), lekin o'zi Sequence.
"""
def __init__(self, hujjatlar=()):
self._h: list[Hujjat] = list(hujjatlar)
def __getitem__(self, i):
if isinstance(i, slice):
return Kutubxona(self._h[i])
if isinstance(i, str):
for h in self._h:
if h.sarlavha == i:
return h
raise KeyError(i)
return self._h[i]
def __len__(self): return len(self._h)
def qosh(self, *hujjatlar: Hujjat) -> "Kutubxona":
self._h.extend(hujjatlar)
return self
def filtrla(self, **shartlar) -> "Kutubxona":
natija = self._h
if "holat" in shartlar:
natija = [h for h in natija if h.holat == shartlar["holat"]]
if "teg" in shartlar:
natija = [h for h in natija if shartlar["teg"] in h.teglar]
if "muallif" in shartlar:
natija = [h for h in natija if h.muallif == shartlar["muallif"]]
return Kutubxona(natija)
def __repr__(self):
return f"Kutubxona({len(self)} hujjat)"
print("1. Hujjat yaratish (kompozitsiya bilan):\n")
h = Hujjat(
"Python OOP",
"Python da obyektga yo'naltirilgan dasturlash. "
"Sinflar, meros va kompozitsiya.",
"Aziz Karimov",
tekshiruvchilar=[UzunlikTekshiruvchi(20), TegTekshiruvchi(2),
MuallifTekshiruvchi()],
)
h.teg_qosh("python", "OOP", " Darslik ")
print(f" {h!r}")
print(f" teglar: {sorted(h.teglar)}")
print(f" statistika: {h.statistika}")
print(f" len(h) = {len(h)}, bool(h) = {bool(h)}")
print(f" 'python' in h = {'python' in h}")
print("\n\n2. ⭐ Formatlagichlar (ish vaqtida):\n")
print(f" Boshida: {h.matn[:50]}...\n")
h.formatlagichlar.append(Qisqartir(40))
print(f" + Qisqartir(40):")
print(f" {h.matn}")
h.formatlagichlar.append(Katta())
print(f"\n + Katta():")
print(f" {h.matn}")
h.formatlagichlar = [Almashtir({"Python": "Pythön", "OOP": "OYD"})]
print(f"\n Almashtir bilan almashtirildi:")
print(f" {h.matn[:60]}...")
h.formatlagichlar.clear()
print(f"\n Tozalandi: {h.matn[:40]}...")
print(f"\n ⭐ xom_matn hech qachon o'zgarmadi:")
print(f" {h.xom_matn[:40]}...")
print("\n\n3. Tekshiruvchilar:\n")
print(f" Tekshiruvchilar: "
f"{[type(t).__name__ for t in h.tekshiruvchilar]}")
print(f" Natija: {h.tekshir() or '✅ xato yo`q'}")
print(f"\n Muammoli hujjat:")
h2 = Hujjat("Qisqa", "Kam", tekshiruvchilar=h.tekshiruvchilar)
for x in h2.tekshir():
print(f" ❌ {x}")
print(f"\n Protocol tekshiruvi:")
for t in h.tekshiruvchilar:
print(f" isinstance({type(t).__name__}, Tekshiruvchi) = "
f"{isinstance(t, Tekshiruvchi)} ⭐ meros yo'q")
print("\n\n4. Holat mashinasi:\n")
print(f" Joriy: {h.holat}")
for yangi in [Holat.KORIB_CHIQISHDA, Holat.NASHR, Holat.ARXIV]:
try:
h.holat_ozgartir(yangi)
print(f" → {yangi} ✅")
except ValueError as e:
print(f" → {yangi} ❌ {e}")
print(f"\n Noto'g'ri o'tish:")
try:
h.holat_ozgartir(Holat.NASHR)
except ValueError as e:
print(f" {str(e)[:64]}")
print(f"\n Tekshiruvsiz nashr:")
try:
h2.holat_ozgartir(Holat.KORIB_CHIQISHDA).holat_ozgartir(Holat.NASHR)
except ValueError as e:
print(f" ❌ {str(e)[:70]}")
print("\n\n5. Eksport (ABC + shablon metod):\n")
print(f" Mavjud formatlar: {Eksportchi.mavjudlar()}\n")
h.holat_ozgartir(Holat.QORALAMA)
for fmt in Eksportchi.mavjudlar():
natija = h.eksport(fmt)
print(f" ┌─ {fmt}")
for q in natija.split("\n")[:5]:
print(f" │ {q[:64]}")
qolgan = len(natija.split("\n")) - 5
if qolgan > 0:
print(f" │ ... yana {qolgan} qator")
print(f" └{'─' * 60}\n")
print("6. Kutubxona (Sequence merosi):\n")
k = Kutubxona()
k.qosh(
h,
Hujjat("Ma'lumot tuzilmalari", "Ro'yxat, lug'at va to'plamlar. " * 3,
"Aziz Karimov").teg_qosh("python", "algoritm"),
Hujjat("Veb dasturlash", "Flask va Django asoslari. " * 4,
"Malika Yusupova").teg_qosh("python", "veb"),
Hujjat("JavaScript", "Brauzerdagi dasturlash. " * 5,
"Bobur Aliyev").teg_qosh("javascript", "veb"),
)
print(f" {k!r}\n")
for x in k:
print(f" {x}")
print(f"\n Sequence metodlari (bepul):")
print(f" len(k) = {len(k)}")
print(f" k[0] = {k[0]}")
print(f" k[-1] = {k[-1]}")
print(f" k[1:3] = {k[1:3]!r}")
print(f" k['JavaScript'] = {k['JavaScript']}")
print(f" h in k = {h in k}")
print(f" k.index(h) = {k.index(h)}")
print(f"\n Filtrlash:")
for shart in [{"teg": "python"}, {"teg": "veb"},
{"muallif": "Aziz Karimov"},
{"holat": Holat.QORALAMA}]:
natija = k.filtrla(**shart)
print(f" {str(shart):<32} → "
f"{[x.sarlavha for x in natija]}")
print("\n\n7. ⭐ Arxitektura qarorlari:\n")
QARORLAR = [
("Versiya", "@dataclass(frozen, slots, order)", "MEROS",
"is-a: dataclass mexanizmi"),
("Holat", "Enum", "MEROS", "is-a: sanab o'tiladigan qiymat"),
("Eksportchi", "ABC + shablon metod", "MEROS",
"is-a: har avlod haqiqiy eksportchi"),
("Kutubxona", "Sequence", "MEROS",
"is-a: ketma-ketlik, HAR metod ma'noli"),
("Hujjat.formatlagichlar", "list[Protocol]", "KOMPOZITSIYA",
"ish vaqtida almashtiriladi"),
("Hujjat.tekshiruvchilar", "list[Protocol]", "KOMPOZITSIYA",
"mustaqil o'lcham"),
("Kutubxona._h", "list", "KOMPOZITSIYA",
"list metodlarining yarmi ortiqcha"),
]
print(f" {'Komponent':<28} {'Qaror':<16} {'Sabab'}")
print(" " + "─" * 76)
for nom, mexanizm, qaror, sabab in QARORLAR:
belgi = "🔷" if qaror == "MEROS" else "🔶"
print(f" {belgi} {nom:<26} {qaror:<16} {sabab}")
print(f"""
⭐ 8-QISM XULOSASI — BU LOYIHADA:
8.1-8.5 Sinf, __init__, atributlar, metodlar
8.6-8.8 Meros (Eksportchi, Kutubxona), MRO
8.9 Polimorfizm (Protocol, duck typing)
8.10 Kapsulatsiya (_matn, __dict__ himoyasi)
8.11-8.14 Dunder: __repr__, __eq__, __len__, __contains__
8.15 @property, @cached_property (statistika)
8.16 @classmethod (Eksportchi.yarat, mavjudlar)
8.17 dataclass (Versiya), Enum (Holat)
8.18 ABC (Eksportchi), __init_subclass__ registry
8.19 __slots__ (Versiya)
8.20 Kompozitsiya (formatlagichlar, tekshiruvchilar)
⭐ QAROR MEZONI:
MEROS — 4 joyda (barchasi haqiqiy "is-a")
KOMPOZITSIYA — 3 joyda (almashtiriladigan xatti-harakat)
""")Natijaning muhim qismi:
2. ⭐ Formatlagichlar (ish vaqtida):
+ Qisqartir(40):
Python da obyektga yo'naltirilgan dast...
+ Katta():
PYTHON DA OBYEKTGA YO'NALTIRILGAN DAS...
⭐ xom_matn hech qachon o'zgarmadi
3. Tekshiruvchilar:
Muammoli hujjat:
❌ Matn juda qisqa: 3 < 20
❌ Kamida 2 teg kerak
isinstance(UzunlikTekshiruvchi, Tekshiruvchi) = True ⭐ meros yo'q
7. ⭐ Arxitektura qarorlari:
🔷 Versiya MEROS is-a: dataclass mexanizmi
🔷 Eksportchi MEROS is-a: har avlod haqiqiy eksportchi
🔶 Hujjat.formatlagichlar KOMPOZITSIYA ish vaqtida almashtiriladiNima ko'rsatdi: 2.1, 2.2, 2.5, 2.7-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Meros — kod qayta ishlatish uchun" | "is-a" uchun; qayta ishlatish — kompozitsiya |
| "Kompozitsiya har doim yaxshi" | Ortiqcha uzatish ham antipattern |
"list/dict dan meros oddiy" |
Yarim metodlar ortiqcha bo'ladi |
"UserList muammoni hal qiladi" |
Faqat C metodlari muammosini |
"__getattr__ — yaxshi uzatish" |
Dunder metodlar uzatilmaydi |
| "Kompozitsiya sekinroq" | Farq nanosekundlarda |
| "Meros yozish oson, demak yaxshi" | Qisqa muddatli yutuq |
"isinstance uchun meros kerak" |
Protocol yoki register() |
6. Keng tarqalgan xatolar va yechimlari
1. O'rnatilgan turlardan meros
class Stack(list): ... # ⚠️ 40 ortiqcha metod
class Stack: # ✅ kompozitsiya
def __init__(self): self._el = []2. "has-a" uchun meros
class Mashina(Dvigatel): ... # ❌
class Mashina:
def __init__(self): self.dvigatel = Dvigatel() # ✅3. Kombinatsiya portlashi
class ZaharliUchuvchiSuzuvchi(...) # ⚠️ 2ⁿ sinf
@dataclass
class Jonzot:
xususiyatlar: list[Xususiyat] # ✅4. __getattr__ bilan to'liq uzatish
def __getattr__(self, n):
return getattr(self._ichki, n) # ⚠️ dunder uzatilmaydi
# ✅ qo'lda yoki dekorator bilan5. Ortiqcha uzatish
class A:
def m1(self): return self._b.m1() # ⚠️ 20 ta shunday
# ✅ Meros ko'rib chiqing yoki interfeysni qisqartiring6. Ish vaqtida almashtirish kerak bo'lganda meros
class SaralovchiTez(Saralovchi): ... # ⚠️
Saralovchi(algoritm=tez_saralash) # ✅7. super() chaqirilmaydigan mixin
class Mixin:
def f(self): return "m" # ⚠️ zanjir uziladi
def f(self): return "m" + super().f() # ✅8. Chuqur ierarxiya
A → B → C → D → E → F # ⚠️
A → B + kompozitsiya # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8.6-8.8-darslar (o'tilgan): meros,
super(), MRO - 8.9, 8.18:
Protocol, ABC — interfeys - 8.17:
dataclassbilan kompozitsiya - 9-qism: istisnolar — meros to'g'ri bo'lgan misol
- 10-qism: dekoratorlar — funksiyalar bilan kompozitsiya
- Kitob: Design Patterns (GoF), Effective Python
- Django, DRF, SQLAlchemy — ikkalasi ham keng ishlatiladi
8. Eng yaxshi amaliyotlar
Sukut — kompozitsiya. Meros — asoslash talab qiladi.
Uch savolni bering. "is-a", "has-a", "har metod ma'nolimi".
O'rnatilgan turlardan meros olmang.
UserDict/UserListyoki kompozitsiya.Mustaqil o'lchamlarni ajrating. Kombinatsiya portlashining oldini oladi.
Uzatishni qo'lda yozing.
__getattr__— oxirgi chora.Meros faqat: ABC, framework, mixin, "is-a". Boshqa hollarda kompozitsiya.
Chuqurlik ≤ 2-3 daraja. Chuqurroq — qayta ko'rib chiqing.
Protocolbilan interfeys. Meros talab qilmaydi.
9. Amaliy topshiriq
Vazifa 1: Meros yoki kompozitsiya?
1. Stack va list
2. ValidationError va Exception
3. Mashina va Dvigatel
4. Admin va Foydalanuvchi
5. Kesh va dict
6. Buyurtma va Mahsulot
7. JsonEksportchi va Eksportchi(ABC)
8. Xizmat va HttpMijoz
9. Kvadrat va Togriturtburchak (o'zgaruvchan)
10. MeningTestim va unittest.TestCase
11. Saralovchi va saralash algoritmi
12. TekshirilganRoyxat va MutableSequenceJavoblar
- Kompozitsiya —
listmetodlarining yarmi ma'nosiz - Meros — haqiqiy "is-a"
- Kompozitsiya — "mashinada dvigatel bor"
- Meros — "admin bu foydalanuvchi"
- Kompozitsiya yoki
UserDict— keshdictemas (TTL, chegara) - Kompozitsiya — "buyurtmada mahsulotlar bor"
- Meros — ABC amalga oshirish
- Kompozitsiya — test uchun almashtirish kerak
- Ikkalasi ham emas — birodar sinflar (umumiy
Shakl) - Meros — framework kengaytirish nuqtasi
- Kompozitsiya — strategiya, ish vaqtida almashtiriladi
- Meros — har metod ma'noli,
is-ato'g'ri
Vazifa 2: Xatolarni tuzating
1. class Stack(list):
def push(self, x): self.append(x)
2. class Mashina(Dvigatel): ...
3. class ZaharliUchuvchiSuzuvchi(Zaharli, Uchuvchi, Suzuvchi): ...
4. class Oram:
def __getattr__(self, n): return getattr(self._ichki, n)
len(oram)
5. class Sozlama(dict):
def __setitem__(self, k, v): super().__setitem__(k.lower(), v)
6. class SaralovchiTez(Saralovchi): ...
class SaralovchiSekin(Saralovchi): ...
7. class Mixin:
def f(self): return "mixin"
8. class A: ...
class B(A): ...
class C(B): ...
class D(C): ...
class E(D): ...Javoblar
1. Kompozitsiya: self._el = []
2. self.dvigatel = Dvigatel()
3. @dataclass class Jonzot: xususiyatlar: list[...]
4. Dunder larni qo'lda uzating yoki dekorator ishlating
5. class Sozlama(UserDict)
6. Saralovchi(algoritm=...) — strategiya
7. return "mixin " + super().f()
8. Ierarxiyani yassilang + kompozitsiyaVazifa 3: Savat sinfi
Yozing:
- Kompozitsiya bilan (ichida
list) - Faqat kerakli metodlar:
qosh,ochir,jami,tozala __len__,__iter__,__contains__,__bool__- Chegirma strategiyasi (ish vaqtida almashtiriladi)
listdan meros olgan versiya bilan solishtiring- Qaysi biri qaysi holatda yaxshi — asoslang
Vazifa 4: Kombinatsiya portlashi
- 4 xususiyatli meros ierarxiyasini yozing (16 sinf)
- Uni kompozitsiyaga o'giring (6-8 sinf)
- Beshinchi xususiyat qo'shing — ikkalasida ham
- Kod qatorlarini solishtiring
- Ish vaqtida o'zgartirish imkoniyatini ko'rsating
- Yangi kombinatsiya qo'shish narxini o'lchang
Vazifa 5: Uzatish generatori
Vosita yozing:
- Sinf va uzatiladigan metodlar ro'yxatini olsin
- Dunder metodlarni ham qo'llab-quvvatlasin
- Imzoni saqlasin (
functools.wraps) - Tur ko'rsatkichlarini ko'chirsin
- Hujjat yaratsin
__getattr__bilan solishtiring
Vazifa 6: Refaktoring
Meros ierarxiyasini kompozitsiyaga o'giring:
- Mavjud kodni tahlil qiling
- Mustaqil o'lchamlarni aniqlang
- Interfeyslarni (
Protocol) ajrating - Bosqichma-bosqich o'tkazing
- Testlar buzilmasin
- Kod hajmi va moslashuvchanlikni solishtiring
Vazifa 7: O'ylash
Nega "Design Patterns" kitobidagi 23 naqshning ko'pchiligi Python kodida ko'rinmaydi?
Javob
Chunki ular tilning bir qismiga aylangan — naqsh nomiga ehtiyoj qolmagan.
1. Naqsh nima
Dizayn naqshi — tilning cheklovini aylanib o'tish usuli:
"Bu til X ni to'g'ridan-to'g'ri qo'llab-quvvatlamaydi, shuning uchun biz Y qilamiz."
Agar til X ni qo'llab-quvvatlasa — naqsh kerak emas.
2. Yo'qolgan naqshlar
| Naqsh (GoF) | Java da | Pythonda |
|---|---|---|
| Factory Method | Abstract class + subclass | @classmethod |
| Strategy | Interface + implementations | Funksiya obyekti |
| Command | Interface + execute() |
Funksiya yoki functools.partial |
| Iterator | Interface + hasNext/next |
__iter__/yield |
| Decorator | Wrapper class ierarxiyasi | @dekorator |
| Singleton | Private constructor + static | Modul |
| Template Method | Abstract class | Bor, lekin soddaroq |
| Adapter | Wrapper class | Bor |
| Observer | Interface + list | Callback ro'yxati |
| Prototype | clone() metodi |
copy.copy |
| Flyweight | Factory + pool | functools.lru_cache |
| Visitor | Double dispatch | singledispatch |
3. Misollar
Strategy:
// Java — naqsh kerak
interface Saralash { List sarala(List m); }
class TezSaralash implements Saralash { ... }
class SekinSaralash implements Saralash { ... }
class Saralovchi {
private Saralash strategiya;
Saralovchi(Saralash s) { this.strategiya = s; }
}# Python — naqsh KO'RINMAYDI
def saralovchi(m, algoritm=sorted):
return algoritm(m)
saralovchi(m, tez_saralash) # ⭐ funksiya — birinchi darajaliStrategy naqshi Pythonda funksiyani uzatish bo'lib qoldi.
Command:
interface Buyruq { void bajar(); }
class SaqlashBuyrugi implements Buyruq {
public void bajar() { ... }
}
List<Buyruq> tarix = new ArrayList<>();from functools import partial
tarix = []
tarix.append(partial(saqla, hujjat)) # ⭐ shunchaki funksiya
for buyruq in tarix:
buyruq()Singleton:
class Sozlama {
private static Sozlama nusxa;
private Sozlama() {}
public static Sozlama olish() {
if (nusxa == null) nusxa = new Sozlama();
return nusxa;
}
}# sozlama.py — ⭐ modul allaqachon singleton
HOST = "localhost"
PORT = 8000
# ishlatish:
import sozlama
sozlama.HOSTIterator:
class MeningRoyxatim implements Iterable<Integer> {
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
public boolean hasNext() { ... }
public Integer next() { ... }
};
}
}class MeningRoyxatim:
def __iter__(self):
yield from self._el # ⭐ bitta qatorDecorator:
abstract class Ombor { abstract String olish(String k); }
class KeshlanganOmbor extends Ombor {
private Ombor ichki;
String olish(String k) { ... }
}@lru_cache # ⭐ tilda bor
def olish(k): ...
# yoki obyekt uchun:
@cached_property
def qiymat(self): ...4. Qolgan naqshlar
Ba'zi naqshlar hali ham kerak:
# ✅ Template Method — ABC bilan
class Quvur(ABC):
def bajar(self, m): # ⭐ algoritm
m = self._yukla(m)
m = self._ishla(m) # ⭐ ilgak
return self._saqla(m)
@abstractmethod
def _ishla(self, m): ...
# ✅ Adapter — interfeys mos kelmasa
class EskiAdapter(YangiInterfeys):
def __init__(self, eski): self._eski = eski
def yangi_metod(self): return self._eski.eski_metod()
# ✅ Facade — murakkablikni yashirish
class Kutubxona:
def kitob_top(self, isbn):
# ichkarida: db, kesh, jurnal, tarmoq
...
# ✅ Composite — daraxt tuzilmalari
class Papka:
def __init__(self): self.bolalar = []
# ✅ Observer — hodisa tizimlari
# (lekin Pythonda oddiy callback ro'yxati)Naqsh: tuzilmaviy (structural) va xatti-harakat naqshlari qoladi; yaratuvchi (creational) naqshlar yo'qoladi.
5. Peter Norvig ning tahlili
1996 yilda Peter Norvig ("Design Patterns in Dynamic Languages") tahlil qildi:
"16 of the 23 patterns are either invisible or simpler in a dynamic language."
23 dan 16 tasi dinamik tilda ko'rinmaydi yoki soddalashadi.
Sabablari:
- Birinchi darajali funksiyalar — Strategy, Command, Visitor
- Birinchi darajali turlar — Factory, Abstract Factory
- Modullar — Singleton, Facade
- Dinamik atributlar — Prototype, Flyweight
- Ko'p meros / mixin — Decorator, Adapter
6. Nima uchun bu muhim
Java tajribasi bilan kelgan dasturchi Pythonda naqshlarni ko'chirib yozadi:
# ⚠️ Java uslubidagi Python
class AbstractSaralashStrategiyaFactory(ABC):
@abstractmethod
def yarat_strategiya(self) -> AbstractSaralashStrategiya: ...
class TezSaralashStrategiyaFactory(AbstractSaralashStrategiyaFactory):
def yarat_strategiya(self):
return TezSaralashStrategiya()
# ✅ Pythoncha
def sarala(m, key=None, reverse=False):
return sorted(m, key=key, reverse=reverse)Belgilar:
AbstractXFactorysinflariIOmbor,IFoydalanuvchi(interfeys prefiksi)- Getter/setter
- Har narsa uchun sinf
- Chuqur ierarxiya
7. Pythonning "naqshlari"
Pythonda o'z idiomalari bor:
| Idioma | Nima hal qiladi |
|---|---|
| Duck typing | Interfeys |
| Dekorator | Cross-cutting concerns |
Kontekst menejeri (with) |
Resurs boshqaruvi |
| Generator | Dangasa hisoblash, Iterator |
functools.partial |
Command, Currying |
singledispatch |
Visitor, ortiqcha yuklash |
| Modul | Singleton, Facade |
dataclass |
Value Object, Builder |
__init_subclass__ |
Registry |
Protocol |
Interface |
8. Amaliy tavsiya
# ⭐ 1. Avval eng ODDIY yechimni sinang
def ishla(m, f=sorted): return f(m)
# ⭐ 2. Yetmasa — funksiya obyekti
class Saralovchi:
def __call__(self, m): ...
# ⭐ 3. Yetmasa — Protocol
class Algoritm(Protocol):
def __call__(self, m: list) -> list: ...
# ⭐ 4. Yetmasa — ABC (umumiy kod kerak bo'lsa)
class AsosAlgoritm(ABC):
@abstractmethod
def _sarala(self, m): ...
def sarala(self, m): # umumiy tekshiruv
...
# ⚠️ 5. Faqat oxirida — to'liq naqsh9. Xulosa
GoF naqshlari Pythonda ko'rinmaydi, chunki:
- Funksiyalar — birinchi darajali → Strategy, Command, Visitor yo'qoldi
- Sinflar — obyekt → Factory Method
@classmethodbo'ldi - Modullar → Singleton, Facade
- Dinamiklik → Prototype, Flyweight
- Dekoratorlar → Decorator naqshi tilga kirdi
Umumiy dars: naqsh — tilning cheklovi belgisi. Kodingizda ko'p naqsh nomi bo'lsa, ehtimol siz tilning imkoniyatlaridan to'liq foydalanmayapsiz.
Paul Graham:
"When you notice a pattern in your code, that's a sign that the language is not powerful enough."
Lekin teskarisi ham to'g'ri emas — naqshlarni butunlay rad etish ham xato. Template Method, Adapter, Facade, Composite — Pythonda ham foydali va o'z nomi bilan ishlatiladi.
Nimani mustahkamlaydi: 2.2, 2.5, 2.7-bo'limlar.
Xulosa
Bu darsda meros va kompozitsiya orasidagi tanlovni o'rgandik.
Eng muhim uch fikr:
Uchinchi savol eng amaliy: "ota-sinfning HAR metodi ma'nolimi?" "is-a" testi ba'zan aldaydi —
Stackvalistmunosabati mantiqan tuyulishi mumkin, lekinlist.sort(),list.insert(),list.__setitem__()stack uchun ma'nosiz. Javob "yo'q" bo'lsa — kompozitsiya, hatto "is-a" to'g'ri ko'rinsa ham.Kompozitsiya kombinatsiya portlashini yo'q qiladi. Meros bilan n mustaqil xususiyat 2ⁿ sinf talab qiladi; kompozitsiya bilan — n sinf va istalgancha obyekt. Bundan tashqari, xususiyatni ish vaqtida almashtirish mumkin bo'ladi — meros bilan bu imkonsiz.
Meros beshta holatda to'g'ri: haqiqiy "is-a", ABC/Protocol, framework kengaytirish nuqtasi, mixin va til konstruktsiyalari (
Enum,dataclass,NamedTuple). Boshqa hollarda sukut tanlov — kompozitsiya. Uzatishni qo'lda yozing:__getattr__dunder metodlarni uzatmaydi va IDE bilanmypyni ko'r qiladi.
8-QISM YAKUNI
Yigirma darsda Pythonning obyekt modelini to'liq ko'rib chiqdik:
| Darslar | Mavzu | Asosiy fikr |
|---|---|---|
| 1-5 | Asoslar | class — bajariladigan kod; o'qish zanjir bo'ylab, yozish nusxaga |
| 6-8 | Meros | "is-a", LSP, super() — MRO da keyingi, C3 linearizatsiyasi |
| 9-10 | Polimorfizm, kapsulatsiya | Duck typing merosni talab qilmaydi; _ va __ — kelishuv |
| 11-14 | Dunder metodlar | __repr__ asos; __eq__+__hash__ shartnomasi; NotImplemented |
| 15-16 | Deskriptorlar | property — data deskriptor; cls() fabrikada |
| 17-19 | Zamonaviy vositalar | dataclass sukut tuzog'ini taqiqlaydi; ABC — sukut kod; __slots__ — o'lchagandan keyin |
| 20 | Arxitektura | Kompozitsiya — sukut, meros — asoslash bilan |
Uch umumiy tamoyil:
Pythonda hamma narsa protokol orqali ishlaydi.
for—__iter__,+—__add__,obj.x— deskriptor,with—__enter__. Siz istalgan protokolga o'z turingizni qo'sha olasiz — bu duck typing ning texnik asosi.Har vosita — ixtiyoriy qatlam. Duck typing → tur ko'rsatkichi →
Protocol+mypy→ ABC +isinstance→pydantic. Xotira uchun: oddiy sinf →dataclass→slots=True→NamedTuple. Siz kerakli darajani tanlaysiz va faqat unga to'laysiz.Aniqlik moslashuvchanlikdan ustun.
selfyashirin emas,__hash__avtomatik yaratilmaydi,NotImplementedistisno emas,__slots__sukut bo'yicha yoqilmagan. Har safar Python jimgina xato o'rniga aniq xatti-harakatni tanlagan.
Keyingi qism — 9-qism: Xatolar va istisnolar. U yerda try/except/else/finally, istisnolar ierarxiyasi, o'z istisno turlaringiz va xatolarni to'g'ri qayta ishlash strategiyalarini o'rganamiz.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!