Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Protokollar iyerarxiyasi
- 2.2. Eski iteratsiya protokoli
- 2.3. __iter__ va __next__
- 2.4. __getitem__ va kesish
- 2.5. __contains__, __len__, __bool__
- 2.6. O'zgartiruvchi metodlar
- 2.7. collections.abc va User*
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Iteratsiya protokollari
- Misol 2 — Kesish va indekslash
- Misol 3 — collections.abc
- Misol 4 — Amaliy: matn korpusi
- 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.14-dars: Dunder: konteyner protokoli
8-QISM — OBYEKTGA YO'NALTIRILGAN DASTURLASH · 14-dars
1. Kirish va motivatsiya
Bitta metod — va sinf for bilan ishlaydi:
class Sanoq:
def __getitem__(self, i):
if i >= 5:
raise IndexError
return i * 10
for x in Sanoq(): # ✅ ishlaydi!
print(x) # 0 10 20 30 40
list(Sanoq()) # [0, 10, 20, 30, 40]
20 in Sanoq() # True __iter__ yozilmagan, lekin for ishladi. Nega?
Va bu — chalkash:
class A:
def __len__(self): return 0
bool(A()) # False ⚠️ __bool__ yozilmagan
if A(): ... # bajarilmaydiVa bu:
class B:
def __contains__(self, x): return True
"har narsa" in B() # True
for x in B(): ... # ❌ TypeErrorBu darsda:
- Konteyner protokollari:
Sized,Iterable,Container,Sequence,Mapping __getitem__va eski iteratsiya protokoli__iter__,__next__,__reversed__- Kesish (
slice) va salbiy indekslar __setitem__,__delitem__,__missing__collections.abcvaUserDict/UserList
2. Nazariya — chuqur tushuntirish
2.1. Protokollar iyerarxiyasi
| Protokol | Metodlar | Beradi |
|---|---|---|
Container |
__contains__ |
in |
Sized |
__len__ |
len() |
Iterable |
__iter__ |
for, list() |
Iterator |
__iter__, __next__ |
next() |
Reversible |
__reversed__ |
reversed() |
Collection |
Sized + Iterable + Container |
uchalasi |
Sequence |
__getitem__, __len__ |
[i], kesish, index, count |
MutableSequence |
+ __setitem__, __delitem__, insert |
append, pop, remove |
Mapping |
__getitem__, __len__, __iter__ |
keys, values, items, get |
MutableMapping |
+ __setitem__, __delitem__ |
pop, update, setdefault |
Set |
__contains__, __len__, __iter__ |
&, |, -, ^ |
collections.abc dan meros olsangiz — qolgan metodlar bepul.
2.2. Eski iteratsiya protokoli
class A:
def __getitem__(self, i):
if i >= 3: raise IndexError
return i
for x in A(): ... # ✅ ishlaydiMexanizm (iter(x)):
1. type(x).__iter__ bor bo'lsa → chaqiriladi
2. type(x).__getitem__ bor bo'lsa → ⭐ eski protokol:
obj[0], obj[1], obj[2], ... IndexError gacha
3. TypeError: 'A' object is not iterable Bu — Python 2.0 dan qolgan orqaga moslik. Yangi kodda __iter__ yozing.
Tuzoq:
class Lugat:
def __getitem__(self, kalit):
return self._d[kalit]
for x in Lugat(): ... # ⚠️ Lugat()[0] chaqiriladi → KeyErrorKeyError — IndexError emas, shuning uchun tsikl to'xtamaydi.
2.3. __iter__ va __next__
class Diapazon:
def __init__(self, n): self.n = n
def __iter__(self):
"""⭐ YANGI iterator qaytaradi."""
return DiapazonIter(self.n)
class DiapazonIter:
def __init__(self, n):
self.n, self.i = n, 0
def __iter__(self):
return self # ⭐ iterator o'zini qaytaradi
def __next__(self):
if self.i >= self.n:
raise StopIteration # ⭐ tugadi
q = self.i
self.i += 1
return qIterable vs Iterator:
| Iterable | Iterator | |
|---|---|---|
| Metodlar | __iter__ |
__iter__ + __next__ |
| Ko'p marta | Har for yangi |
Bir marta |
| Misol | list, dict, range |
iter(lst), generator |
O'zi iterator bo'lgan sinf — bir martalik:
class Yomon:
def __init__(self, n): self.n, self.i = n, 0
def __iter__(self): return self # ⚠️ o'zini
def __next__(self):
if self.i >= self.n: raise StopIteration
self.i += 1
return self.i - 1
y = Yomon(3)
list(y) # [0, 1, 2]
list(y) # [] ⚠️ tugaganGenerator bilan eng oson:
class Yaxshi:
def __init__(self, n): self.n = n
def __iter__(self):
for i in range(self.n):
yield i # ⭐ har safar yangi generator2.4. __getitem__ va kesish
class Royxat:
def __init__(self, el): self._el = list(el)
def __getitem__(self, i):
if isinstance(i, slice): # ⭐ kesish
return Royxat(self._el[i])
if isinstance(i, int):
if i < 0:
i += len(self._el) # ⭐ salbiy indeks
if not 0 <= i < len(self._el):
raise IndexError("indeks chegaradan tashqarida")
return self._el[i]
raise TypeError(
f"indeks int yoki slice bo'lsin: {type(i).__name__}"
)Uch holat:
r[0] # int
r[1:3] # slice(1, 3, None)
r[::2] # slice(None, None, 2)
r["a"] # ⚠️ TypeError berish kerakslice obyekti:
s = slice(1, 10, 2)
s.start, s.stop, s.step # 1, 10, 2
s.indices(5) # (1, 5, 2) ⭐ uzunlikka moslashtiradi slice.indices(len) — salbiy va chegaradan tashqari qiymatlarni to'g'rilaydi.
Kesish natijasi — o'sha tur:
"abc"[0:2] # 'ab' str
[1,2,3][0:2] # [1, 2] list
(1,2,3)[0:2] # (1, 2) tupleSizning sinfingiz ham shunday qilsin.
2.5. __contains__, __len__, __bool__
in mexanizmi:
x in obj:
1. obj.__contains__(x) bor bo'lsa
2. iteratsiya: obj bo'ylab yurib == bilan solishtiradi
3. TypeErrorclass A:
def __getitem__(self, i):
if i >= 3: raise IndexError
return i
2 in A() # True ⭐ iteratsiya orqalibool mexanizmi (8.13-darsda ko'rgan edik):
1. __bool__()
2. __len__() != 0
3. TrueTuzoq:
class Sozlama:
def __len__(self): return len(self._d)
s = Sozlama() # bo'sh
if s: # ⚠️ False — kutilmagan bo'lishi mumkin
...
if s is not None: # ✅ aniq
...2.6. O'zgartiruvchi metodlar
class Konteyner:
def __setitem__(self, k, v): ... # obj[k] = v
def __delitem__(self, k): ... # del obj[k]
def __missing__(self, k): ... # ⭐ faqat dict avlodlarida __missing__ — faqat dict dan meros olganda:
class Sukutli(dict):
def __missing__(self, k):
return f"<{k} yo'q>"
d = Sukutli(a=1)
d["a"] # 1
d["yoq"] # '<yoq yo'q>'
d.get("yoq") # None ⚠️ get __missing__ ni chaqirmaydi Oddiy sinfda __missing__ ishlamaydi — u dict.__getitem__ ichida chaqiriladi.
2.7. collections.abc va User*
A) ABC dan meros — metodlar bepul:
from collections.abc import Sequence
class Royxat(Sequence):
def __init__(self, el): self._el = list(el)
def __getitem__(self, i): return self._el[i]
def __len__(self): return len(self._el)
# ⭐ BEPUL: __contains__, __iter__, __reversed__, index, count| ABC | Yozish kerak | Bepul |
|---|---|---|
Sequence |
__getitem__, __len__ |
__contains__, __iter__, __reversed__, index, count |
MutableSequence |
+ __setitem__, __delitem__, insert |
append, extend, pop, remove, __iadd__, reverse |
Mapping |
__getitem__, __len__, __iter__ |
__contains__, keys, items, values, get, __eq__ |
MutableMapping |
+ __setitem__, __delitem__ |
pop, popitem, clear, update, setdefault |
Set |
__contains__, __len__, __iter__ |
__le__, __lt__, __and__, __or__, __sub__, isdisjoint |
B) UserDict, UserList, UserString:
from collections import UserDict
class Sozlama(UserDict):
def __setitem__(self, k, v):
super().__setitem__(k.lower(), v) # ⭐ normallashtiradi Nega dict dan meros olmaslik kerak:
class YomonSozlama(dict):
def __setitem__(self, k, v):
super().__setitem__(k.lower(), v)
d = YomonSozlama(A=1) # ⚠️ __init__ __setitem__ ni chaqirmaydi
d # {'A': 1} ⚠️ normallashmadi
d.update(B=2) # ⚠️ update ham chaqirmaydi
d # {'A': 1, 'B': 2} C da yozilgan dict metodlari ichkarida __setitem__ ni chaqirmaydi.
UserDict — sof Python, self.data lug'atini o'raydi:
class Sozlama(UserDict):
def __setitem__(self, k, v):
super().__setitem__(k.lower(), v)
s = Sozlama(A=1)
s # {'a': 1} ✅
s.update(B=2)
s # {'a': 1, 'b': 2} ✅3. Tez ma'lumotnoma
Protokollar
__len__ len(x), bool(x) (fallback)
__getitem__ x[i], eski iteratsiya, in (fallback)
__setitem__ x[i] = v
__delitem__ del x[i]
__contains__ x in obj
__iter__ for, list(), iter()
__next__ next() (iterator)
__reversed__ reversed()
__missing__ ⭐ faqat dict avlodlaridaiter(x) tartibi
1. __iter__ bor bo'lsa
2. __getitem__ eski protokol: x[0], x[1], ... IndexError gacha
3. TypeErrorin tartibi
1. __contains__
2. iteratsiya + ==
3. TypeErrorKesish
def __getitem__(self, i):
if isinstance(i, slice):
return type(self)(self._el[i]) # ⭐ o'sha tur
if isinstance(i, int):
if i < 0: i += len(self) # salbiy
if not 0 <= i < len(self):
raise IndexError
return self._el[i]
raise TypeErrorcollections.abc
Sequence → __getitem__, __len__
MutableSequence → + __setitem__, __delitem__, insert
Mapping → __getitem__, __len__, __iter__
MutableMapping → + __setitem__, __delitem__
Set → __contains__, __len__, __iter__
UserDict/UserList ⭐ dict/list dan meros o'rniga4. Batafsil misollar
Misol 1 — Iteratsiya protokollari
"""__iter__, __next__, __getitem__ va ular orasidagi farq."""
from collections.abc import Iterable, Iterator, Sequence, Container, Sized
print("=== ⭐ 1. Eski iteratsiya protokoli ===\n")
class FaqatGetitem:
"""__iter__ YO'Q, lekin for ishlaydi."""
def __init__(self, n): self.n = n
def __getitem__(self, i):
print(f" __getitem__({i})")
if i >= self.n:
raise IndexError # ⭐ tsiklni to'xtatadi
return i * 10
print(f" for x in FaqatGetitem(3):")
for x in FaqatGetitem(3):
print(f" → {x}")
print(f"\n list(FaqatGetitem(3)) = ", end="")
print(list(FaqatGetitem(3)))
print(f"\n 10 in FaqatGetitem(3) = {10 in FaqatGetitem(3)}")
print(f" 99 in FaqatGetitem(3) = {99 in FaqatGetitem(3)}")
f = FaqatGetitem(3)
print(f"\n isinstance(f, Iterable) = {isinstance(f, Iterable)} "
f"⚠️ False, lekin iteratsiya ishlaydi!")
print(f"""
⭐ iter(x) MEXANIZMI:
1. type(x).__iter__ bor bo'lsa → chaqiriladi
2. type(x).__getitem__ bor bo'lsa → ESKI PROTOKOL:
x[0], x[1], x[2], ... IndexError gacha
3. TypeError
⚠️ collections.abc.Iterable FAQAT __iter__ ni tekshiradi.
""")
print("=== ⚠️ 2. Eski protokol tuzog'i ===\n")
class LugatKabi:
"""⚠️ Kalitlar satr — eski protokol buziladi."""
def __init__(self): self._d = {"a": 1, "b": 2}
def __getitem__(self, k):
return self._d[k] # ⚠️ KeyError, IndexError emas
print(f" for x in LugatKabi():")
try:
for x in LugatKabi():
print(f" {x}")
break
except KeyError as e:
print(f" ❌ KeyError: {e}")
print(f" ⚠️ x[0] chaqirildi → KeyError → tsikl TO'XTAMADI")
print(f"""
✅ YECHIM: __iter__ ni ANIQ yozing.
class LugatKabi:
def __iter__(self):
return iter(self._d)
""")
print("=== 3. Iterable vs Iterator ===\n")
class OziIterator:
"""⚠️ O'zi iterator — BIR MARTALIK."""
def __init__(self, n): self.n, self.i = n, 0
def __iter__(self): return self # ⚠️ o'zini
def __next__(self):
if self.i >= self.n: raise StopIteration
self.i += 1
return self.i - 1
class AlohidaIterator:
"""✅ Har safar yangi iterator."""
def __init__(self, n): self.n = n
def __iter__(self): return _Iter(self.n)
class _Iter:
def __init__(self, n): self.n, self.i = n, 0
def __iter__(self): return self
def __next__(self):
if self.i >= self.n: raise StopIteration
self.i += 1
return self.i - 1
class Generatorli:
"""✅ Eng oson — generator."""
def __init__(self, n): self.n = n
def __iter__(self):
for i in range(self.n):
yield i
print(f" {'Sinf':<20} {'1-marta':<14} {'2-marta':<14} {'Ichma-ich'}")
print(" " + "─" * 62)
for Sinf in (OziIterator, AlohidaIterator, Generatorli):
x = Sinf(3)
b1 = list(x)
b2 = list(x)
ichma = [(a, b) for a in x for b in x][:2]
print(f" {Sinf.__name__:<20} {str(b1):<14} {str(b2):<14} {ichma}")
print(f"""
⚠️ OziIterator: ikkinchi marta BO'SH, ichma-ich tsikl ishlamaydi
⭐ QOIDA:
Iterable — __iter__ YANGI iterator qaytaradi (ko'p marta)
Iterator — __iter__ o'zini qaytaradi + __next__ (bir marta)
Sizning KONTEYNERINGIZ — Iterable bo'lsin.
""")
x = Generatorli(3)
print(f" isinstance(Generatorli(3), Iterable) = {isinstance(x, Iterable)}")
print(f" isinstance(Generatorli(3), Iterator) = {isinstance(x, Iterator)}")
print(f" isinstance(iter(x), Iterator) = {isinstance(iter(x), Iterator)}")
print("\n=== 4. Protokol tekshiruvi ===\n")
class Bosh: pass
class FaqatLen:
def __len__(self): return 5
class FaqatContains:
def __contains__(self, x): return x == 1
class FaqatIter:
def __iter__(self): return iter([1, 2, 3])
class Toliq:
def __len__(self): return 3
def __iter__(self): return iter([1, 2, 3])
def __contains__(self, x): return x in (1, 2, 3)
def __getitem__(self, i): return [1, 2, 3][i]
SINFLAR = [Bosh, FaqatLen, FaqatContains, FaqatIter, Toliq,
FaqatGetitem]
print(f" {'Sinf':<18} {'len()':<8} {'in':<8} {'for':<8} {'[i]':<8} "
f"{'Sized':<8} {'Iterable'}")
print(" " + "─" * 72)
for S in SINFLAR:
x = S(3) if S is FaqatGetitem else S()
natijalar = []
for kod in ["len(x)", "1 in x", "list(x)", "x[0]"]:
try:
eval(kod, {"x": x})
natijalar.append("✅")
except (TypeError, IndexError, KeyError):
natijalar.append("❌")
sized = "✅" if isinstance(x, Sized) else "❌"
iterable = "✅" if isinstance(x, Iterable) else "❌"
print(f" {S.__name__:<18} {natijalar[0]:<8} {natijalar[1]:<8} "
f"{natijalar[2]:<8} {natijalar[3]:<8} {sized:<8} {iterable}")
print(f"""
⭐ KUZATUVLAR:
• FaqatContains: `in` ishlaydi, `for` ishlamaydi
• FaqatIter: `for` va `in` ishlaydi (iteratsiya orqali)
• FaqatGetitem: hammasi ishlaydi, lekin Iterable EMAS
""")
print("=== 5. __reversed__ ===\n")
class BilanReversed:
def __init__(self, el): self._el = list(el)
def __len__(self): return len(self._el)
def __getitem__(self, i): return self._el[i]
def __reversed__(self):
print(f" __reversed__ chaqirildi")
return reversed(self._el)
class ReversedSiz:
def __init__(self, el): self._el = list(el)
def __len__(self): return len(self._el)
def __getitem__(self, i):
print(f" __getitem__({i})")
return self._el[i]
print(f" __reversed__ bor:")
print(f" {list(reversed(BilanReversed([1, 2, 3])))}")
print(f"\n __reversed__ yo'q (__len__ + __getitem__):")
print(f" {list(reversed(ReversedSiz([1, 2, 3])))}")
print(f"""
⭐ reversed(x) MEXANIZMI:
1. __reversed__() bor bo'lsa
2. __len__ + __getitem__ ikkalasi ham bor bo'lsa
→ x[len-1], x[len-2], ..., x[0]
3. TypeError
""")
class FaqatIterSinf:
def __iter__(self): return iter([1, 2, 3])
try:
reversed(FaqatIterSinf())
except TypeError as e:
print(f" Faqat __iter__ bilan: ❌ TypeError: {e}")Natijaning muhim qismi:
=== ⭐ 1. Eski iteratsiya protokoli ===
for x in FaqatGetitem(3):
__getitem__(0)
→ 0
__getitem__(1)
→ 10
__getitem__(3)
isinstance(f, Iterable) = False ⚠️ False, lekin iteratsiya ishlaydi!
=== 3. Iterable vs Iterator ===
Sinf 1-marta 2-marta Ichma-ich
──────────────────────────────────────────────────────────────
OziIterator [0, 1, 2] [] []
AlohidaIterator [0, 1, 2] [0, 1, 2] [(0, 0), (0, 1)]
Generatorli [0, 1, 2] [0, 1, 2] [(0, 0), (0, 1)]
=== 4. Protokol tekshiruvi ===
Sinf len() in for [i] Sized Iterable
────────────────────────────────────────────────────────────────────────
FaqatContains ❌ ✅ ❌ ❌ ❌ ❌
FaqatIter ❌ ✅ ✅ ❌ ❌ ✅
FaqatGetitem ❌ ✅ ✅ ✅ ❌ ❌Nima ko'rsatdi: 2.1, 2.2, 2.3, 2.5-bo'limlar.
Misol 2 — Kesish va indekslash
"""__getitem__ ning barcha holatlari."""
print("=== ⭐ 1. Uch xil indeks ===\n")
class Kuzatuvchi:
"""Qanday indeks kelayotganini ko'rsatadi."""
def __getitem__(self, i):
return f"{type(i).__name__}: {i!r}"
k = Kuzatuvchi()
INDEKSLAR = [
"k[0]", "k[-1]", "k[1:3]", "k[::2]", "k[::-1]",
"k[1:10:2]", "k['a']", "k[1, 2]", "k[1:2, 3:4]",
"k[...]", "k[None]",
]
for kod in INDEKSLAR:
print(f" {kod:<16} → {eval(kod)}")
print(f"""
⭐ __getitem__ ISTALGAN obyektni oladi:
int, slice, str, tuple, Ellipsis, None, ...
NumPy aynan shundan foydalanadi:
arr[1:3, 2:4] → tuple of slices
""")
print("=== 2. To'g'ri __getitem__ ===\n")
class Royxat:
"""✅ Barcha holatlar to'g'ri qayta ishlanadi."""
def __init__(self, el=()):
self._el = list(el)
def __len__(self):
return len(self._el)
def __getitem__(self, i):
if isinstance(i, slice):
return Royxat(self._el[i]) # ⭐ o'sha tur
if isinstance(i, int):
if i < 0:
i += len(self._el) # ⭐ salbiy
if not 0 <= i < len(self._el):
raise IndexError(
f"indeks chegaradan tashqarida: {i}"
)
return self._el[i]
raise TypeError(
f"indeks int yoki slice bo'lsin, {type(i).__name__} emas"
)
def __setitem__(self, i, q):
if isinstance(i, slice):
self._el[i] = list(q)
elif isinstance(i, int):
if i < 0:
i += len(self._el)
if not 0 <= i < len(self._el):
raise IndexError(f"indeks chegaradan tashqarida: {i}")
self._el[i] = q
else:
raise TypeError("int yoki slice")
def __delitem__(self, i):
del self._el[i]
def __iter__(self):
return iter(self._el)
def __contains__(self, x):
return x in self._el
def __repr__(self):
return f"Royxat({self._el!r})"
def __eq__(self, b):
if isinstance(b, Royxat):
return self._el == b._el
if isinstance(b, list):
return self._el == b
return NotImplemented
r = Royxat(range(10))
print(f" r = {r}\n")
AMALLAR = [
("r[0]", lambda: r[0]),
("r[-1]", lambda: r[-1]),
("r[-3]", lambda: r[-3]),
("r[2:5]", lambda: r[2:5]),
("r[::2]", lambda: r[::2]),
("r[::-1]", lambda: r[::-1]),
("r[-3:]", lambda: r[-3:]),
("r[100]", lambda: r[100]),
("r[-100]", lambda: r[-100]),
("r['a']", lambda: r["a"]),
("len(r)", lambda: len(r)),
("5 in r", lambda: 5 in r),
("list(r)[:3]", lambda: list(r)[:3]),
("r == list(range(10))", lambda: r == list(range(10))),
]
for kod, f in AMALLAR:
try:
print(f" {kod:<24} → {f()!r}")
except (IndexError, TypeError) as e:
print(f" {kod:<24} → ❌ {type(e).__name__}: {e}")
print("\n=== ⭐ 3. slice.indices() ===\n")
s = slice(2, 8, 2)
print(f" s = slice(2, 8, 2)")
print(f" s.start, s.stop, s.step = {s.start}, {s.stop}, {s.step}")
print(f"\n s.indices(uzunlik) — chegaralarni to'g'rilaydi:")
for uzunlik in [10, 5, 3, 0]:
print(f" s.indices({uzunlik:<3}) = {s.indices(uzunlik)} "
f"→ range{s.indices(uzunlik)}")
print(f"\n Salbiy va chegaradan tashqari:")
for sl in [slice(-3, None), slice(None, -2), slice(None, None, -1),
slice(100, 200), slice(-100, 100)]:
print(f" slice({sl.start}, {sl.stop}, {sl.step}).indices(10) = "
f"{sl.indices(10)}")
print(f"""
⭐ AMALIY ISHLATISH:
def __getitem__(self, i):
if isinstance(i, slice):
boshlanish, tugash, qadam = i.indices(len(self))
return [self._ol(j) for j in range(boshlanish, tugash, qadam)]
""")
class Dangasa:
"""⭐ Elementlarni HISOBLAB beradi (saqlamaydi)."""
def __init__(self, n, f):
self.n, self.f = n, f
def __len__(self):
return self.n
def __getitem__(self, i):
if isinstance(i, slice):
boshlanish, tugash, qadam = i.indices(self.n)
return [self.f(j) for j in range(boshlanish, tugash, qadam)]
if i < 0:
i += self.n
if not 0 <= i < self.n:
raise IndexError(i)
return self.f(i)
def __repr__(self):
namuna = [self.f(i) for i in range(min(3, self.n))]
qolgan = f", ... ({self.n} ta)" if self.n > 3 else ""
return f"Dangasa({namuna}{qolgan})"
kvadratlar = Dangasa(1_000_000, lambda i: i ** 2)
print(f" Dangasa (1 million element, xotirada saqlanmaydi):")
print(f" {kvadratlar}")
print(f" len = {len(kvadratlar):,}")
print(f" [0] = {kvadratlar[0]}")
print(f" [999] = {kvadratlar[999]}")
print(f" [-1] = {kvadratlar[-1]:,}")
print(f" [10:15] = {kvadratlar[10:15]}")
print(f" [::250000] = {kvadratlar[::250000]}")
import sys
print(f"\n Xotira: {sys.getsizeof(kvadratlar)} bayt")
print(f" Ro'yxat bo'lganda: ~{1_000_000 * 28 / 1_048_576:.0f} MB")
print("\n\n=== 4. __setitem__ va __delitem__ ===\n")
r = Royxat(range(10))
print(f" Boshida: {r}\n")
OZGARTIRISHLAR = [
("r[0] = 100", lambda: r.__setitem__(0, 100)),
("r[-1] = 900", lambda: r.__setitem__(-1, 900)),
("r[2:5] = [0,0]", lambda: r.__setitem__(slice(2, 5), [0, 0])),
("del r[0]", lambda: r.__delitem__(0)),
("del r[:2]", lambda: r.__delitem__(slice(None, 2))),
("r[100] = 1", lambda: r.__setitem__(100, 1)),
]
for kod, f in OZGARTIRISHLAR:
try:
f()
print(f" {kod:<20} → {r}")
except (IndexError, TypeError) as e:
print(f" {kod:<20} → ❌ {type(e).__name__}: {e}")
print("\n=== ⭐ 5. __missing__ ===\n")
class Sukutli(dict):
"""⭐ FAQAT dict avlodlarida ishlaydi."""
def __missing__(self, k):
print(f" __missing__({k!r})")
return f"<{k} yo'q>"
class Hisoblagich(dict):
def __missing__(self, k):
self[k] = 0 # ⭐ yaratadi
return 0
d = Sukutli(a=1, b=2)
print(f" d = {dict(d)}")
print(f" d['a'] → {d['a']}")
print(f" d['yoq'] → ", end="")
print(f"{d['yoq']!r}")
print(f" d.get('yoq') → {d.get('yoq')!r} ⚠️ __missing__ chaqirilmadi")
print(f" 'yoq' in d → {'yoq' in d} ⚠️ ham yo'q")
h = Hisoblagich()
for soz in "salom dunyo salom python dunyo salom".split():
h[soz] += 1
print(f"\n Hisoblagich: {dict(h)}")
class OddiySinf:
"""⚠️ dict dan meros olmagan — __missing__ ISHLAMAYDI."""
def __init__(self): self._d = {}
def __getitem__(self, k): return self._d[k]
def __missing__(self, k): return "hech qachon chaqirilmaydi"
try:
OddiySinf()["yoq"]
except KeyError:
print(f"\n OddiySinf()['yoq'] → ❌ KeyError")
print(f" ⚠️ __missing__ CHAQIRILMADI (dict avlodi emas)")
print(f"""
⭐ __missing__ — dict.__getitem__ ICHIDA chaqiriladi.
Sizning __getitem__ ingiz uni o'zi chaqirishi kerak:
def __getitem__(self, k):
try:
return self._d[k]
except KeyError:
if hasattr(self, "__missing__"):
return self.__missing__(k)
raise
""")Natijaning muhim qismi:
=== ⭐ 1. Uch xil indeks ===
k[0] → int: 0
k[1:3] → slice: slice(1, 3, None)
k['a'] → str: 'a'
k[1, 2] → tuple: (1, 2)
k[...] → ellipsis: Ellipsis
=== 2. To'g'ri __getitem__ ===
r[2:5] → Royxat([2, 3, 4])
r[::-1] → Royxat([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
r[100] → ❌ IndexError: indeks chegaradan tashqarida
r['a'] → ❌ TypeError: indeks int yoki slice bo'lsin
=== ⭐ 3. slice.indices() ===
...
Dangasa (1 million element, xotirada saqlanmaydi):
[-1] = 999,998,000,001
Xotira: 48 bayt
Ro'yxat bo'lganda: ~27 MB
=== ⭐ 5. __missing__ ===
d.get('yoq') → None ⚠️ __missing__ chaqirilmadi
Hisoblagich: {'salom': 3, 'dunyo': 2, 'python': 1}Nima ko'rsatdi: 2.4, 2.6-bo'limlar.
Misol 3 — collections.abc
"""ABC dan meros — metodlar bepul."""
from collections.abc import (Sequence, MutableSequence, Mapping,
MutableMapping, Set, MutableSet)
from collections import UserDict, UserList
print("=== 1. Sequence — bepul metodlar ===\n")
class QoldaRoyxat:
"""⚠️ Hammasini qo'lda yozish kerak."""
def __init__(self, el): self._el = list(el)
def __getitem__(self, i): return self._el[i]
def __len__(self): return len(self._el)
class AbcRoyxat(Sequence):
"""✅ Sequence dan meros."""
def __init__(self, el): self._el = list(el)
def __getitem__(self, i): return self._el[i]
def __len__(self): return len(self._el)
q, a = QoldaRoyxat([1, 2, 3, 2]), AbcRoyxat([1, 2, 3, 2])
METODLAR = ["__contains__", "__iter__", "__reversed__", "index", "count"]
print(f" {'Metod':<16} {'QoldaRoyxat':<16} {'AbcRoyxat'}")
print(" " + "─" * 46)
for m in METODLAR:
qq = "✅" if hasattr(q, m) else "❌"
aa = "✅" if hasattr(a, m) else "❌"
print(f" {m:<16} {qq:<16} {aa}")
print(f"\n AbcRoyxat imkoniyatlari:")
print(f" 2 in a = {2 in a}")
print(f" a.index(3) = {a.index(3)}")
print(f" a.count(2) = {a.count(2)}")
print(f" list(reversed(a)) = {list(reversed(a))}")
print(f" isinstance(a, Sequence) = {isinstance(a, Sequence)}")
print("\n=== 2. MutableSequence ===\n")
class Stack(MutableSequence):
"""✅ Uch metod → to'liq ro'yxat."""
def __init__(self, el=()):
self._el = list(el)
# ── Majburiy (5 ta) ──
def __getitem__(self, i): return self._el[i]
def __setitem__(self, i, q): self._el[i] = q
def __delitem__(self, i): del self._el[i]
def __len__(self): return len(self._el)
def insert(self, i, q): self._el.insert(i, q)
def __repr__(self): return f"Stack({self._el!r})"
s = Stack([1, 2, 3])
print(f" s = {s}\n")
BEPUL = [
("s.append(4)", lambda: s.append(4)),
("s.extend([5, 6])", lambda: s.extend([5, 6])),
("s.pop()", lambda: s.pop()),
("s.pop(0)", lambda: s.pop(0)),
("s.remove(3)", lambda: s.remove(3)),
("s.insert(0, 99)", lambda: s.insert(0, 99)),
("s.reverse()", lambda: s.reverse()),
("s += [7]", lambda: s.__iadd__([7])),
("s.index(99)", lambda: s.index(99)),
("s.count(99)", lambda: s.count(99)),
("99 in s", lambda: 99 in s),
]
for kod, f in BEPUL:
natija = f()
korinish = f" → {natija!r}" if natija is not None and \
not isinstance(natija, Stack) else ""
print(f" {kod:<20}{korinish:<12} s = {s}")
print(f"""
⭐ 5 metod yozdik, 11+ metod BEPUL oldik.
""")
print("=== 3. Mapping ===\n")
class OqishLugat(Mapping):
"""✅ Faqat o'qish uchun lug'at."""
def __init__(self, **kw):
self._d = dict(kw)
def __getitem__(self, k): return self._d[k]
def __iter__(self): return iter(self._d)
def __len__(self): return len(self._d)
def __repr__(self): return f"OqishLugat({self._d!r})"
o = OqishLugat(a=1, b=2, c=3)
print(f" o = {o}\n")
for kod, f in [
("o['a']", lambda: o["a"]),
("o.get('a')", lambda: o.get("a")),
("o.get('yoq', 0)", lambda: o.get("yoq", 0)),
("'a' in o", lambda: "a" in o),
("list(o.keys())", lambda: list(o.keys())),
("list(o.values())", lambda: list(o.values())),
("list(o.items())", lambda: list(o.items())),
("len(o)", lambda: len(o)),
("dict(o)", lambda: dict(o)),
("o == {'a':1,'b':2,'c':3}", lambda: o == {"a": 1, "b": 2, "c": 3}),
]:
print(f" {kod:<28} → {f()!r}")
print(f"\n O'zgartirish:")
def _yoz():
o["d"] = 4 # ⚠️ o.__setitem__(...) emas — Mapping da bu metod YO'Q
# (u AttributeError berardi); sintaksis TypeError beradi
def _ochir():
del o["a"]
for kod, f in [
("o['d'] = 4", _yoz),
("del o['a']", _ochir),
]:
try:
f()
print(f" {kod:<16} ⚠️ o'tdi")
except TypeError as e:
print(f" {kod:<16} ✅ TypeError: {e}")
print("\n=== 4. Set ===\n")
class Diapazon(Set):
"""⭐ Diapazonni to'plam sifatida — elementlar saqlanmaydi."""
def __init__(self, boshlanish, tugash):
self.boshlanish, self.tugash = boshlanish, tugash
def __contains__(self, x):
return (isinstance(x, int)
and self.boshlanish <= x < self.tugash)
def __iter__(self):
return iter(range(self.boshlanish, self.tugash))
def __len__(self):
return max(0, self.tugash - self.boshlanish)
def __repr__(self):
return f"Diapazon({self.boshlanish}, {self.tugash})"
@classmethod
def _from_iterable(cls, it):
# ⚠️ Set ning &, |, -, ^ metodlari natijani cls(it) bilan yasaydi.
# Bizning konstruktor (boshlanish, tugash) kutadi → TypeError.
# Shuning uchun natijani oddiy frozenset qilib qaytaramiz.
return frozenset(it)
d1, d2 = Diapazon(0, 10), Diapazon(5, 15)
print(f" d1 = {d1}, d2 = {d2}\n")
for kod, f in [
("5 in d1", lambda: 5 in d1),
("len(d1)", lambda: len(d1)),
("d1 & d2", lambda: d1 & d2),
("d1 | d2", lambda: d1 | d2),
("d1 - d2", lambda: d1 - d2),
("d1 ^ d2", lambda: d1 ^ d2),
("d1 <= d2", lambda: d1 <= d2),
("d1.isdisjoint(Diapazon(20,30))",
lambda: d1.isdisjoint(Diapazon(20, 30))),
("set(d1) == set(range(10))", lambda: set(d1) == set(range(10))),
]:
natija = f()
if isinstance(natija, (set, frozenset)) and len(natija) > 6:
natija = f"{{{', '.join(map(str, sorted(natija)[:5]))}, ...}}"
print(f" {kod:<34} → {natija!r}")
print(f"""
⭐ __contains__, __iter__, __len__ yozdik —
BARCHA to'plam amallari bepul.
⚠️ Natija — oddiy set (yangi Diapazon emas).
_from_iterable() ni qayta aniqlash mumkin.
""")
print("=== ⚠️ 5. dict dan meros — tuzoq ===\n")
class YomonSozlama(dict):
"""⚠️ Kalitlarni kichik harfga o'girmoqchi."""
def __setitem__(self, k, v):
super().__setitem__(k.lower(), v)
class YaxshiSozlama(UserDict):
"""✅ UserDict — sof Python."""
def __setitem__(self, k, v):
super().__setitem__(k.lower(), v)
print(f" {'Amal':<28} {'dict avlodi':<24} {'UserDict avlodi'}")
print(" " + "─" * 74)
SINOVLAR = [
("Sinf(A=1)", lambda S: dict(S(A=1))),
("s['B'] = 2", None),
("s.update(C=3)", None),
("s.setdefault('D', 4)", None),
]
y1, y2 = YomonSozlama(A=1), YaxshiSozlama(A=1)
print(f" {'Sinf(A=1)':<28} {str(dict(y1)):<24} {dict(y2)}")
y1["B"] = 2; y2["B"] = 2
kod = "s['B'] = 2"
print(f" {kod:<28} {str(dict(y1)):<24} {dict(y2)}")
y1.update(C=3); y2.update(C=3)
print(f" {'s.update(C=3)':<28} {str(dict(y1)):<24} {dict(y2)}")
y1.setdefault("D", 4); y2.setdefault("D", 4)
kod = "s.setdefault('D', 4)"
print(f" {kod:<28} {str(dict(y1)):<24} {dict(y2)}")
print(f"""
⚠️ dict AVLODI:
• __init__, update, setdefault — C da yozilgan
• Ular __setitem__ ni CHAQIRMAYDI
• Faqat s['B'] = 2 ishlaydi
✅ UserDict:
• Sof Python, self.data lug'atini o'raydi
• Barcha metodlar __setitem__ orqali o'tadi
""")
print("=== 6. Amaliy: normallashtiruvchi lug'at ===\n")
class HttpSarlavhalar(UserDict):
"""HTTP sarlavhalari — katta-kichik harf farqlanmaydi."""
def __setitem__(self, k, v):
super().__setitem__(self._normalla(k), v)
def __getitem__(self, k):
return super().__getitem__(self._normalla(k))
def __delitem__(self, k):
super().__delitem__(self._normalla(k))
def __contains__(self, k):
return self._normalla(k) in self.data
@staticmethod
def _normalla(k: str) -> str:
return "-".join(q.capitalize() for q in str(k).split("-"))
h = HttpSarlavhalar()
h["content-type"] = "application/json"
h["CONTENT-LENGTH"] = "42"
h.update({"x-custom-header": "qiymat"})
print(f" Kiritildi: 'content-type', 'CONTENT-LENGTH', 'x-custom-header'")
print(f" Saqlandi:")
for k, v in h.items():
print(f" {k:<22} {v}")
print(f"\n Har xil yozuvda o'qish:")
for k in ["Content-Type", "content-type", "CONTENT-TYPE", "cOnTeNt-TyPe"]:
print(f" h[{k!r:<16}] = {h[k]!r}")
print(f"\n Boshqa amallar:")
print(f" 'content-type' in h = {'content-type' in h}")
print(f" h.get('YOQ', 'sukut') = {h.get('YOQ', 'sukut')!r}")
print(f" len(h) = {len(h)}")
del h["CONTENT-length"]
print(f" del h['CONTENT-length'] → {list(h.keys())}")
print(f"""
⭐ UserDict tufayli:
• __init__, update, setdefault — hammasi ishlaydi
• Faqat 4 metod qayta aniqlandi
• self.data — asl lug'at
""")Natijaning muhim qismi:
=== 1. Sequence — bepul metodlar ===
Metod QoldaRoyxat AbcRoyxat
──────────────────────────────────────────────
__contains__ ❌ ✅
__reversed__ ❌ ✅
index ❌ ✅
count ❌ ✅
=== 2. MutableSequence ===
s.append(4) s = Stack([1, 2, 3, 4])
s.pop() → 6 s = Stack([1, 2, 3, 4, 5])
s += [7] s = Stack([5, 4, 2, 99, 7])
⭐ 5 metod yozdik, 11+ metod BEPUL oldik.
=== ⚠️ 5. dict dan meros — tuzoq ===
Amal dict avlodi UserDict avlodi
──────────────────────────────────────────────────────────────────────
Sinf(A=1) {'A': 1} {'a': 1}
s['B'] = 2 {'A': 1, 'b': 2} {'a': 1, 'b': 2}
s.update(C=3) {'A': 1, 'b': 2, 'C': 3} {'a': 1, ..., 'c': 3}Nima ko'rsatdi: 2.7-bo'lim.
Misol 4 — Amaliy: matn korpusi
"""To'liq konteyner — barcha protokollar birga."""
from __future__ import annotations
import re
from collections.abc import Sequence, Mapping
from dataclasses import dataclass, field
from typing import Iterator, Any
print("=== MATN KORPUSI ===\n")
@dataclass(frozen=True, slots=True)
class Hujjat:
"""Korpusdagi bitta hujjat."""
id: int
sarlavha: str
matn: str
teglar: frozenset[str] = frozenset()
@property
def sozlar(self) -> tuple[str, ...]:
return tuple(re.findall(r"[^\W\d_]+", self.matn.lower()))
def __len__(self) -> int:
return len(self.sozlar)
def __contains__(self, soz: str) -> bool:
return soz.lower() in self.sozlar
def __repr__(self) -> str:
return f"Hujjat(#{self.id}, {self.sarlavha!r}, {len(self)} so'z)"
class Korpus(Sequence):
"""Hujjatlar to'plami.
PROTOKOLLAR:
Sequence — [i], kesish, iteratsiya, index, count
Mapping-kabi — ["sarlavha"] bilan ham topish
Container — hujjat yoki so'z bo'yicha `in`
Sized — len()
"""
def __init__(self, hujjatlar=()):
self._h: list[Hujjat] = list(hujjatlar)
self._indeks: dict[str, set[int]] | None = None
# ── Sequence protokoli ──
def __len__(self) -> int:
return len(self._h)
def __getitem__(self, i):
"""⭐ int, slice va str ni qo'llab-quvvatlaydi."""
if isinstance(i, slice):
return Korpus(self._h[i]) # ⭐ o'sha tur
if isinstance(i, int):
if i < 0:
i += len(self._h)
if not 0 <= i < len(self._h):
raise IndexError(f"indeks chegaradan tashqarida: {i}")
return self._h[i]
if isinstance(i, str):
for h in self._h:
if h.sarlavha == i:
return h
raise KeyError(f"sarlavha topilmadi: {i!r}")
raise TypeError(
f"indeks int, slice yoki str bo'lsin, "
f"{type(i).__name__} emas"
)
def __contains__(self, x) -> bool:
"""⭐ Hujjat, sarlavha yoki so'z bo'yicha."""
if isinstance(x, Hujjat):
return x in self._h
if isinstance(x, str):
return (any(h.sarlavha == x for h in self._h)
or any(x.lower() in h for h in self._h))
return False
def __iter__(self) -> Iterator[Hujjat]:
return iter(self._h)
def __reversed__(self) -> Iterator[Hujjat]:
return reversed(self._h)
# ── O'zgartirish ──
def qosh(self, h: Hujjat) -> "Korpus":
if not isinstance(h, Hujjat):
raise TypeError(f"Hujjat kutildi: {type(h).__name__}")
self._h.append(h)
self._indeks = None # kesh bekor
return self
def __iadd__(self, boshqa) -> "Korpus":
"""⭐ korpus += [hujjat, ...]"""
for h in boshqa:
self.qosh(h)
return self # ⭐ SHART
def __add__(self, boshqa) -> "Korpus":
"""⭐ YANGI korpus."""
if isinstance(boshqa, Korpus):
return Korpus(self._h + boshqa._h)
if isinstance(boshqa, (list, tuple)):
return Korpus(self._h + list(boshqa))
return NotImplemented
# ── To'plam kabi amallar ──
def __and__(self, boshqa: "Korpus") -> "Korpus":
"""Umumiy hujjatlar."""
if not isinstance(boshqa, Korpus):
return NotImplemented
idlar = {h.id for h in boshqa}
return Korpus(h for h in self._h if h.id in idlar)
def __or__(self, boshqa: "Korpus") -> "Korpus":
if not isinstance(boshqa, Korpus):
return NotImplemented
korilgan, natija = set(), []
for h in list(self._h) + list(boshqa):
if h.id not in korilgan:
korilgan.add(h.id)
natija.append(h)
return Korpus(natija)
def __sub__(self, boshqa: "Korpus") -> "Korpus":
if not isinstance(boshqa, Korpus):
return NotImplemented
idlar = {h.id for h in boshqa}
return Korpus(h for h in self._h if h.id not in idlar)
# ── Qidiruv ──
def _indeksni_qur(self) -> dict[str, set[int]]:
if self._indeks is None:
ind: dict[str, set[int]] = {}
for h in self._h:
for soz in set(h.sozlar):
ind.setdefault(soz, set()).add(h.id)
self._indeks = ind
return self._indeks
def qidir(self, *sozlar: str) -> "Korpus":
"""Barcha so'zlar bor hujjatlar."""
ind = self._indeksni_qur()
if not sozlar:
return Korpus(self._h)
natija = ind.get(sozlar[0].lower(), set())
for s in sozlar[1:]:
natija &= ind.get(s.lower(), set())
return Korpus(h for h in self._h if h.id in natija)
def teg_boyicha(self, *teglar: str) -> "Korpus":
kerak = frozenset(t.lower() for t in teglar)
return Korpus(h for h in self._h if kerak <= h.teglar)
def filtrla(self, shart) -> "Korpus":
return Korpus(h for h in self._h if shart(h))
# ── Statistika ──
@property
def sozlar_soni(self) -> int:
return sum(len(h) for h in self._h)
def chastota(self, n: int = 10) -> list[tuple[str, int]]:
hisob: dict[str, int] = {}
for h in self._h:
for s in h.sozlar:
hisob[s] = hisob.get(s, 0) + 1
return sorted(hisob.items(), key=lambda x: (-x[1], x[0]))[:n]
# ── Ko'rinish ──
def __repr__(self) -> str:
if len(self._h) <= 2:
ichki = ", ".join(repr(h) for h in self._h)
else:
ichki = (f"{self._h[0]!r}, ... yana {len(self._h) - 1}")
return f"Korpus([{ichki}])"
def __str__(self) -> str:
return f"Korpus: {len(self._h)} hujjat, {self.sozlar_soni} so'z"
def __bool__(self) -> bool:
return bool(self._h)
def __eq__(self, b) -> bool:
if not isinstance(b, Korpus):
return NotImplemented
return [h.id for h in self._h] == [h.id for h in b._h]
HUJJATLAR = [
Hujjat(1, "Python asoslari",
"Python oddiy va kuchli dasturlash tili. "
"Python o'rganish oson.",
frozenset({"python", "darslik"})),
Hujjat(2, "JavaScript kirish",
"JavaScript veb dasturlash uchun til. "
"JavaScript brauzerda ishlaydi.",
frozenset({"javascript", "veb"})),
Hujjat(3, "Ma'lumot tuzilmalari",
"Ro'yxat va lug'at Python dagi asosiy tuzilmalar. "
"Ular dasturlash uchun muhim.",
frozenset({"python", "algoritm", "darslik"})),
Hujjat(4, "Veb dasturlash",
"Veb dasturlash uchun Python va JavaScript ishlatiladi.",
frozenset({"python", "javascript", "veb"})),
Hujjat(5, "Algoritmlar",
"Saralash va qidirish algoritmlari dasturlash asosi.",
frozenset({"algoritm"})),
]
k = Korpus(HUJJATLAR)
print("1. Sequence protokoli:\n")
for kod, f in [
("len(k)", lambda: len(k)),
("k[0]", lambda: k[0]),
("k[-1]", lambda: k[-1]),
("k[1:3]", lambda: k[1:3]),
("k[::2]", lambda: k[::2]),
("k['Algoritmlar']", lambda: k["Algoritmlar"]),
("k.index(HUJJATLAR[2])", lambda: k.index(HUJJATLAR[2])),
("k.count(HUJJATLAR[0])", lambda: k.count(HUJJATLAR[0])),
("bool(k)", lambda: bool(k)),
("bool(Korpus())", lambda: bool(Korpus())),
]:
print(f" {kod:<24} → {f()!r}")
print(f"\n Xatolar:")
for kod, f in [
("k[100]", lambda: k[100]),
("k['yoq']", lambda: k["yoq"]),
("k[1.5]", lambda: k[1.5]),
]:
try:
f()
print(f" {kod:<16} ⚠️")
except (IndexError, KeyError, TypeError) as e:
print(f" {kod:<16} ✅ {type(e).__name__}: {str(e)[:40]}")
print("\n\n2. ⭐ __contains__ — uch xil:\n")
for x, izoh in [
(HUJJATLAR[0], "Hujjat obyekti"),
("Algoritmlar", "sarlavha"),
("python", "so'z (matn ichida)"),
("javascript", "so'z"),
("rust", "yo'q so'z"),
]:
korinish = repr(x) if not isinstance(x, Hujjat) else "HUJJATLAR[0]"
print(f" {korinish:<18} in k → {x in k!s:<7} ({izoh})")
print("\n\n3. Iteratsiya:\n")
print(f" for h in k:")
for h in k:
print(f" {h}")
print(f"\n reversed(k):")
for h in list(reversed(k))[:2]:
print(f" {h}")
print(f"\n Comprehension:")
uzunlar = [h.sarlavha for h in k if len(h) > 8]
print(f" 8 dan uzun: {uzunlar}")
print("\n\n4. Amallar:\n")
python_k = k.teg_boyicha("python")
veb_k = k.teg_boyicha("veb")
print(f" python teglilar: {[h.id for h in python_k]}")
print(f" veb teglilar: {[h.id for h in veb_k]}\n")
for kod, f in [
("python_k & veb_k", lambda: python_k & veb_k),
("python_k | veb_k", lambda: python_k | veb_k),
("python_k - veb_k", lambda: python_k - veb_k),
("k[:2] + k[3:]", lambda: k[:2] + k[3:]),
]:
natija = f()
print(f" {kod:<22} → {[h.id for h in natija]}")
print(f"\n += bilan:")
yangi = Korpus(k[:2])
print(f" yangi = Korpus(k[:2]) → {[h.id for h in yangi]}")
yangi += [HUJJATLAR[4]]
print(f" yangi += [HUJJATLAR[4]] → {[h.id for h in yangi]}")
print("\n\n5. Qidiruv:\n")
SOROVLAR = [
("python",),
("javascript",),
("python", "javascript"),
("dasturlash",),
("dasturlash", "python"),
("rust",),
]
for sorov in SOROVLAR:
natija = k.qidir(*sorov)
idlar = [h.id for h in natija]
print(f" qidir{sorov} → {idlar if idlar else '❌ topilmadi'}")
print(f"\n Teg bo'yicha:")
for teglar in [("python",), ("darslik",), ("python", "darslik"),
("python", "javascript")]:
natija = k.teg_boyicha(*teglar)
print(f" {str(teglar):<26} → {[h.id for h in natija]}")
print(f"\n Filtrlash:")
uzun = k.filtrla(lambda h: len(h) >= 10)
print(f" len(h) >= 10 → {[h.id for h in uzun]}")
print("\n\n6. Statistika:\n")
print(f" {k}")
print(f" Hujjatlar: {len(k)}")
print(f" So'zlar: {k.sozlar_soni}")
print(f" O'rtacha: {k.sozlar_soni / len(k):.1f} so'z/hujjat")
print(f"\n Eng ko'p uchraydigan so'zlar:")
for soz, n in k.chastota(8):
print(f" {soz:<16} {'█' * n} {n}")
print(f"\n Indeks hajmi: {len(k._indeksni_qur())} noyob so'z")
print("\n\n7. ABC tekshiruvi:\n")
from collections.abc import (Iterable, Container, Sized, Collection,
Reversible, Sequence as SeqABC)
print(f" {'Protokol':<16} {'Korpus':<10} {'Hujjat'}")
print(" " + "─" * 38)
for A in (Sized, Iterable, Container, Collection, Reversible, SeqABC):
kk = "✅" if isinstance(k, A) else "❌"
hh = "✅" if isinstance(HUJJATLAR[0], A) else "❌"
print(f" {A.__name__:<16} {kk:<10} {hh}")
print(f"""
⭐ BU SINFDA:
Sequence dan meros:
__getitem__, __len__ yozildi
index, count BEPUL olindi
Qayta aniqlangan (samaradorlik/qulaylik uchun):
__contains__ uch xil qidiruv
__iter__ to'g'ridan-to'g'ri
__reversed__ to'g'ridan-to'g'ri
Qo'shimcha protokollar:
__add__, __iadd__ birlashtirish
__and__, __or__, __sub__ to'plam amallari
__bool__, __eq__ mantiq
__repr__, __str__ ko'rinish
⭐ __getitem__ UCH turni qabul qiladi:
int → Hujjat
slice → Korpus (o'sha tur!)
str → sarlavha bo'yicha Hujjat
""")Natijaning muhim qismi:
1. Sequence protokoli:
k[1:3] → Korpus([Hujjat(#2, ...), Hujjat(#3, ...)])
k['Algoritmlar'] → Hujjat(#5, 'Algoritmlar', 6 so'z)
k.index(HUJJATLAR[2]) → 2
bool(Korpus()) → False
k[1.5] ✅ TypeError: indeks int, slice yoki str bo'lsin
2. ⭐ __contains__ — uch xil:
HUJJATLAR[0] in k → True (Hujjat obyekti)
'Algoritmlar' in k → True (sarlavha)
'python' in k → True (so'z (matn ichida))
'rust' in k → False (yo'q so'z)
5. Qidiruv:
qidir('python',) → [1, 3, 4]
qidir('python', 'javascript') → [4]
qidir('rust',) → ❌ topilmadi
7. ABC tekshiruvi:
Protokol Korpus Hujjat
──────────────────────────────────────
Sized ✅ ✅
Iterable ✅ ❌
Container ✅ ✅
Sequence ✅ ❌Nima ko'rsatdi: 2.1, 2.4, 2.5, 2.7-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
"for uchun __iter__ shart" |
__getitem__ ham yetadi (eski protokol) |
"__getitem__ bo'lsa Iterable" |
isinstance(x, Iterable) — False |
"__iter__ self qaytarishi kerak" |
Faqat iterator shunday qiladi |
"__contains__ bo'lsa for ishlaydi" |
Alohida protokollar |
"__len__ bo'lsa bool True" |
len() == 0 → False |
"__missing__ har sinfda ishlaydi" |
Faqat dict avlodlarida |
"dict dan meros olsa bo'ladi" |
C metodlari __setitem__ ni chaqirmaydi |
"Kesish list qaytarishi kerak" |
O'sha turni qaytaring |
6. Keng tarqalgan xatolar va yechimlari
1. Kesishni qo'llab-quvvatlamaslik
def __getitem__(self, i):
return self._el[i] # ⚠️ kesish list qaytaradi
if isinstance(i, slice): # ✅
return type(self)(self._el[i])2. Salbiy indeks
if i >= len(self._el): raise IndexError # ⚠️ -1 o'tib ketadi
if i < 0: i += len(self._el) # ✅3. __iter__ da self qaytarish
def __iter__(self): return self # ⚠️ bir martalik
def __iter__(self): yield from self._el # ✅4. KeyError bilan eski protokol
def __getitem__(self, k): return self._d[k] # ⚠️ for cheksiz
def __iter__(self): return iter(self._d) # ✅ aniq yozing5. dict dan meros
class A(dict): ... # ⚠️ update ishlamaydi
class A(UserDict): ... # ✅6. __len__ va __bool__ chalkashligi
if sozlama: # ⚠️ bo'sh bo'lsa False
if sozlama is not None: # ✅7. __iadd__ da return yo'q
def __iadd__(self, b):
self._el.extend(b) # ⚠️ None
return self # ✅8. ABC ni ishlatmaslik
class A: # ⚠️ 10 metod qo'lda
...
class A(Sequence): # ✅ 2 metod
...7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 6-qism (o'tilgan):
list,dict,set— bularning hammasi shu protokollar - 6.17-dars: generator ifodalari
- 8.9-dars:
Protocol, ABC - 10-qism: iteratorlar va generatorlar — chuqur
collections.abc,collections—UserDict,UserList,UserString- NumPy, pandas:
__getitem__bilan murakkab indekslash - PEP 234: iteratsiya protokoli
8. Eng yaxshi amaliyotlar
__iter__ni aniq yozing. Eski protokolga tayanmang.collections.abcdan meros oling. O'nlab metod bepul.Kesishda o'sha turni qaytaring.
type(self)(...).Salbiy indekslarni qo'llab-quvvatlang.
if i < 0: i += len(self).Noto'g'ri indeks turida
TypeError. Aniq xabar bilan.dict/listo'rnigaUserDict/UserList. Yoki kompozitsiya.__iter__generator bilan. Eng oson va to'g'ri yo'l.__len__bilan__bool__ni o'ylang. Bo'sh konteynerFalsebo'lishi kutilganmi?
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
1. class A:
def __getitem__(self, i):
if i >= 3: raise IndexError
return i
print(list(A()), 2 in A())
2. from collections.abc import Iterable
class A:
def __getitem__(self, i): raise IndexError
print(isinstance(A(), Iterable))
3. class A:
def __len__(self): return 0
print(bool(A()))
4. class A:
def __contains__(self, x): return True
try: print(list(A()))
except TypeError: print("TypeError")
5. class A:
def __init__(self): self.i = 0
def __iter__(self): return self
def __next__(self):
if self.i >= 2: raise StopIteration
self.i += 1
return self.i
a = A()
print(list(a), list(a))
6. class A:
def __getitem__(self, i): return i
print(A()[1:3])
7. print(slice(1, 10, 2).indices(5))
8. class A(dict):
def __setitem__(self, k, v): super().__setitem__(k.upper(), v)
a = A(x=1)
print(dict(a))
9. from collections import UserDict
class A(UserDict):
def __setitem__(self, k, v): super().__setitem__(k.upper(), v)
print(dict(A(x=1)))
10. class A(dict):
def __missing__(self, k): return k * 2
a = A()
print(a["ab"], a.get("ab"))
11. from collections.abc import Sequence
class A(Sequence):
def __getitem__(self, i): return [1,2,3][i]
def __len__(self): return 3
print(A().count(2), list(reversed(A())))
12. class A:
def __len__(self): return 3
try: print(A()[0])
except TypeError: print("TypeError")Javoblar
[0, 1, 2] TrueFalse—Iterablefaqat__iter__ni tekshiradiFalseTypeError—__iter__ham,__getitem__ham yo'q[1, 2] []— o'zi iterator, bir martalikslice(1, 3, None)— slice obyekti qaytdi(1, 5, 2){'x': 1}—__init____setitem__ni chaqirmadi{'X': 1}—abab None—get__missing__ni chaqirmaydi1 [3, 2, 1]TypeError
Vazifa 2: Xatolarni tuzating
1. def __getitem__(self, i): return self._el[i] # kesish
2. def __getitem__(self, i):
if i >= len(self._el): raise IndexError
return self._el[i]
3. def __iter__(self): return self
4. class Lugat:
def __getitem__(self, k): return self._d[k]
5. class Sozlama(dict):
def __setitem__(self, k, v): super().__setitem__(k.lower(), v)
6. def __iadd__(self, b): self._el.extend(b)
7. class A:
def __getitem__(self, i): return self._el[i]
# index, count, __contains__ qo'lda yozilgan
8. if sozlama: # bo'sh bo'lsa ham davom etsinJavoblar
1. if isinstance(i, slice): return type(self)(self._el[i])
2. if i < 0: i += len(self._el) qo'shing
3. yield from self._el (yoki alohida iterator sinfi)
4. __iter__ ni aniq yozing: return iter(self._d)
5. class Sozlama(UserDict)
6. return self qo'shing
7. class A(Sequence) — bepul metodlar
8. if sozlama is not None:Vazifa 3: Halqa (ring buffer)
Yozing:
- Belgilangan hajm, to'lganda eng eskisini o'chiradi
__len__,__getitem__(kesish bilan),__iter____setitem__,append,extend__contains__,__reversed__MutableSequencedan meros__repr__— to'lganini ko'rsatsin
Vazifa 4: Ikki tomonlama lug'at
kalit → qiymatvaqiymat → kalitMutableMappingdan merosteskarixususiyati- Takroriy qiymat —
ValueError __setitem__ikkalasini yangilasinUserDictbilan ham yozing, solishtiring
Vazifa 5: Dangasa fayl
- Katta faylni qatorma-qator o'qish
__len__— qatorlar soni (keshlangan)__getitem__— n-qator (indeks bilan tez)- Kesish qo'llab-quvvatlansin
__iter__— xotirani to'ldirmasin__contains__— matn qidirish
Vazifa 6: Ichma-ich lug'at
d["a.b.c"]→d["a"]["b"]["c"]__setitem__yo'lni yaratsin__delitem__,__contains____iter__— barcha yo'llarni bersintekis()vachuqur()metodlariMutableMappingdan meros
Vazifa 7: O'ylash
Nega Python __getitem__ orqali iteratsiyani (eski protokol) hali ham qo'llab-quvvatlaydi — nega uni olib tashlamadi?
Javob
Chunki orqaga moslik — Pythonning eng muhim kafolatlaridan biri, va olib tashlash foydasi zaridan kam.
1. Tarixiy kontekst
Python 2.0 (2000) gacha iteratsiya protokoli yo'q edi. for shunday ishlardi:
for x in obj:
...
# Aslida:
i = 0
while True:
try:
x = obj[i]
except IndexError:
break
...
i += 1 Ya'ni __getitem__ — yagona iteratsiya usuli edi.
PEP 234 (2001, Python 2.2) __iter__/__next__ protokolini qo'shdi. Sabablari:
- Samaradorlik — indeks hisoblash kerak emas
- Ketma-ketlik bo'lmagan turlar —
dict,set,file - Cheksiz iteratsiya — generatorlar
- Holat saqlash — iterator o'z holatini biladi
Lekin eski protokol saqlanib qoldi.
2. Nima uchun olib tashlanmadi
a) Buzilgan kod hajmi
# 2000-2002 yillarda yozilgan minglab sinflar:
class MeningRoyxatim:
def __getitem__(self, i): ...
def __len__(self): ...
# __iter__ YO'Q — o'sha paytda kerak emas ediBunday kod hali ham ishlaydi — ilmiy kutubxonalar, ichki korporativ kodlar, eski loyihalar.
b) Python 3 ga o'tish tajribasi
Python 2 → 3 o'tishi 11 yil davom etdi (2008-2020). Jamoa buzilishlarga juda sezgir bo'lib qoldi.
Guido va boshqa asosiy ishlab chiquvchilar bir necha marta aytdi: "biz yana bir Python 3 ni qilmaymiz".
c) Foydasi kam
Olib tashlash nima beradi?
- Kod soddalashadi (
iter()da bitta shox kamayadi) — juda kichik - Xatolar erta aniqlanadi — lekin
mypybuni allaqachon qiladi
Nima yo'qotamiz?
- Ishlaydigan kod buziladi
- Foydalanuvchilar ishonchi
Bu — noto'g'ri savdo.
3. Amalda hali ham foydali
Ba'zi hollarda __getitem__ — tabiiy interfeys:
class Dangasa:
"""Hisoblanadigan ketma-ketlik."""
def __init__(self, n, f): self.n, self.f = n, f
def __len__(self): return self.n
def __getitem__(self, i):
if i >= self.n: raise IndexError
return self.f(i)
kvadratlar = Dangasa(10**6, lambda i: i**2)
kvadratlar[500] # ✅ to'g'ridan-to'g'ri
for x in kvadratlar: ... # ✅ ham ishlaydi __iter__ yozish ortiqcha bo'lardi — __getitem__ allaqachon hamma narsani biladi.
4. Lekin tuzoqlari bor
class Lugat:
def __getitem__(self, k): return self._d[k]
for x in Lugat():
...Lugat()[0] → KeyError, IndexError emas → tsikl to'xtamaydi va KeyError chiqadi.
Xato xabari chalkash:
KeyError: 0Foydalanuvchi "nega 0 kaliti qidirilyapti?" deb hayron bo'ladi.
Yana bir tuzoq:
from collections.abc import Iterable
class A:
def __getitem__(self, i): ...
isinstance(A(), Iterable) # False ⚠️
list(A()) # ✅ ishlaydi isinstance va amaliyot mos kelmaydi — bu chalkash.
5. Qanday hal qilingan
Python muammoni olib tashlash o'rniga hujjatlash bilan hal qildi:
a) Rasmiy hujjatda ogohlantirish:
"Objects can also provide the older iteration protocol using
__getitem__()... but this is deprecated in favor of__iter__()."
b) collections.abc aniq:
Iterable → faqat __iter__
Sequence → __getitem__ + __len__ (va __iter__ ni BERADI) Sequence dan meros olsangiz — __iter__ bepul olasiz:
class A(Sequence):
def __getitem__(self, i): ...
def __len__(self): ...
isinstance(A(), Iterable) # True ✅c) mypy tekshiradi:
def f(x: Iterable[int]): ...
class A:
def __getitem__(self, i) -> int: ...
f(A())
# mypy: Argument 1 has incompatible type "A"; expected "Iterable[int]"6. Boshqa tillar
| Til | Yondashuv |
|---|---|
| Python | Ikki protokol (eski saqlangan) |
| Java | Iterable<T> interfeysi (bitta) |
| C# | IEnumerable<T> (bitta) |
| Ruby | each metodi + Enumerable modul |
| JavaScript | Symbol.iterator (ES6 da qo'shildi) |
| Rust | IntoIterator trait |
| Go | range — faqat o'rnatilgan turlar (1.23 gacha) |
JavaScript ham shunday muammoni boshdan kechirdi:
// ES5 gacha:
for (var i = 0; i < arr.length; i++) { ... }
// ES6:
for (const x of iterable) { ... } // Symbol.iteratorJavaScript eski usulni olib tashlamadi — ikkalasi ham ishlaydi.
Go 1.23 (2024) da:
// Oldin: faqat slice, map, chan
for i, v := range slice { ... }
// 1.23: range over func
for v := range mening_iteratorim { ... }Go ham eskisini saqlab, yangisini qo'shdi.
7. Deprecation siyosati
Python nimani olib tashlaydi?
| Turi | Misol | Natija |
|---|---|---|
| Xavfsizlik xavfi | crypt moduli |
Olib tashlandi (3.13) |
| Buzilgan API | asyncio.async |
Olib tashlandi |
| Kam ishlatiladigan modul | imp, distutils |
Olib tashlandi |
| Ishlaydigan xatti-harakat | eski iteratsiya | Saqlanadi |
Qoida: agar biror narsa ishlaydi va zarar keltirmaydi — u qoladi.
PEP 387 (Backwards Compatibility Policy) buni rasmiylashtirdi:
Xatti-harakatni o'zgartirish uchun kamida ikki versiya ogohlantirish kerak, va o'zgarish jiddiy sabab talab qiladi.
8. Shunga o'xshash misollar
Pythonda saqlanib qolgan boshqa "eski" narsalar:
# 1. % formatlash (f-string bo'lsa ham)
"%s" % x # ✅ hali ishlaydi
# 2. dict.has_key() — ❌ olib tashlangan (Python 3 da)
# 3. Eski uslub sinflar — ❌ olib tashlangan (Python 3 da)
# 4. __cmp__ — ❌ olib tashlangan
# 5. Eski iteratsiya — ✅ saqlanib qoldiNaqsh: Python 3 ga o'tishda katta tozalash bo'ldi. Undan keyin — juda ehtiyotkorlik.
9. Amaliy tavsiya
# ⭐ 1. Yangi kodda __iter__ yozing
class A:
def __iter__(self):
yield from self._el
# ⭐ 2. Yoki ABC dan meros oling
class A(Sequence):
def __getitem__(self, i): ...
def __len__(self): ...
# __iter__ bepul
# ⚠️ 3. __getitem__ satr kalitini oladi bo'lsa —
# __iter__ ni ALBATTA yozing
class Lugat:
def __getitem__(self, k): return self._d[k]
def __iter__(self): return iter(self._d) # ⭐ SHART
# ⭐ 4. mypy ishlating
def f(x: Iterable[int]): ...10. Xulosa
Eski protokol saqlanadi, chunki:
- Orqaga moslik — Pythonning asosiy va'dasi
- Ishlaydigan kod buzilmasligi kerak — millionlab qator
- Foydasi kam — olib tashlash deyarli hech narsa bermaydi
- Python 3 travmasi — jamoa katta buzilishlarga tayyor emas
- Ba'zan tabiiy — hisoblanadigan ketma-ketliklar uchun
Umumiy dars: til dizaynida "toza" yechim har doim ham to'g'ri yechim emas. Pythonning muvaffaqiyati qisman shunda — u ishlaydigan kodni buzmaydi.
Guido van Rossum:
"Har bir eskirgan xususiyat — kimningdir ishlayotgan dasturi. Uni olib tashlash — o'sha odamning ishini buzish."
Nimani mustahkamlaydi: 2.2, 2.7-bo'limlar.
Xulosa
Bu darsda konteyner protokollarini o'rgandik.
Eng muhim uch fikr:
Iteratsiya ikki yo'l bilan ishlaydi.
iter(x)avval__iter__ni qidiradi; topilmasa__getitem__ni0, 1, 2, ...bilanIndexErrorgacha chaqiradi (Python 2.0 dan qolgan eski protokol). Shuning uchun__getitem__yozilgan sinfforbilan ishlaydi, lekinisinstance(x, Iterable)—False. Yangi kodda__iter__ni aniq yozing, ayniqsa kalitlar satr bo'lsa (aks holdaKeyErrorbilan buziladi).collections.abc— o'nlab metodni bepul beradi.Sequencedan meros olsangiz,__getitem__va__len__yozib,__contains__,__iter__,__reversed__,index,countni olasiz.MutableSequenceesa 5 metoddanappend,pop,remove,extend,__iadd__va boshqalarni yasaydi.__getitem__uch holatni qayta ishlashi kerak.int(salbiy indeksni ham),slice(natija o'sha turda bo'lsin) va boshqa turlar uchun aniqTypeError.dict/listdan meros olish o'rnigaUserDict/UserListishlating — C da yozilgan metodlar sizning__setitem__ingizni chaqirmaydi.
Keyingi darsda @property ni chuqur ko'ramiz: deskriptor protokoli, getter/setter/deleter va hisoblanadigan atributlarni to'g'ri loyihalash.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!