IlmHamroh
Python kursi/Malumot tuzilmalari11/18-dars32 daqiqa
Mundarija (21)

6.11-dars: dict metodlari

6-QISM — MA'LUMOT TUZILMALARI · 11-dars


1. Kirish va motivatsiya

dict da 11 ta metod bor — list bilan bir xil son. Lekin ularning nozikliklari ko'proq:

python
d.get(k)                    # None qaytaradi
d.get(k, sukut)             # sukut qaytaradi
d.setdefault(k, sukut)      # sukut qaytaradi VA QO'SHADI
d.pop(k, sukut)             # o'chirib qaytaradi

Uchtasi "sukut qiymat" bilan ishlaydi, lekin uchalasi turlicha xatti-harakat qiladi. Qaysi birini qachon?

Va amaliy savol: sanash vazifasi. To'rt xil yozish mumkin:

python
# 1
hisob = {}
for x in malumot:
    if x in hisob:
        hisob[x] += 1
    else:
        hisob[x] = 1

# 2
hisob = {}
for x in malumot:
    hisob[x] = hisob.get(x, 0) + 1

# 3
from collections import defaultdict
hisob = defaultdict(int)
for x in malumot:
    hisob[x] += 1

# 4
from collections import Counter
hisob = Counter(malumot)

Qaysi biri eng yaxshi? Nega?

Bu darsda:

  • Barcha 11 metod va murakkabligi
  • get vs setdefault vs pop — aniq farqlar
  • update ning barcha shakllari
  • collections: defaultdict, Counter, ChainMap, OrderedDict
  • Sanash, guruhlash, invertlash naqshlari
  • Tezlik solishtirilishi

2. Nazariya — chuqur tushuntirish

2.1. Barcha metodlar

python
d = {"a": 1}
print([m for m in dir(d) if not m.startswith("_")])
text
['clear', 'copy', 'fromkeys', 'get', 'items', 'keys',
 'pop', 'popitem', 'setdefault', 'update', 'values']
Metod Nima qiladi Qaytaradi Murakkablik
get(k, s=None) Xavfsiz o'qish Qiymat yoki s O(1)
setdefault(k, s=None) O'qish + qo'shish Qiymat yoki s O(1)
pop(k[, s]) O'chirib qaytarish Qiymat O(1)
popitem() Oxirgi juftlikni (k, v) O(1)
update(...) Birlashtirish None O(k)
clear() Tozalash None O(1)
copy() Sayoz nusxa Yangi dict O(n)
keys() Kalitlar ko'rinishi View O(1)
values() Qiymatlar ko'rinishi View O(1)
items() Juftliklar ko'rinishi View O(1)
fromkeys(k, v) Sinf metodi Yangi dict O(n)

clear() — O(1), list.clear() esa O(n). Lug'at butun jadvalni bir marta bo'shatadi.

2.2. get vs setdefault vs pop

Uchalasi ham "sukut qiymat" bilan ishlaydi, lekin farqli:

python
d = {"a": 1}

d.get("b", 0)                   # 0    — d o'zgarmaydi
print(d)                        # {'a': 1}

d.setdefault("b", 0)            # 0    — d GA QO'SHILDI
print(d)                        # {'a': 1, 'b': 0}

d.pop("b", 0)                   # 0    — d dan O'CHIRILDI
print(d)                        # {'a': 1}

Jadval:

Kalit bor Kalit yo'q d o'zgaradi
get(k, s) Qiymat s
setdefault(k, s) Qiymat s qo'shadi
pop(k, s) Qiymat s o'chiradi
pop(k) Qiymat KeyError
d[k] Qiymat KeyError

setdefault nomi chalkash. U "sukut qiymatni o'rnatish" emas, "yo'q bo'lsa qo'yish va qaytarish". Aniqroq nom get_or_set bo'lardi.

Sukut qiymat DOIM hisoblanadi:

python
d.setdefault(k, qimmat_funksiya())      # ⚠️ kalit bor bo'lsa ham chaqiriladi
d.get(k, qimmat_funksiya())             # ⚠️ ham chaqiriladi
d.pop(k, qimmat_funksiya())             # ⚠️ ham

Bu — Python semantikasi: argumentlar funksiya chaqirilishidan oldin hisoblanadi. Dangasa hisoblash uchun:

python
if k not in d:
    d[k] = qimmat_funksiya()            # ✅ faqat kerak bo'lganda

setdefault ning klassik qo'llanishi — guruhlash:

python
guruhlar = {}
for soz in sozlar:
    guruhlar.setdefault(soz[0], []).append(soz)

Lekin defaultdict yaxshiroq (2.4-bo'lim).

2.3. update — barcha shakllar

python
d.update(boshqa_lugat)
d.update([("a", 1), ("b", 2)])          # juftliklar
d.update(zip("ab", [1, 2]))             # zip
d.update(a=1, b=2)                      # nomli argumentlar
d.update({"a": 1}, b=2)                 # aralash
d.update()                              # hech narsa

Nomli argumentlar oxirida va kalitlar identifikator bo'lishi kerak:

python
d.update(a=1)                           # ✅
d.update(**{"1-kalit": 1})              # ⚠️ ishlaydi
d.update({"1-kalit": 1})                # ✅ toza usul

update None qaytaradi:

python
d = d.update({"a": 1})                  # ❌ d endi None!
d.update({"a": 1})                      # ✅
yangi = d | {"a": 1}                    # ✅ yangi lug'at

Chuqur birlashtirish emas:

python
d1 = {"a": {"x": 1, "y": 2}}
d2 = {"a": {"x": 99}}
d1.update(d2)
print(d1)                               # {'a': {'x': 99}}  ← 'y' YO'QOLDI

update — sayoz. Ichma-ich lug'atlar to'liq almashtiriladi. Chuqur birlashtirish uchun rekursiv funksiya kerak (4-misolda).

2.4. collections.defaultdict

defaultdict — yo'q kalitga murojaat qilganda avtomatik sukut qiymat yaratadi.

python
from collections import defaultdict

d = defaultdict(list)
d["a"].append(1)                        # 'a' yo'q edi — [] yaratildi
print(d)                                # defaultdict(<class 'list'>, {'a': [1]})

Konstruktor argumenti — CHAQIRILADIGAN (callable):

python
defaultdict(list)                       # []
defaultdict(int)                        # 0
defaultdict(set)                        # set()
defaultdict(dict)                       # {}
defaultdict(str)                        # ""
defaultdict(lambda: "yo'q")             # "yo'q"
defaultdict(lambda: [0] * 3)            # [0, 0, 0]

Chaqiriladigan, qiymat emas:

python
defaultdict(0)                          # ❌ TypeError: first argument must be callable
defaultdict(int)                        # ✅ int() → 0
defaultdict(lambda: 0)                  # ✅

Murojaat ham kalit YARATADI:

python
d = defaultdict(int)
print(d["yo'q"])                        # 0
print(d)                                # {"yo'q": 0}  ← QO'SHILDI!
print(len(d))                           # 1

Bu — eng ko'p uchraydigan tuzoq. Tekshirish uchun:

python
if k in d:                              # ✅ kalit yaratmaydi
d.get(k)                                # ✅ kalit yaratmaydi
d[k]                                    # ⚠️ YARATADI

__missing__ — ichki mexanizm:

python
class Mening(dict):
    def __missing__(self, kalit):
        qiymat = f"sukut-{kalit}"
        self[kalit] = qiymat            # ixtiyoriy — saqlash
        return qiymat

d = Mening()
print(d["x"])                           # sukut-x

defaultdict aynan shunday ishlaydi. __missing__ faqat d[k] uchun chaqiriladi — get uchun emas.

default_factory ni o'zgartirish:

python
d = defaultdict(list)
d.default_factory = None                # endi oddiy dict kabi
d["yo'q"]                               # ❌ KeyError

defaultdict vs setdefault vs get:

python
# Sanash
hisob = defaultdict(int)
for x in m: hisob[x] += 1               # ✅ eng tez

hisob = {}
for x in m: hisob[x] = hisob.get(x, 0) + 1      # ✅ oddiy dict

# Guruhlash
guruh = defaultdict(list)
for x in m: guruh[kalit(x)].append(x)   # ✅ eng tez

guruh = {}
for x in m: guruh.setdefault(kalit(x), []).append(x)

2.5. collections.Counter

Counter — sanash uchun maxsus lug'at (defaultdict(int) ning kengaytmasi).

python
from collections import Counter

c = Counter("mississippi")
# Counter({'i': 4, 's': 4, 'p': 2, 'm': 1})

c = Counter([1, 1, 2, 3])               # ro'yxatdan
c = Counter({"a": 3, "b": 1})           # lug'atdan
c = Counter(a=3, b=1)                   # nomli argument

Metodlar:

python
c.most_common()                         # [('i',4), ('s',4), ('p',2), ('m',1)]
c.most_common(2)                        # eng ko'p 2 tasi
c.total()                               # 11 — barcha sanoqlar (3.10+)
c.elements()                            # iterator: i,i,i,i,s,s,s,s,p,p,m
c.subtract(boshqa)                      # ayirish (manfiy bo'lishi mumkin)
c.update(boshqa)                        # qo'shish

Yo'q kalit — KeyError emas, 0:

python
c = Counter("abc")
c["z"]                                  # 0 — xato yo'q
print(c)                                # Counter({'a':1,'b':1,'c':1})  ← qo'shilmadi!

defaultdict dan farq: Counter yo'q kalitni qo'shmaydi.

Arifmetik amallar:

python
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2, c=1)

