collections — Counter, defaultdict, deque, namedtuple

~20 daq · Python · Modullar va Standart kutubxona

Muammodan boshlaylik

Uch xil kod — har biri tez-tez yoziladi:

# 1. sanash
hisob = {}
for soz in sozlar:
    if soz not in hisob:
        hisob[soz] = 0
    hisob[soz] += 1

# 2. guruhlash
guruhlar = {}
for t in talabalar:
    if t["guruh"] not in guruhlar:
        guruhlar[t["guruh"]] = []
    guruhlar[t["guruh"]].append(t["ism"])

# 3. oxirgi 100 ta hodisa
oxirgilar = []
oxirgilar.append(hodisa)
if len(oxirgilar) > 100:
    oxirgilar.pop(0)       # sekin — butun ro'yxat suriladi

collections moduli bu vazifalar uchun maxsus, tez va qisqa konteynerlarni beradi.


Hayotiy o'xshatma

Oddiy quti (dict, list) — har narsaga yaraydi. Lekin oshxonada maxsus idishlar ham bor: tuxum uchun katakli quti, ziravorlar uchun aylanuvchi javon. Ular oddiy qutining ishini qilmaydi, lekin o'z ishini ancha qulay bajaradi.


Counter — sanash

from collections import Counter

sozlar = "olma nok olma uzum nok olma anor".split()
hisob = Counter(sozlar)

print(hisob)                    # Counter({'olma': 3, 'nok': 2, 'uzum': 1, 'anor': 1})
print(hisob["olma"])            # 3
print(hisob["banan"])           # 0 — yo'q kalit uchun KeyError emas
print(hisob.most_common(2))     # [('olma', 3), ('nok', 2)]
harflar = Counter("assalomu alaykum")
print(harflar.most_common(3))   # [('a', 4), ('s', 2), ('l', 2)]

Yangilash va amallar

savdo = Counter({"olma": 10, "nok": 5})
savdo.update({"olma": 3, "uzum": 7})
print(savdo)                    # Counter({'olma': 13, 'uzum': 7, 'nok': 5})

kecha = Counter(olma=10, nok=5)
bugun = Counter(olma=7, nok=8)
print(kecha + bugun)            # Counter({'olma': 17, 'nok': 13})
print(kecha - bugun)            # Counter({'olma': 3}) — manfiylar tashlab yuboriladi

print(sum(savdo.values()))      # jami: 25
print(savdo.total())            # Python 3.10+: 25

Amaliy: eng ko'p sotilgan mahsulotlar, eng faol foydalanuvchilar, so'z chastotasi, takrorlanishlarni topish.

emaillar = ["a@x.uz", "b@x.uz", "a@x.uz"]
takrorlar = [e for e, son in Counter(emaillar).items() if son > 1]

defaultdict — standart qiymatli dictionary

from collections import defaultdict

guruhlar = defaultdict(list)
for t in talabalar:
    guruhlar[t["guruh"]].append(t["ism"])     # kalit yo'q bo'lsa — avtomatik []

print(dict(guruhlar))
# {'A': ['Lola', 'Bobur'], 'B': ['Aziz']}

defaultdict(fabrika) — mavjud bo'lmagan kalitga murojaat qilinganda fabrika() chaqirilib, natija avtomatik qo'yiladi.

Fabrika Standart qiymat Qachon
list [] Guruhlash
int 0 Sanash, yig'indi
set set() Noyob qiymatlarni guruhlash
dict {} Ichma-ich tuzilma
lambda: "noma'lum" "noma'lum" O'z standart qiymatingiz
tushum = defaultdict(int)
for kategoriya, summa in sotuvlar:
    tushum[kategoriya] += summa

[!WARNING] defaultdict da faqat o'qish ham kalitni yaratadi: if guruhlar["Z"]: — endi lug'atda "Z": [] paydo bo'ldi. Kalit borligini tekshirish uchun — "Z" in guruhlar, yoki oddiy dict.get().


deque — ikki tomonlama navbat

from collections import deque

navbat = deque(["Lola", "Aziz"])
navbat.append("Bobur")          # oxiriga
navbat.appendleft("Sardor")     # boshiga
print(navbat.popleft())         # Sardor — boshidan olish
print(navbat.pop())             # Bobur — oxiridan
Amal list deque
Oxiriga qo'shish/olish Tez Tez
Boshiga qo'shish/olish Sekin (hamma elementlar suriladi) Tez
Indeks bo'yicha o'rtasidan Tez Sekinroq