c1 + c2                                 # Counter({'a':4, 'b':3, 'c':1})
c1 - c2                                 # Counter({'a':2})  ← manfiylar tushib qoladi
c1 & c2                                 # Counter({'a':1, 'b':1})  — min
c1 | c2                                 # Counter({'a':3, 'b':2, 'c':1})  — max

- manfiy va nol sanoqlarni olib tashlaydi:

python
Counter(a=1) - Counter(a=3)             # Counter()  ← bo'sh
Counter(a=1).subtract(Counter(a=3))     # Counter({'a': -2})  ← saqlanadi

Amaliy misollar:

python
# Eng ko'p uchraydigan so'zlar
Counter(matn.split()).most_common(10)

# Ikki matn o'xshashligi
umumiy = Counter(a) & Counter(b)
oxshashlik = sum(umumiy.values()) / max(len(a), len(b))

# Anagram tekshiruvi
Counter("listen") == Counter("silent")  # True

# Takrorlarni topish
{x for x, n in Counter(r).items() if n > 1}

2.6. ChainMap va OrderedDict

ChainMap — bir nechta lug'atni birlashtirmasdan ko'rish:

python
from collections import ChainMap

standart = {"til": "uz", "tema": "yorug'"}
foydalanuvchi = {"tema": "qorong'i"}

sozlamalar = ChainMap(foydalanuvchi, standart)
sozlamalar["tema"]                      # "qorong'i"  ← birinchi topilgani
sozlamalar["til"]                       # "uz"

Nusxa yaratmaydi — qidiruv zanjir bo'ylab ketadi.

python
foydalanuvchi["til"] = "en"
sozlamalar["til"]                       # "en"  ← avtomatik yangilandi

Yozish — faqat birinchi lug'atga:

python
sozlamalar["yangi"] = 1
print(foydalanuvchi)                    # {'tema': "qorong'i", 'yangi': 1}
print(standart)                         # o'zgarmadi