Navbat (FIFO) uchun — deque, list.pop(0) emas.

Cheklangan uzunlik — maxlen

oxirgi_qidiruvlar = deque(maxlen=5)

for soz in ["python", "django", "flask", "fastapi", "numpy", "pandas"]:
    oxirgi_qidiruvlar.append(soz)

print(oxirgi_qidiruvlar)   # deque(['django', 'flask', 'fastapi', 'numpy', 'pandas'], maxlen=5)

To'lganda eng eskisi avtomatik chiqib ketadi — "oxirgi N ta" uchun ideal: loglar, tarix, harakatlanuvchi o'rtacha.

navbat.rotate(1)     # elementlarni aylantirish

namedtuple — nomli maydonli tuple

from collections import namedtuple

Nuqta = namedtuple("Nuqta", ["x", "y"])
Talaba = namedtuple("Talaba", "ism yosh guruh")

p = Nuqta(3, 4)
print(p.x, p.y)          # 3 4 — nom bilan
print(p[0])              # 3 — indeks bilan ham

t = Talaba("Lola", 20, "A")
print(t)                 # Talaba(ism='Lola', yosh=20, guruh='A')
ism, yosh, guruh = t     # unpacking

t2 = t._replace(yosh=21) # o'zgarmas — yangi nusxa
print(t._asdict())       # {'ism': 'Lola', 'yosh': 20, 'guruh': 'A'}
  • Tuple kabi o'zgarmas va yengil
  • t[1] o'rniga t.yosh — o'qishli
  • Funksiyadan bir nechta qiymat qaytarishda (12-dars) — aniqroq

[!TIP] Zamonaviy kodda namedtuple o'rniga ko'pincha typing.NamedTuple (tur ko'rsatkichlari bilan) yoki @dataclass (49-dars, o'zgaruvchan bo'lishi mumkin, metodlar qo'shish oson) ishlatiladi: class Nuqta(NamedTuple): x: float; y: float


OrderedDict va ChainMap — qisqacha

from collections import OrderedDict, ChainMap

# Python 3.7+ da oddiy dict ham tartibni saqlaydi;
# OrderedDict — move_to_end() va tartibga sezgir solishtirish uchun
od = OrderedDict(a=1, b=2)
od.move_to_end("a")

# bir nechta lug'atni bitta ko'rinishda qidirish (birinchisi ustun)
sozlama = ChainMap(cli_argumentlar, muhit_ozgaruvchilari, standart)

Amaliy misol — log tahlili

from collections import Counter, defaultdict, deque

loglar = [
    "10:01 ERROR db ulanish uzildi",
    "10:02 INFO foydalanuvchi kirdi",
    "10:03 ERROR db ulanish uzildi",
    "10:04 WARN sekin so'rov",
    "10:05 ERROR to'lov rad etildi",
]

darajalar = Counter(q.split()[1] for q in loglar)
xatolar = defaultdict(list)
oxirgi_3 = deque(maxlen=3)

for q in loglar:
    vaqt, daraja, *xabar = q.split()
    if daraja == "ERROR":
        xatolar[" ".join(xabar)].append(vaqt)
    oxirgi_3.append(q)

print(darajalar.most_common())     # [('ERROR', 3), ('INFO', 1), ('WARN', 1)]
for xabar, vaqtlar in xatolar.items():
    print(f"{xabar}: {len(vaqtlar)} marta ({', '.join(vaqtlar)})")
print(list(oxirgi_3))

Tez-tez uchraydigan xatolar

list.pop(0) bilan navbat — katta ro'yxatda sekin; deque.popleft().

defaultdict da o'qish kalit yaratadi — in bilan tekshiring.

namedtuple ni o'zgartirishga urinish:

t.yosh = 21          # ❌ AttributeError
t = t._replace(yosh=21)   # ✅

Xulosa

collections — tez-tez uchraydigan vazifalar uchun tayyor konteynerlar.

Eslab qoling:

  • Counter — sanash; most_common(n), yo'q kalit — 0, +/-
  • defaultdict(list/int/set) — guruhlash va yig'ish; o'qish ham kalit yaratadi
  • deque — ikki tomondan tez; navbat — popleft(); maxlen — "oxirgi N ta"
  • namedtuple — nomli maydonli o'zgarmas tuple; _replace, _asdict
  • Zamonaviy alternativa — typing.NamedTuple, @dataclass

Keyingi dars

44-dars: re — regular expressions, match, search, findall, sub, groups