Qachon foydali:

  • Konfiguratsiya qatlamlari (CLI → muhit → fayl → standart)
  • Vaqtinchalik o'zgarishlar (new_child())
  • Nom fazolari (Python o'zi locals → globals → builtins uchun ishlatadi)
python
vaqtinchalik = sozlamalar.new_child({"debug": True})
# Asl zanjir o'zgarmaydi

OrderedDict — 3.7 dan keyin ham foydali:

python
from collections import OrderedDict

od = OrderedDict([("a", 1), ("b", 2)])

dict tartibni saqlagach, OrderedDict deyarli keraksiz. Lekin uch farq qoldi:

1. Tenglikda tartib muhim:

python
OrderedDict(a=1, b=2) == OrderedDict(b=2, a=1)      # False
dict(a=1, b=2) == dict(b=2, a=1)                    # True

2. move_to_end:

python
od.move_to_end("a")                     # oxirga
od.move_to_end("a", last=False)         # boshiga

3. popitem(last=False) — FIFO:

python
od.popitem()                            # oxirgisi (LIFO)
od.popitem(last=False)                  # birinchisi (FIFO)
d.popitem()                             # faqat LIFO

Shuning uchun LRU kesh yozishda OrderedDict hali ham qulay.

2.7. Tezlik solishtirilishi

Sanash vazifasi uchun (100k element):

Usul Nisbiy tezlik
Counter(malumot) 1.0x (C da)
defaultdict(int) ~2.5x
d.get(x, 0) + 1 ~3.2x
if x in d: ... else: ... ~3.0x
d.setdefault(x, 0) ~4.5x
try/except KeyError ~3.5x (xatolar kam bo'lsa tezroq)

Counter(iterable) — C darajasida optimallashtirilgan (_count_elements).

Lekin Counter ni siklda yangilash sekin:

python
c = Counter()
for x in m:
    c[x] += 1                           # ⚠️ defaultdict dan sekinroq

c = Counter(m)                          # ✅ eng tez

Umumiy tavsiya:

Sanash:              Counter(iterable)
Guruhlash:           defaultdict(list)
Qatlamlar:           ChainMap
Bir marta o'qish:    d.get(k, sukut)
LRU/FIFO:            OrderedDict
Oddiy holat:         oddiy dict

3. Tez ma'lumotnoma

11 metod

python
get(k, s)           o'qish, d o'zgarmaydi
setdefault(k, s)    o'qish + QO'SHADI ⭐
pop(k[, s])         o'chirib qaytaradi
popitem()           oxirgi juftlik (LIFO, 3.7+)
update(...)         birlashtirish, None qaytaradi
clear()             O(1) ⭐ (list.clear O(n))
copy()              sayoz
keys/values/items   ko'rinishlar
fromkeys(k, v)      sinf metodi

Sukut qiymat DOIM hisoblanadi

python
d.setdefault(k, qimmat())   ⚠️ kalit bor bo'lsa ham
if k not in d: d[k] = qimmat()      ✅

collections

python
defaultdict(list)       d[k].append(x)      ⚠️ murojaat KALIT YARATADI
defaultdict(int)        d[k] += 1
Counter(iterable)       ⭐ eng tez sanash
    most_common(n), total(), elements()
    + - & |    (- manfiylarni tushiradi)
    c["yo'q"] → 0, kalit QO'SHILMAYDI
ChainMap(d1, d2)        nusxasiz qatlamlar, yozish → d1
OrderedDict             tenglikda tartib, move_to_end,
                        popitem(last=False) — FIFO

Naqshlar

python
Sanash:      Counter(m)
Guruhlash:   defaultdict(list); d[kalit(x)].append(x)
Invertlash:  {v: k for k, v in d.items()}
Filtrlash:   {k: v for k, v in d.items() if shart}
Birlashtirish: d1 | d2
Qatlamlar:   ChainMap(cli, muhit, fayl, standart)

4. Batafsil misollar

Misol 1 — Metodlar to'liq

python
"""Barcha dict metodlari va ularning nozikliklari."""

print("=== 1. ⭐ get vs setdefault vs pop ===")

BOSHLANGICH = {"a": 1, "b": 2}

AMALLAR = [
    ('d.get("a")',              lambda d: d.get("a")),
    ('d.get("z")',              lambda d: d.get("z")),
    ('d.get("z", 0)',           lambda d: d.get("z", 0)),
    ('d.setdefault("a", 99)',   lambda d: d.setdefault("a", 99)),
    ('d.setdefault("z", 0)',    lambda d: d.setdefault("z", 0)),
    ('d.pop("a")',              lambda d: d.pop("a")),
    ('d.pop("z", 0)',           lambda d: d.pop("z", 0)),
    ('d.popitem()',             lambda d: d.popitem()),
]

print(f"  Boshlang'ich: {BOSHLANGICH}\n")
print(f"  {'Amal':<26} {'Qaytardi':<14} {'d keyin'}")
print("  " + "─" * 60)

for kod, f in AMALLAR:
    d = BOSHLANGICH.copy()
    try:
        natija = repr(f(d))
    except KeyError as x:
        natija = f"❌ KeyError"
    print(f"  {kod:<26} {natija:<14} {d}")

try:
    BOSHLANGICH.copy().pop("z")
except KeyError as x:
    print(f"  {'d.pop(\"z\")':<26} ❌ KeyError: {x}")

print("""
  ⭐ get        — o'qiydi, d O'ZGARMAYDI
     setdefault — o'qiydi, yo'q bo'lsa QO'SHADI
     pop        — o'qiydi va O'CHIRADI
""")


print("\n=== 2. ⚠️ Sukut qiymat doim hisoblanadi ===")

chaqiruvlar = []


def qimmat(nom="?"):
    chaqiruvlar.append(nom)
    return f"hisoblandi-{nom}"


d = {"a": 1}

chaqiruvlar.clear()
d.get("a", qimmat("get"))
d.setdefault("a", qimmat("setdefault"))
d.pop("a", qimmat("pop"))
print(f"  Kalit 'a' BOR, lekin funksiya chaqirildi: {chaqiruvlar}")

print("\n  ✅ Dangasa hisoblash:")
d = {"a": 1}
chaqiruvlar.clear()
if "a" not in d:
    d["a"] = qimmat("if")
print(f"  if k not in d: ...  →  chaqiruvlar: {chaqiruvlar or 'yo`q'}")

print("""
  Sabab: Pythonda argumentlar funksiya chaqirilishidan
         OLDIN hisoblanadi (eager evaluation).
""")


print("\n=== 3. update — barcha shakllar ===")

SHAKLLAR = [
    ('d.update({"x": 1})',              lambda d: d.update({"x": 1})),
    ('d.update([("x", 1)])',            lambda d: d.update([("x", 1)])),
    ('d.update(zip("xy", [1, 2]))',     lambda d: d.update(zip("xy", [1, 2]))),
    ('d.update(x=1, y=2)',              lambda d: d.update(x=1, y=2)),
    ('d.update({"x": 1}, y=2)',         lambda d: d.update({"x": 1}, y=2)),
    ('d.update()',                      lambda d: d.update()),
]

print(f"  Boshlang'ich: {{'a': 0}}\n")
for kod, f in SHAKLLAR:
    d = {"a": 0}
    natija = f(d)
    print(f"  {kod:<34} → {d}  (qaytardi: {natija})")

print(f"\n  ⚠️ update None qaytaradi:")
d = {"a": 1}
natija = d.update({"b": 2})
print(f"    d = d.update({{'b': 2}})  →  d = {natija}  ❌")
print(f"    d.update({{'b': 2}})      →  ✅")
print(f"    yangi = d | {{'b': 2}}    →  ✅")

print(f"\n  ⚠️ Sayoz birlashtirish:")
d1 = {"a": {"x": 1, "y": 2}, "b": 1}
d2 = {"a": {"x": 99}}
nusxa = {k: (v.copy() if isinstance(v, dict) else v) for k, v in d1.items()}
nusxa.update(d2)
print(f"    d1 = {d1}")
print(f"    d2 = {d2}")
print(f"    update → {nusxa}")
print(f"    ⚠️ 'y' YO'QOLDI — ichki lug'at to'liq almashtirildi")


print("\n=== 4. Chuqur birlashtirish ===")


def chuqur_birlashtir(a: dict, b: dict) -> dict:
    """Ichma-ich lug'atlarni rekursiv birlashtiradi."""
    natija = dict(a)
    for kalit, qiymat in b.items():
        if (kalit in natija
                and isinstance(natija[kalit], dict)
                and isinstance(qiymat, dict)):
            natija[kalit] = chuqur_birlashtir(natija[kalit], qiymat)
        else:
            natija[kalit] = qiymat
    return natija


D1 = {
    "baza": {"host": "localhost", "port": 5432, "ssl": False},
    "kesh": {"turi": "redis", "ttl": 300},
    "debug": False,
}
D2 = {
    "baza": {"host": "db.wisar.uz", "ssl": True},
    "kesh": {"ttl": 600},
    "log": "DEBUG",
}

print(f"  D1: {D1}")
print(f"  D2: {D2}\n")

sayoz = D1 | D2
print(f"  Sayoz (D1 | D2):")
for k, v in sayoz.items():
    print(f"    {k}: {v}")

chuqur = chuqur_birlashtir(D1, D2)
print(f"\n  Chuqur:")
for k, v in chuqur.items():
    print(f"    {k}: {v}")

print(f"\n  ⭐ Chuqur birlashtirish 'port' va 'turi' ni SAQLADI")


print("\n=== 5. popitem va clear ===")

d = {"a": 1, "b": 2, "c": 3}
print(f"  d = {d}\n")

nusxa = d.copy()
print(f"  popitem() ketma-ket (LIFO):")
while nusxa:
    print(f"    {nusxa.popitem()}   qoldi: {nusxa}")

print(f"\n  ⭐ Oxirgi qo'shilgandan boshlab (3.7+)")

import time
KATTA = dict.fromkeys(range(500_000))

boshlandi = time.perf_counter()
KATTA.clear()
vaqt_dict = time.perf_counter() - boshlandi

KATTA_LIST = list(range(500_000))
boshlandi = time.perf_counter()
KATTA_LIST.clear()
vaqt_list = time.perf_counter() - boshlandi

print(f"\n  clear() tezligi (500k element):")
print(f"    dict.clear():  {vaqt_dict * 1000:>8.3f} ms   O(1)")
print(f"    list.clear():  {vaqt_list * 1000:>8.3f} ms   O(n)")


print("\n=== 6. Ko'rinishlar bilan ishlash ===")

D = {"a": 1, "b": 2, "c": 3}

print(f"  d = {D}\n")

AMALLAR = [
    ("len(d.keys())",           len(D.keys())),
    ("'a' in d.keys()",         "a" in D.keys()),
    ("1 in d.values()",         1 in D.values()),
    ("('a', 1) in d.items()",   ("a", 1) in D.items()),
    ("list(d.items())",         list(D.items())),
    ("sorted(d.items(), key=lambda x: -x[1])",
     sorted(D.items(), key=lambda x: -x[1])),
    ("dict(reversed(d.items()))", dict(reversed(D.items()))),
    ("max(d, key=d.get)",       max(D, key=D.get)),
    ("min(d.values())",         min(D.values())),
    ("sum(d.values())",         sum(D.values())),
]

for kod, natija in AMALLAR:
    print(f"  {kod:<40} → {natija}")

print(f"\n  ⚠️ 1 in d — KALITLAR bo'yicha qidiradi:")
print(f"    1 in {{'a': 1}}         → {1 in {'a': 1}}")
print(f"    1 in {{'a': 1}}.values() → {1 in {'a': 1}.values()}")

Natijaning muhim qismi:

text
=== 1. ⭐ get vs setdefault vs pop ===
  Amal                       Qaytardi       d keyin
  ────────────────────────────────────────────────────────────
  d.get("a")                 1              {'a': 1, 'b': 2}
  d.get("z")                 None           {'a': 1, 'b': 2}
  d.setdefault("a", 99)      1              {'a': 1, 'b': 2}
  d.setdefault("z", 0)       0              {'a': 1, 'b': 2, 'z': 0}
  d.pop("a")                 1              {'b': 2}
  d.popitem()                ('b', 2)       {'a': 1}

=== 2. ⚠️ Sukut qiymat doim hisoblanadi ===
  Kalit 'a' BOR, lekin funksiya chaqirildi: ['get', 'setdefault', 'pop']

=== 5. popitem va clear ===
  clear() tezligi (500k element):
    dict.clear():     0.184 ms   O(1)
    list.clear():     2.412 ms   O(n)

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

Misol 2 — defaultdict

python
"""defaultdict — avtomatik sukut qiymatlar."""

from collections import defaultdict

print("=== 1. Asosiy shakllar ===")

SHAKLLAR = [
    ("defaultdict(list)",           defaultdict(list),          "append"),
    ("defaultdict(int)",            defaultdict(int),           "+="),
    ("defaultdict(set)",            defaultdict(set),           "add"),
    ("defaultdict(dict)",           defaultdict(dict),          "ichki"),
    ("defaultdict(str)",            defaultdict(str),           "+="),
    ("defaultdict(lambda: 'yo`q')", defaultdict(lambda: "yo'q"), "sukut"),
    ("defaultdict(lambda: [0]*3)",  defaultdict(lambda: [0] * 3), "vektor"),
]

print(f"  {'Shakl':<30} {'d[k] boshlang`ich qiymati'}")
print("  " + "─" * 60)
for nom, d, _ in SHAKLLAR:
    print(f"  {nom:<30} {d['yangi_kalit']!r}")

print(f"\n  ⚠️ Konstruktor CHAQIRILADIGAN bo'lishi kerak:")
try:
    defaultdict(0)
except TypeError as x:
    print(f"    defaultdict(0)         → ❌ {x}")
print(f"    defaultdict(int)       → ✅ int() = {int()}")
print(f"    defaultdict(lambda: 0) → ✅")


print("\n=== 2. ⚠️ Murojaat kalit YARATADI ===")

d = defaultdict(int)
print(f"  d = defaultdict(int)")
print(f"    len(d) = {len(d)}")

qiymat = d["yo'q"]
print(f"\n  d['yo`q'] o'qildi → {qiymat}")
print(f"    len(d) = {len(d)}   ⚠️ KALIT QO'SHILDI!")
print(f"    d = {dict(d)}")

print(f"\n  ✅ Kalit yaratmaydigan usullar:")
d2 = defaultdict(int)
print(f"    'x' in d2      → {'x' in d2},  len = {len(d2)}")
print(f"    d2.get('x')    → {d2.get('x')},  len = {len(d2)}")
print(f"    d2.get('x', 0) → {d2.get('x', 0)},  len = {len(d2)}")

print("""
  ⭐ Bu — defaultdict ning eng ko'p uchraydigan tuzog'i.
     Tekshirish uchun `in` yoki `get` ishlating.
""")


print("\n=== 3. Guruhlash naqshlari ===")

SOZLAR = ["olma", "anor", "behi", "olcha", "uzum", "anjir",
          "bodring", "banan", "uzum"]

print(f"  So'zlar: {SOZLAR}\n")

# Birinchi harf bo'yicha
harflar = defaultdict(list)
for s in SOZLAR:
    harflar[s[0]].append(s)

print(f"  Birinchi harf bo'yicha:")
for harf in sorted(harflar):
    print(f"    {harf}: {harflar[harf]}")

# Uzunlik bo'yicha
uzunliklar = defaultdict(list)
for s in SOZLAR:
    uzunliklar[len(s)].append(s)

print(f"\n  Uzunlik bo'yicha:")
for n in sorted(uzunliklar):
    print(f"    {n}: {uzunliklar[n]}")

# Noyob (set bilan)
noyob_harflar = defaultdict(set)
for s in SOZLAR:
    noyob_harflar[s[0]].add(s)

print(f"\n  Noyob (set bilan):")
for harf in sorted(noyob_harflar):
    print(f"    {harf}: {sorted(noyob_harflar[harf])}")

# Sanash
hisob = defaultdict(int)
for s in SOZLAR:
    hisob[s] += 1

print(f"\n  Sanash:")
for s, n in sorted(hisob.items(), key=lambda x: (-x[1], x[0])):
    if n > 1:
        print(f"    {s}: {n}  ← takror")


print("\n=== 4. Ichma-ich defaultdict ===")

# Ikki darajali
ikki = defaultdict(lambda: defaultdict(int))
ikki["IT"]["Aziz"] += 100
ikki["IT"]["Bobur"] += 200
ikki["HR"]["Aziza"] += 150

print(f"  Ikki darajali:")
for bolim, xodimlar in ikki.items():
    print(f"    {bolim}:")
    for ism, ball in xodimlar.items():
        print(f"      {ism}: {ball}")

# Cheksiz darajali
def cheksiz():
    return defaultdict(cheksiz)


daraxt = cheksiz()
daraxt["a"]["b"]["c"]["d"] = "chuqur qiymat"
print(f"\n  Cheksiz daraxt:")
print(f"    daraxt['a']['b']['c']['d'] = "
      f"{daraxt['a']['b']['c']['d']!r}")


def korsat(d, daraja=0):
    for k, v in d.items():
        if isinstance(v, dict):
            print(f"    {'  ' * daraja}{k}/")
            korsat(v, daraja + 1)
        else:
            print(f"    {'  ' * daraja}{k}: {v!r}")


daraxt["a"]["x"] = 1
daraxt["z"]["y"] = 2
print(f"\n  Tuzilma:")
korsat(daraxt)


print("\n=== 5. __missing__ — ichki mexanizm ===")


class Kuzatuvchi(dict):
    """defaultdict qanday ishlashini ko'rsatadi."""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.yaratilgan = []

    def __missing__(self, kalit):
        print(f"      __missing__({kalit!r}) chaqirildi")
        qiymat = f"sukut-{kalit}"
        self[kalit] = qiymat
        self.yaratilgan.append(kalit)
        return qiymat


d = Kuzatuvchi(mavjud="qiymat")

print(f"  d = {dict(d)}\n")
print(f"  d['mavjud']:")
print(f"    → {d['mavjud']!r}")
print(f"\n  d['yangi']:")
print(f"    → {d['yangi']!r}")
print(f"\n  d.get('boshqa'):")
print(f"    → {d.get('boshqa')!r}   ⭐ __missing__ CHAQIRILMADI")

print(f"\n  Yakuniy: {dict(d)}")
print(f"  Yaratilgan kalitlar: {d.yaratilgan}")

print("""
  ⭐ __missing__ FAQAT d[k] uchun chaqiriladi.
     get(), in, pop() uchun — yo'q.

     defaultdict aynan shu mexanizmni ishlatadi.
""")


print("\n=== 6. default_factory ni o'zgartirish ===")

d = defaultdict(list)
d["a"].append(1)
print(f"  d['a'].append(1)  →  {dict(d)}")

d.default_factory = None
print(f"\n  d.default_factory = None")
try:
    d["yo'q"]
except KeyError as x:
    print(f"    d['yo`q']  →  ❌ KeyError: {x}")

d.default_factory = int
print(f"\n  d.default_factory = int")
print(f"    d['yangi']  →  {d['yangi']}")

print(f"\n  Oddiy dict ga aylantirish:")
print(f"    dict(d)  →  {dict(d)}  (turi: {type(dict(d)).__name__})")

Natijaning muhim qismi:

text
=== 2. ⚠️ Murojaat kalit YARATADI ===
  d = defaultdict(int)
    len(d) = 0

  d['yo`q'] o'qildi → 0
    len(d) = 1   ⚠️ KALIT QO'SHILDI!

  ✅ Kalit yaratmaydigan usullar:
    'x' in d2      → False,  len = 0
    d2.get('x')    → None,  len = 0

=== 5. __missing__ — ichki mexanizm ===
  d['yangi']:
      __missing__('yangi') chaqirildi
    → 'sukut-yangi'

  d.get('boshqa'):
    → None   ⭐ __missing__ CHAQIRILMADI

Nima ko'rsatdi: 2.4-bo'lim.

Misol 3 — Counter, ChainMap, OrderedDict

python
"""collections modulining lug'at turlari."""

from collections import Counter, ChainMap, OrderedDict, defaultdict

print("=== 1. Counter asoslari ===")

MATN = "Python — kuchli va oddiy dasturlash tili. Python o'rganish oson."

c = Counter(MATN.lower())
harflar = Counter(x for x in MATN.lower() if x.isalpha())

print(f"  Matn: {MATN[:40]}...\n")
print(f"  Eng ko'p uchraydigan harflar:")
for harf, soni in harflar.most_common(8):
    print(f"    {harf!r}  {'█' * soni} {soni}")

sozlar = Counter(MATN.lower().replace(".", "").replace("—", "").split())
print(f"\n  So'zlar:")
for soz, soni in sozlar.most_common(5):
    print(f"    {soz:<14} {soni}")

print(f"\n  Statistika:")
print(f"    Jami belgilar:    {c.total()}")
print(f"    Noyob belgilar:   {len(c)}")
print(f"    Jami harflar:     {harflar.total()}")
print(f"    Noyob harflar:    {len(harflar)}")


print("\n=== 2. Counter metodlari ===")

c1 = Counter(a=3, b=1, c=2)
c2 = Counter(a=1, b=2, d=1)

print(f"  c1 = {dict(c1)}")
print(f"  c2 = {dict(c2)}\n")

AMALLAR = [
    ("c1 + c2",             c1 + c2,            "yig'indi"),
    ("c1 - c2",             c1 - c2,            "ayirma (manfiylarsiz)"),
    ("c1 & c2",             c1 & c2,            "minimum"),
    ("c1 | c2",             c1 | c2,            "maksimum"),
]

for kod, natija, izoh in AMALLAR:
    print(f"  {kod:<12} {str(dict(natija)):<32} {izoh}")

print(f"\n  ⚠️ subtract — manfiylarni SAQLAYDI:")
c3 = Counter(a=3, b=1)
c3.subtract(Counter(a=5, b=1))
print(f"    Counter(a=3,b=1).subtract(Counter(a=5,b=1)) → {dict(c3)}")
c4 = Counter(a=3, b=1) - Counter(a=5, b=1)
print(f"    Counter(a=3,b=1) - Counter(a=5,b=1)         → {dict(c4)}")

print(f"\n  elements() — sanoq bo'yicha takrorlaydi:")
print(f"    list(Counter(a=3, b=1).elements()) → "
      f"{list(Counter(a=3, b=1).elements())}")

print(f"\n  ⭐ Yo'q kalit → 0, va QO'SHILMAYDI:")
c5 = Counter("abc")
print(f"    c['z']  →  {c5['z']}")
print(f"    len(c)  →  {len(c5)}  (o'zgarmadi)")
print(f"\n  defaultdict bilan solishtiring:")
d = defaultdict(int)
_ = d["z"]
print(f"    d['z']  →  0")
print(f"    len(d)  →  {len(d)}  ⚠️ qo'shildi")


print("\n=== 3. Counter amaliyotda ===")

print("  Anagram tekshiruvi:")
JUFTLIKLAR = [("listen", "silent"), ("olma", "amlo"), ("python", "java")]
for a, b in JUFTLIKLAR:
    natija = "✅" if Counter(a) == Counter(b) else "❌"
    print(f"    {natija} {a!r} ↔ {b!r}")

print("\n  Ikki matn o'xshashligi:")
A = "python dasturlash tili"
B = "python veb dasturlash"
ca, cb = Counter(A.split()), Counter(B.split())
umumiy = ca & cb
oxshashlik = sum(umumiy.values()) / max(sum(ca.values()), sum(cb.values()))
print(f"    A: {A}")
print(f"    B: {B}")
print(f"    Umumiy: {dict(umumiy)}")
print(f"    O'xshashlik: {oxshashlik:.2%}")

print("\n  Takrorlarni topish:")
MALUMOT = [1, 2, 2, 3, 3, 3, 4]
hisob = Counter(MALUMOT)
print(f"    Ma'lumot: {MALUMOT}")
print(f"    Takrorlar: {{x for x, n in Counter(m).items() if n > 1}} → "
      f"{ {x for x, n in hisob.items() if n > 1} }")
print(f"    Bir martaliklar: { {x for x, n in hisob.items() if n == 1} }")

print("\n  Inventar boshqaruvi:")
ombor = Counter(non=100, sut=50, yog=20)
buyurtma = Counter(non=30, sut=60, shakar=10)
print(f"    Ombor:    {dict(ombor)}")
print(f"    Buyurtma: {dict(buyurtma)}")
print(f"    Berilishi mumkin: {dict(ombor & buyurtma)}")
print(f"    Yetishmaydi:      {dict(buyurtma - ombor)}")
print(f"    Qoladi:           {dict(ombor - buyurtma)}")


print("\n\n=== 4. ChainMap ===")

STANDART = {"til": "uz", "tema": "yorug'", "hajm": 14, "debug": False}
FAYLDAN = {"tema": "qorong'i", "hajm": 16}
MUHITDAN = {"debug": True}
CLIDAN = {"til": "en"}

sozlamalar = ChainMap(CLIDAN, MUHITDAN, FAYLDAN, STANDART)

print(f"  Qatlamlar (birinchi g'olib):")
for i, qatlam in enumerate(sozlamalar.maps):
    nomlar = ["CLI", "MUHIT", "FAYL", "STANDART"]
    print(f"    {i}. {nomlar[i]:<10} {qatlam}")

print(f"\n  Yakuniy qiymatlar:")
for kalit in sorted(sozlamalar):
    # Qaysi qatlamdan
    for i, qatlam in enumerate(sozlamalar.maps):
        if kalit in qatlam:
            manba = ["CLI", "MUHIT", "FAYL", "STANDART"][i]
            break
    print(f"    {kalit:<10} = {str(sozlamalar[kalit]):<12} ({manba})")

print(f"\n  ⭐ Nusxa yaratmaydi — asl lug'atlar o'zgarsa yangilanadi:")
FAYLDAN["hajm"] = 20
print(f"    FAYLDAN['hajm'] = 20  →  sozlamalar['hajm'] = {sozlamalar['hajm']}")

print(f"\n  Yozish — faqat BIRINCHI lug'atga:")
sozlamalar["yangi"] = "qiymat"
print(f"    sozlamalar['yangi'] = 'qiymat'")
print(f"    CLIDAN     = {CLIDAN}   ← o'zgardi")
print(f"    STANDART   = {STANDART}   ← o'zgarmadi")

print(f"\n  new_child — vaqtinchalik qatlam:")
vaqtinchalik = sozlamalar.new_child({"debug": False, "test": True})
print(f"    vaqtinchalik['debug'] = {vaqtinchalik['debug']}")
print(f"    sozlamalar['debug']   = {sozlamalar['debug']}   ← asl o'zgarmadi")

print(f"\n  ChainMap vs birlashtirish:")
import sys
birlashtirilgan = {**STANDART, **FAYLDAN, **MUHITDAN, **CLIDAN}
print(f"    ChainMap:  {sys.getsizeof(sozlamalar)} B (+ havolalar)")
print(f"    dict:      {sys.getsizeof(birlashtirilgan)} B (to'liq nusxa)")

print("""
  ⭐ ChainMap: nusxa yo'q, avtomatik yangilanadi, sekinroq qidiruv
     dict:     bir marta birlashtiriladi, tez qidiruv, nusxa
""")


print("\n=== 5. OrderedDict — 3.7 dan keyin ===")

od1 = OrderedDict([("a", 1), ("b", 2)])
od2 = OrderedDict([("b", 2), ("a", 1)])
d1 = {"a": 1, "b": 2}
d2 = {"b": 2, "a": 1}

print(f"  1. Tenglikda tartib:")
print(f"    OrderedDict(a,b) == OrderedDict(b,a)  →  {od1 == od2}")
print(f"    dict(a,b) == dict(b,a)                →  {d1 == d2}")

print(f"\n  2. move_to_end:")
od = OrderedDict([("a", 1), ("b", 2), ("c", 3)])
print(f"    Asl:                      {list(od)}")
od.move_to_end("a")
print(f"    move_to_end('a'):         {list(od)}")
od.move_to_end("a", last=False)
print(f"    move_to_end('a', False):  {list(od)}")

print(f"\n  3. popitem(last=False) — FIFO:")
od = OrderedDict([("a", 1), ("b", 2), ("c", 3)])
print(f"    popitem()            → {od.popitem()}   (LIFO)")
print(f"    popitem(last=False)  → {od.popitem(last=False)}   (FIFO)")

d = {"a": 1, "b": 2}
try:
    d.popitem(last=False)
except TypeError as x:
    print(f"    dict.popitem(last=False) → ❌ {x}")


print("\n=== 6. LRU kesh — OrderedDict bilan ===")


class LRUKesh:
    """Eng kam ishlatilgan elementni chiqaradi."""

    def __init__(self, hajm: int = 3):
        self.hajm = hajm
        self._kesh: OrderedDict = OrderedDict()
        self.topildi = 0
        self.topilmadi = 0

    def olish(self, kalit):
        if kalit not in self._kesh:
            self.topilmadi += 1
            return None
        self.topildi += 1
        self._kesh.move_to_end(kalit)           # ⭐ eng yangi qilish
        return self._kesh[kalit]

    def qoyish(self, kalit, qiymat):
        if kalit in self._kesh:
            self._kesh.move_to_end(kalit)
        self._kesh[kalit] = qiymat
        if len(self._kesh) > self.hajm:
            eskisi = self._kesh.popitem(last=False)     # ⭐ FIFO
            return eskisi
        return None

    def __repr__(self):
        return f"LRU{list(self._kesh)}"


kesh = LRUKesh(hajm=3)

AMALLAR = [
    ("qoyish", "a", 1), ("qoyish", "b", 2), ("qoyish", "c", 3),
    ("olish", "a", None),
    ("qoyish", "d", 4),
    ("olish", "b", None),
    ("olish", "a", None),
    ("qoyish", "e", 5),
]

print(f"  Hajm: 3\n")
print(f"  {'Amal':<16} {'Natija':<12} Kesh holati")
print("  " + "─" * 52)

for amal, kalit, qiymat in AMALLAR:
    if amal == "qoyish":
        chiqarilgan = kesh.qoyish(kalit, qiymat)
        natija = f"↳{chiqarilgan[0]}" if chiqarilgan else "—"
        print(f"  qoyish({kalit!r}, {qiymat})   {natija:<12} {kesh}")
    else:
        n = kesh.olish(kalit)
        natija = "✅ topildi" if n is not None else "❌ yo'q"
        print(f"  olish({kalit!r})        {natija:<12} {kesh}")

print(f"\n  Statistika: {kesh.topildi} topildi, {kesh.topilmadi} topilmadi "
      f"({kesh.topildi / (kesh.topildi + kesh.topilmadi):.0%})")

print("""
  ⭐ move_to_end + popitem(last=False) — LRU ning yuragi.
     functools.lru_cache ham shu g'oyaga asoslangan.
""")

Natijaning muhim qismi:

text
=== 2. Counter metodlari ===
  c1 + c2      {'a': 4, 'b': 3, 'c': 2, 'd': 1} yig'indi
  c1 - c2      {'a': 2, 'c': 2}                    ayirma (manfiylarsiz)
  c1 & c2      {'a': 1, 'b': 1}                    minimum
  c1 | c2      {'a': 3, 'b': 2, 'c': 2, 'd': 1}    maksimum

=== 6. LRU kesh — OrderedDict bilan ===
  Amal             Natija       Kesh holati
  ────────────────────────────────────────────────────
  qoyish('a', 1)   —            LRU['a']
  qoyish('b', 2)   —            LRU['a', 'b']
  qoyish('c', 3)   —            LRU['a', 'b', 'c']
  olish('a')       ✅ topildi    LRU['b', 'c', 'a']
  qoyish('d', 4)   ↳b           LRU['c', 'a', 'd']
  olish('b')       ❌ yo'q       LRU['c', 'a', 'd']

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

Misol 4 — Amaliy: log tahlilchisi

python
"""dict metodlari bilan real vazifa: server loglarini tahlil qilish."""

import re
import random
from collections import Counter, defaultdict
from datetime import datetime, timedelta

print("=== Server loglari tahlilchisi ===\n")

# Soxta loglar generatsiyasi
random.seed(42)

YOLLAR = ["/", "/maqola", "/maqola/python", "/api/users", "/api/posts",
          "/login", "/static/app.js", "/admin"]
USULLAR = ["GET"] * 8 + ["POST"] * 3 + ["PUT", "DELETE"]
KODLAR = [200] * 15 + [304] * 3 + [404] * 4 + [500] * 2 + [301, 403]
IPLAR = [f"192.168.1.{i}" for i in range(1, 15)]

boshlanish = datetime(2026, 9, 8, 10, 0, 0)
LOGLAR = []
for i in range(500):
    vaqt = boshlanish + timedelta(seconds=random.randrange(3600))
    LOGLAR.append(
        f'{random.choice(IPLAR)} - [{vaqt.strftime("%d/%b/%Y:%H:%M:%S")}] '
        f'"{random.choice(USULLAR)} {random.choice(YOLLAR)} HTTP/1.1" '
        f'{random.choice(KODLAR)} {random.randrange(100, 50000)}'
    )

NAQSH = re.compile(
    r'(?P<ip>[\d.]+) - \[(?P<vaqt>[^\]]+)\] '
    r'"(?P<usul>\w+) (?P<yol>\S+) [^"]*" '
    r'(?P<kod>\d+) (?P<hajm>\d+)'
)


class LogTahlilchisi:
    def __init__(self):
        self.yozuvlar: list[dict] = []
        self.notogri = 0

        # Turli hisoblagichlar
        self.kodlar = Counter()
        self.yollar = Counter()
        self.usullar = Counter()
        self.iplar = Counter()

        # Guruhlar
        self.yol_kodlari = defaultdict(Counter)
        self.ip_yollari = defaultdict(set)
        self.soatlar = defaultdict(int)

        # Trafik
        self.yol_hajmi = defaultdict(int)

    def qosh(self, qator: str) -> bool:
        mos = NAQSH.match(qator)
        if not mos:
            self.notogri += 1
            return False

        y = mos.groupdict()
        y["kod"] = int(y["kod"])
        y["hajm"] = int(y["hajm"])
        y["vaqt"] = datetime.strptime(y["vaqt"], "%d/%b/%Y:%H:%M:%S")
        self.yozuvlar.append(y)

        self.kodlar[y["kod"]] += 1
        self.yollar[y["yol"]] += 1
        self.usullar[y["usul"]] += 1
        self.iplar[y["ip"]] += 1

        self.yol_kodlari[y["yol"]][y["kod"]] += 1
        self.ip_yollari[y["ip"]].add(y["yol"])
        self.soatlar[y["vaqt"].hour] += 1
        self.yol_hajmi[y["yol"]] += y["hajm"]

        return True

    @property
    def xato_foizi(self) -> float:
        xatolar = sum(n for k, n in self.kodlar.items() if k >= 400)
        return xatolar / len(self.yozuvlar) * 100 if self.yozuvlar else 0.0

    def muammoli_yollar(self, chegara: float = 20.0) -> dict[str, float]:
        """Xato foizi chegaradan yuqori bo'lgan yo'llar."""
        natija = {}
        for yol, kodlar in self.yol_kodlari.items():
            jami = sum(kodlar.values())
            xatolar = sum(n for k, n in kodlar.items() if k >= 400)
            foiz = xatolar / jami * 100
            if foiz >= chegara:
                natija[yol] = foiz
        return dict(sorted(natija.items(), key=lambda x: -x[1]))

    def shubhali_iplar(self, chegara: int = 40) -> dict[str, int]:
        return {ip: n for ip, n in self.iplar.items() if n >= chegara}


t = LogTahlilchisi()
for qator in LOGLAR:
    t.qosh(qator)

print(f"=== 1. Umumiy statistika ===\n")
print(f"  Jami so'rovlar:   {len(t.yozuvlar):,}")
print(f"  Noto'g'ri qator:  {t.notogri}")
print(f"  Noyob IP:         {len(t.iplar)}")
print(f"  Noyob yo'l:       {len(t.yollar)}")
print(f"  Xato foizi:       {t.xato_foizi:.1f}%")
print(f"  Jami trafik:      {sum(t.yol_hajmi.values()) / 1024 / 1024:.2f} MB")


print(f"\n\n=== 2. Javob kodlari ===\n")

TOIFALAR = {2: "Muvaffaqiyat", 3: "Yo'naltirish", 4: "Mijoz xatosi", 5: "Server xatosi"}
toifa_hisobi = Counter(k // 100 for k in t.kodlar.elements())

jami = sum(t.kodlar.values())
print(f"  {'Kod':>5} {'Soni':>6} {'Foiz':>7}  Grafik")
print("  " + "─" * 48)
for kod, soni in sorted(t.kodlar.items()):
    foiz = soni / jami * 100
    belgi = "✅" if kod < 400 else "❌"
    print(f"  {belgi}{kod:>4} {soni:>6} {foiz:>6.1f}%  {'█' * int(foiz / 2)}")

print(f"\n  Toifalar bo'yicha:")
for toifa, soni in sorted(toifa_hisobi.items()):
    print(f"    {toifa}xx {TOIFALAR[toifa]:<16} {soni:>5} "
          f"({soni / jami:>5.1%})")


print(f"\n\n=== 3. Eng ko'p so'ralgan yo'llar ===\n")

print(f"  {'Yo`l':<22} {'So`rov':>7} {'Trafik':>10} {'O`rtacha':>10}")
print("  " + "─" * 54)
for yol, soni in t.yollar.most_common():
    hajm = t.yol_hajmi[yol]
    print(f"  {yol:<22} {soni:>7} {hajm / 1024:>8.1f}KB "
          f"{hajm / soni / 1024:>8.1f}KB")


print(f"\n\n=== 4. Muammoli yo'llar ===\n")

muammoli = t.muammoli_yollar(chegara=15)
if muammoli:
    print(f"  {'Yo`l':<22} {'Xato %':>8}  Kodlar")
    print("  " + "─" * 56)
    for yol, foiz in muammoli.items():
        kodlar = dict(sorted(t.yol_kodlari[yol].items()))
        print(f"  {yol:<22} {foiz:>7.1f}%  {kodlar}")
else:
    print(f"  ✅ Muammoli yo'l yo'q")


print(f"\n\n=== 5. IP tahlili ===\n")

print(f"  Eng faol IP lar:")
print(f"  {'IP':<16} {'So`rov':>7} {'Noyob yo`l':>11}  Grafik")
print("  " + "─" * 52)
for ip, soni in t.iplar.most_common(6):
    noyob = len(t.ip_yollari[ip])
    print(f"  {ip:<16} {soni:>7} {noyob:>11}  {'█' * (soni // 3)}")

shubhali = t.shubhali_iplar(chegara=45)
if shubhali:
    print(f"\n  ⚠️ Shubhali faollik (45+ so'rov):")
    for ip, soni in sorted(shubhali.items(), key=lambda x: -x[1]):
        yollar = t.ip_yollari[ip]
        print(f"    {ip:<16} {soni:>4} so'rov, {len(yollar)} yo'l")


print(f"\n\n=== 6. Vaqt bo'yicha taqsimot ===\n")

if t.soatlar:
    eng_ko_p = max(t.soatlar.values())
    print(f"  {'Soat':>6} {'So`rov':>7}  Grafik")
    print("  " + "─" * 46)
    for soat in sorted(t.soatlar):
        soni = t.soatlar[soat]
        uzunlik = int(soni / eng_ko_p * 30)
        print(f"  {soat:>4}:00 {soni:>7}  {'█' * uzunlik}")


print(f"\n\n=== 7. Ishlatilgan naqshlar ===\n")

print("""
  Counter(...)              — kodlar, yo'llar, usullar, IP lar sanash
  defaultdict(Counter)      — yo'l → kod → soni (ikki darajali)
  defaultdict(set)          — IP → noyob yo'llar
  defaultdict(int)          — soat → so'rovlar soni
  most_common(n)            — reyting
  elements()                — toifalar bo'yicha qayta guruhlash
  {k: v for ... if shart}   — filtrlash
  sorted(d.items(), key=)   — tartiblash

  ⭐ Har bir vazifa uchun to'g'ri tuzilmani tanlash —
     kodni qisqa VA tez qiladi.
""")

Natijaning muhim qismi:

text
=== 1. Umumiy statistika ===

  Jami so'rovlar:   500
  Noto'g'ri qator:  0
  Noyob IP:         14
  Noyob yo'l:       8
  Xato foizi:       28.0%
  Jami trafik:      11.65 MB

=== 2. Javob kodlari ===

    Kod   Soni    Foiz  Grafik
  ────────────────────────────────────────────────
  ✅ 200    282   56.4%  ████████████████████████████
  ✅ 301     28    5.6%  ██
  ✅ 304     50   10.0%  █████
  ❌ 403     16    3.2%  █
  ❌ 404     88   17.6%  ████████
  ❌ 500     36    7.2%  ███

=== 4. Muammoli yo'llar ===

  Yo`l                    Xato %  Kodlar
  ────────────────────────────────────────────────────────
  /admin                    20.3%  {200: 43, 301: 2, 304: 6, 403: 1, 404: 7, 500: 5}

Nima ko'rsatdi: 2.4, 2.5-bo'limlar.


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

Noto'g'ri fikr To'g'risi
"setdefault faqat o'qiydi" Yo'q bo'lsa qo'shadi
"Sukut qiymat faqat kerak bo'lganda hisoblanadi" Doim hisoblanadi
"update yangi lug'at qaytaradi" None. d1 | d2 — yangi
"update chuqur birlashtiradi" Sayoz — ichki lug'at almashtiriladi
"defaultdict[k] kalit yaratmaydi" Yaratadi
"Counter[k] kalit yaratadi" Yaratmaydi, 0 qaytaradi
"Counter - manfiy sanoqlarni saqlaydi" Tushiradi. subtract saqlaydi
"OrderedDict 3.7+ da keraksiz" 3 farq qoldi: tenglik, move_to_end, FIFO
"dict.clear() O(n)" O(1). list.clear() — O(n)

6. Keng tarqalgan xatolar va yechimlari

1. update natijasini o'zlashtirish

python
d = d.update({"a": 1})                  # ❌ d = None
d.update({"a": 1})                      # ✅
yangi = d | {"a": 1}                    # ✅

2. setdefault da qimmat sukut

python
d.setdefault(k, qimmat())               # ⚠️ har safar chaqiriladi
if k not in d:                          # ✅
    d[k] = qimmat()

3. defaultdict da tekshirish

python
if d[k]:                                # ⚠️ kalit yaratadi
if k in d:                              # ✅
if d.get(k):                            # ✅

4. Counter ni siklda yangilash

python
c = Counter()
for x in m: c[x] += 1                   # ⚠️ sekin

c = Counter(m)                          # ✅ C darajasida

5. Chuqur birlashtirish kutish

python
d1.update(d2)                           # ⚠️ ichki lug'at almashtiriladi
chuqur_birlashtir(d1, d2)               # ✅ rekursiv funksiya

6. defaultdict ni funksiyaga uzatish

python
def f(d):
    return d[kalit]                     # ⚠️ defaultdict bo'lsa kalit yaratadi

def f(d):
    return d.get(kalit)                 # ✅ xavfsiz

7. Counter ni dict deb hisoblash

python
c = Counter("abc")
c["z"]                                  # 0, KeyError emas
if c["z"]:                              # ✅ ishlaydi
if "z" in c:                            # ✅ False

8. ChainMap ga yozish

python
cm["kalit"] = 1                         # ⚠️ faqat BIRINCHI lug'atga
cm.maps[1]["kalit"] = 1                 # ✅ aniq qatlamga

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 6.10-dars (o'tilgan): dict asoslari
  • 6.12-dars: tartib va OrderedDict tarixi
  • 6.16-dars: lug'at generatorlari — {k: v for ...}
  • 7-qism: **kwargs, sukut argumentlar
  • 8-qism: __missing__, dict dan meros, UserDict
  • 10-qism: functools.lru_cache — LRU implementatsiyasi
  • 15-qism: collections moduli to'liq
  • 18-qism: profillash — qaysi tuzilma tezroq

8. Eng yaxshi amaliyotlar

  1. Sanash — Counter(iterable). C darajasida, eng tez.

  2. Guruhlash — defaultdict(list). setdefault — ikkinchi tanlov.

  3. defaultdict da tekshirish uchun in yoki get. d[k] kalit yaratadi.

  4. Sukut qiymat qimmat bo'lsa if k not in d. Argumentlar doim hisoblanadi.

  5. Qatlamlar uchun ChainMap. Nusxa yaratmaydi, avtomatik yangilanadi.

  6. LRU/FIFO uchun OrderedDict. move_to_end va popitem(last=False).

  7. Chuqur birlashtirish uchun rekursiv funksiya. update sayoz.

  8. Natijani qaytaruvchi funksiyada dict(defaultdict). Chaqiruvchini ajablantirmang.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
d = {"a": 1}
1.  print(d.get("b"), d)
2.  print(d.setdefault("b", 0), d)
3.  print(d.pop("a", 9), d)
4.  print({"a":1}.update({"b":2}))
5.  from collections import defaultdict
    dd = defaultdict(int); _ = dd["x"]; print(len(dd))
6.  from collections import Counter
    c = Counter("ab"); _ = c["z"]; print(len(c))
7.  print(Counter(a=1) - Counter(a=3))
8.  c = Counter(a=1); c.subtract(Counter(a=3)); print(c)
9.  print(Counter("listen") == Counter("silent"))
10. from collections import OrderedDict
    print(OrderedDict(a=1,b=2) == OrderedDict(b=2,a=1))
11. print(dict(a=1,b=2) == dict(b=2,a=1))
12. d1={"a":{"x":1,"y":2}}; d1.update({"a":{"x":9}}); print(d1)
Javoblar
  1. None {'a': 1} — get o'zgartirmaydi
  2. 0 {'a': 1, 'b': 0} — setdefault qo'shadi
  3. 1 {'b': 0} — pop o'chiradi; 'b' 2-bandda setdefault bilan qo'shilgan (bandlar ketma-ket, bitta d ustida)
  4. None — update hech narsa qaytarmaydi
  5. 1 — defaultdict kalit yaratdi
  6. 2 — Counter yaratmadi
  7. Counter() — manfiylar tushirildi
  8. Counter({'a': -2}) — subtract saqlaydi
  9. True — anagram
  10. False — tartib muhim
  11. True — dict da tartib muhim emas
  12. {'a': {'x': 9}} — 'y' yo'qoldi (sayoz)

Vazifa 2: Xatolarni tuzating

python
1.  d = d.update({"a": 1})
2.  d.setdefault(k, qimmat_hisob())
3.  dd = defaultdict(int)
    if dd[k]: ...
4.  c = Counter()
    for x in m: c[x] += 1
5.  d1.update(d2)   # ichma-ich saqlanishi kerak
6.  guruh = {}
    for x in m:
        if kalit(x) not in guruh: guruh[kalit(x)] = []
        guruh[kalit(x)].append(x)
7.  natija = defaultdict(list)
    return natija      # funksiyadan qaytarish
Javoblar
python
1.  d.update({"a": 1})
2.  if k not in d: d[k] = qimmat_hisob()
3.  if k in dd: ...          # yoki if dd.get(k):
4.  c = Counter(m)
5.  d1 = chuqur_birlashtir(d1, d2)
6.  guruh = defaultdict(list)
    for x in m: guruh[kalit(x)].append(x)
7.  return dict(natija)

Vazifa 3: Chuqur birlashtirish

Funksiya yozing:

python
def chuqur_birlashtir(*lugatlar, royxat_qoshish=False) -> dict:
  1. Ichma-ich lug'atlarni rekursiv birlashtiring
  2. royxat_qoshish=True bo'lsa ro'yxatlarni birlashtiring
  3. None qiymatlarni e'tiborsiz qoldirish opsiyasi
  4. Konfliktlar ro'yxatini qaytarish
  5. Chuqurlik chegarasi (max_daraja)

Vazifa 4: Ko'p funksiyali hisoblagich

Counter ni kengaytiring:

  1. eng_kam(n) — eng kam uchraganlar
  2. foizlar() — har birining ulushi
  3. entropiya() — Shannon entropiyasi
  4. gistogramma(kenglik) — matn grafigi
  5. filtrla(min_soni) — chegaradan yuqorilar
  6. birlashtir(*boshqalar, usul="sum") — sum/max/min

Vazifa 5: Ko'p darajali indeks

Sinf yozing:

  1. qosh(yozuv, *kalitlar) — ixtiyoriy darajali guruhlash
  2. olish(*kalitlar) — qisman kalit bilan ham
  3. sanash(*kalitlar) — har darajadagi sonlar
  4. tekislash() — {(k1, k2): [...]} shakliga
  5. xulosa(funksiya) — har guruh uchun agregatsiya
  6. Chiroyli daraxt chiqarish

Vazifa 6: Kesh tizimi

Uch kesh strategiyasini amalga oshiring va solishtiring:

  1. LRU — eng kam ishlatilgan (OrderedDict)
  2. LFU — eng kam chaqirilgan (Counter)
  3. TTL — muddat bilan (dict + vaqt)
  4. Har biri uchun: olish, qoyish, statistika
  5. Bir xil ish yuklamasida topilish foizini solishtiring
  6. functools.lru_cache bilan solishtiring

Vazifa 7: O'ylash

Nega Counter[k] yo'q kalit uchun 0 qaytaradi va kalitni qo'shmaydi, defaultdict(int)[k] esa 0 qaytaradi va qo'shadi? Qaysi biri to'g'riroq?

Javob

Ikkalasi ham to'g'ri — turli vazifalar uchun.

Counter — o'qish uchun optimallashtirilgan.

Sanoq semantikasida "uchramagan element" va "0 marta uchragan element" — bir xil narsa. Shuning uchun:

python
c = Counter("abc")
c["z"]                      # 0 — "z hech qachon uchramadi"

Kalitni qo'shish ma'nosiz bo'lardi: lug'at "0 marta uchragan" barcha element bilan to'lib ketardi:

python
# Agar Counter kalit yaratsa:
c = Counter("abc")
for harf in "abcdefghijklmnopqrstuvwxyz":
    if c[harf] > 5:                     # faqat o'qish
        ...
print(len(c))                           # 26!  ← 23 tasi keraksiz

Bu — real muammo. Counter ni tekshirish sikllarida ishlatish juda keng tarqalgan.

Amalga oshirish:

python
class Counter(dict):
    def __missing__(self, kalit):
        return 0                        # ⭐ self[kalit] = 0 YO'Q

defaultdict — yozish uchun optimallashtirilgan.

defaultdict ning asosiy qo'llanishi — to'plash:

python
d = defaultdict(list)
d["a"].append(1)                        # d["a"] qaytargan ro'yxat
                                        # SAQLANISHI kerak!

Agar defaultdict kalitni saqlamasa:

python
# Tasavvur qiling: saqlamaydi
d = defaultdict(list)
d["a"].append(1)                        # yangi [] yaratildi, 1 qo'shildi
print(d)                                # {} — ro'yxat yo'qoldi!

Ya'ni defaultdict majburan kalitni saqlashi kerak — aks holda uning asosiy vazifasi ishlamaydi.

Amalga oshirish:

python
class defaultdict(dict):
    def __missing__(self, kalit):
        if self.default_factory is None:
            raise KeyError(kalit)
        qiymat = self.default_factory()
        self[kalit] = qiymat            # ⭐ SAQLANADI
        return qiymat

Bu — asosiy farq va u ataylab qilingan.

Counter defaultdict
Asosiy vazifa O'qish (sanoq) Yozish (to'plash)
d[yo'q] 0, saqlamaydi Sukut, saqlaydi
+= ishlaydi
.append() ishlaydi (int)
Tekshirish xavfsizmi

Amaliy tavsiya:

python
# Sanash → Counter
hisob = Counter(malumot)
if hisob["kamdan-kam"] > 10:            # ✅ xavfsiz

# To'plash → defaultdict
guruhlar = defaultdict(list)
guruhlar[kalit].append(x)               # ✅

# defaultdict ni tekshirishda ehtiyot
if kalit in guruhlar:                   # ✅
if guruhlar[kalit]:                     # ⚠️ kalit yaratadi

Uchinchi variant — dict.get:

python
d = {}
d.get(k, 0)                             # 0, saqlamaydi
d.get(k, [])                            # [], saqlamaydi — lekin append yo'qoladi

get — Counter ga o'xshaydi, lekin har safar sukut qiymatni qayta yaratadi.

Xulosa: bu — API dizaynining yaxshi namunasi. Ikki sinf bir xil __missing__ mexanizmiga tayanadi, lekin turli semantika tanlagan — chunki ular turli vazifalar uchun. "Bir o'lcham hammaga" yechim ikkalasini ham yomonlashtirardi.

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


Xulosa

Bu darsda dict metodlarini va collections turlarini o'rgandik.

Eng muhim uch fikr:

  1. get, setdefault, pop — uchta turli xatti-harakat. get o'qiydi, setdefault yo'q bo'lsa qo'shadi, pop o'chiradi. Va uchalasida ham sukut qiymat doim hisoblanadi — qimmat bo'lsa if k not in d ishlating.

  2. Counter — sanash uchun, defaultdict — to'plash uchun. Counter[k] kalit yaratmaydi (o'qish xavfsiz), defaultdict[k] yaratadi (chunki .append() ishlashi kerak). Counter(iterable) — C darajasida, eng tez sanash usuli.

  3. update sayoz va None qaytaradi. Ichma-ich lug'atlar to'liq almashtiriladi — chuqur birlashtirish uchun rekursiv funksiya kerak. Yangi lug'at kerak bo'lsa d1 | d2.

Keyingi darsda lug'at va tartib mavzusini chuqurlashtiramiz: ixcham lug'at tuzilishi, OrderedDict bilan farqlar va tartibga tayanadigan naqshlar.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
6.11-dars: dict metodlari — IlmHamroh