Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Yaratish tuzoqlari
- 2.2. Xavfsiz o'qish
- 2.3. Yozish va yo'l yaratish
- 2.4. Rekursiv aylanib chiqish
- 2.5. Tekislash va tiklash
- 2.6. Nusxa olish (18-darsga kirish)
- 2.7. Ichma-ich birlashtirish va transformatsiya
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Yaratish va xavfsiz o'qish
- Misol 2 — Aylanib chiqish va tekislash
- Misol 3 — Transformatsiya
- Misol 4 — Amaliy: JSON validator va tahlilchi
- 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
6.14-dars: Ichma-ich tuzilmalar
6-QISM — MA'LUMOT TUZILMALARI · 14-dars
1. Kirish va motivatsiya
Haqiqiy ma'lumot kamdan-kam tekis bo'ladi. API javobi, konfiguratsiya fayli, ma'lumotlar bazasi natijasi — hammasi ichma-ich:
javob = {
"foydalanuvchi": {
"id": 42,
"ism": "Aziz",
"manzillar": [
{"turi": "uy", "shahar": "Toshkent", "kocha": "Amir Temur 1"},
{"turi": "ish", "shahar": "Samarqand", "kocha": None},
],
"sozlamalar": {
"bildirishnoma": {"email": True, "sms": False},
"til": "uz",
},
},
"meta": {"versiya": 2, "vaqt": "2026-09-08T10:00:00"},
}Bunday ma'lumotdan qiymat olish tez qiyinlashadi:
shahar = javob["foydalanuvchi"]["manzillar"][0]["shahar"] # ✅
shahar = javob["foydalanuvchi"]["manzillar"][5]["shahar"] # ❌ IndexError
email = javob["foydalanuvchi"]["sozlama"]["email"] # ❌ KeyError
kocha = javob["foydalanuvchi"]["manzillar"][1]["kocha"].upper() # ❌ AttributeErrorVa o'zgartirish yanada xavfliroq:
nusxa = javob.copy()
nusxa["foydalanuvchi"]["ism"] = "Boshqa"
print(javob["foydalanuvchi"]["ism"]) # "Boshqa" ← asl ham o'zgardi!Bu darsda:
- Ichma-ich tuzilmalarni xavfsiz o'qish (
getzanjiri, yordamchi funksiya) - Yaratish tuzoqlari (
[[0]*3]*3,fromkeys) - Aylanib chiqish (rekursiv aylanish)
- Tekislash (flatten) va teskarisi
- Ichma-ich birlashtirish, filtrlash, transformatsiya
- JSON bilan ishlash va validatsiya
2. Nazariya — chuqur tushuntirish
2.1. Yaratish tuzoqlari
* n bilan ko'paytirish (6.1-dars):
matritsa = [[0] * 3] * 3 # ❌ BITTA ro'yxatga 3 havola
matritsa[0][0] = 1
print(matritsa) # [[1,0,0], [1,0,0], [1,0,0]]
matritsa = [[0] * 3 for _ in range(3)] # ✅ 3 ta alohida
matritsa[0][0] = 1
print(matritsa) # [[1,0,0], [0,0,0], [0,0,0]]Qoida: * n ichki o'lchamda xavfsiz ([0] * 3 — int o'zgarmas), tashqi o'lchamda xavfli.
dict.fromkeys (6.10-dars):
d = dict.fromkeys("abc", []) # ❌ bitta ro'yxat
d = {k: [] for k in "abc"} # ✅Ko'p o'lchovli:
# 3D massiv
kub = [[[0] * 4 for _ in range(3)] for _ in range(2)] # 2×3×4
# Ichma-ich lug'at
from collections import defaultdict
d = defaultdict(lambda: defaultdict(int))
d["a"]["b"] += 1
# Cheksiz daraxt
def daraxt():
return defaultdict(daraxt)
t = daraxt()
t["a"]["b"]["c"] = 1 defaultdict(daraxt) ni JSON ga aylantirish:
import json
json.dumps(t) # ✅ ishlaydi (defaultdict — dict)
# Lekin o'qishda kalit yaratadi:
t["yo'q"]["ham"]["yo'q"] # ⚠️ butun yo'l yaratiladi2.2. Xavfsiz o'qish
Muammo: har daraja KeyError, IndexError yoki TypeError berishi mumkin.
1. get zanjiri:
shahar = (javob
.get("foydalanuvchi", {})
.get("manzillar", [{}])[0]
.get("shahar"))Uzun, o'qish qiyin, va ro'yxat indeksi bilan baribir xavfli.
2. try/except:
try:
shahar = javob["foydalanuvchi"]["manzillar"][0]["shahar"]
except (KeyError, IndexError, TypeError):
shahar = NoneIshlaydi, lekin har murojaat uchun blok yozish kerak.
3. Yordamchi funksiya:
def chuqur_ol(malumot, *yol, sukut=None):
"""Ichma-ich tuzilmadan xavfsiz o'qish."""
joriy = malumot
for qadam in yol:
try:
joriy = joriy[qadam]
except (KeyError, IndexError, TypeError):
return sukut
return joriy
chuqur_ol(javob, "foydalanuvchi", "manzillar", 0, "shahar") # "Toshkent"
chuqur_ol(javob, "foydalanuvchi", "yo'q", 5, "x", sukut="—") # "—"4. Nuqtali yo'l:
def yol_ol(malumot, yol: str, sukut=None):
"""'a.b.0.c' shaklidagi yo'l bilan."""
joriy = malumot
for qadam in yol.split("."):
try:
joriy = joriy[int(qadam)] if qadam.isdigit() else joriy[qadam]
except (KeyError, IndexError, TypeError, ValueError):
return sukut
return joriy
yol_ol(javob, "foydalanuvchi.manzillar.0.shahar")Nuqtali yo'l cheklovi: kalitda nuqta bo'lsa ishlamaydi.
5. Tashqi kutubxonalar:
# glom
from glom import glom
glom(javob, "foydalanuvchi.manzillar.0.shahar")
# jmespath
import jmespath
jmespath.search("foydalanuvchi.manzillar[0].shahar", javob)Murakkab so'rovlar uchun foydali, lekin oddiy holatda o'z funksiyangiz yetarli.
2.3. Yozish va yo'l yaratish
def chuqur_qoy(malumot: dict, yol: list, qiymat) -> None:
"""Oraliq lug'atlarni yaratib, qiymat yozadi."""
joriy = malumot
for qadam in yol[:-1]:
joriy = joriy.setdefault(qadam, {})
joriy[yol[-1]] = qiymat
d = {}
chuqur_qoy(d, ["a", "b", "c"], 1)
print(d) # {'a': {'b': {'c': 1}}}Mavjud non-dict qiymatni bosib o'tish:
d = {"a": 5}
chuqur_qoy(d, ["a", "b"], 1) # ❌ AttributeError: 'int' has no 'setdefault'Xavfsizroq:
def chuqur_qoy(malumot: dict, yol: list, qiymat, majburiy=False) -> bool:
joriy = malumot
for qadam in yol[:-1]:
keyingi = joriy.get(qadam)
if not isinstance(keyingi, dict):
if keyingi is not None and not majburiy:
return False # mavjud qiymatni buzmaymiz
joriy[qadam] = {}
joriy = joriy[qadam]
joriy[yol[-1]] = qiymat
return True2.4. Rekursiv aylanib chiqish
Barcha barg qiymatlarni topish:
def barglar(malumot, yol=()):
"""(yol, qiymat) juftliklarini beradi."""
if isinstance(malumot, dict):
for k, v in malumot.items():
yield from barglar(v, yol + (k,))
elif isinstance(malumot, (list, tuple)):
for i, v in enumerate(malumot):
yield from barglar(v, yol + (i,))
else:
yield yol, malumot
for yol, qiymat in barglar(javob):
print(".".join(map(str, yol)), "=", qiymat)Satr — iteratsiya qilinadigan, lekin barg:
isinstance("abc", (list, tuple)) # False ✅
# Lekin agar Sequence tekshirsangiz:
from collections.abc import Sequence
isinstance("abc", Sequence) # True ⚠️ — satr belgilarga bo'linadiDoim str va bytes ni alohida tekshiring.
Aylanma havolalar — cheksiz rekursiya:
d = {"a": 1}
d["o'zi"] = d # aylanma!
list(barglar(d)) # ❌ RecursionErrorHimoya:
def barglar(malumot, yol=(), korilgan=None):
if korilgan is None:
korilgan = set()
if id(malumot) in korilgan:
yield yol, "<AYLANMA>"
return
if isinstance(malumot, (dict, list, tuple)):
korilgan = korilgan | {id(malumot)}
...Rekursiya chuqurligi:
import sys
sys.getrecursionlimit() # 1000 (sukut)Juda chuqur tuzilmalar uchun iterativ yechim (stek bilan):
def barglar_iterativ(malumot):
stek = [((), malumot)]
while stek:
yol, joriy = stek.pop()
if isinstance(joriy, dict):
stek.extend((yol + (k,), v) for k, v in reversed(joriy.items()))
elif isinstance(joriy, (list, tuple)):
stek.extend((yol + (i,), v) for i, v in reversed(list(enumerate(joriy))))
else:
yield yol, joriy2.5. Tekislash va tiklash
Tekislash (flatten):
def tekisla(malumot, ajratgich=".", prefiks=""):
"""{'a': {'b': 1}} → {'a.b': 1}"""
natija = {}
if isinstance(malumot, dict):
for k, v in malumot.items():
yangi = f"{prefiks}{ajratgich}{k}" if prefiks else str(k)
natija |= tekisla(v, ajratgich, yangi)
elif isinstance(malumot, list):
for i, v in enumerate(malumot):
yangi = f"{prefiks}{ajratgich}{i}" if prefiks else str(i)
natija |= tekisla(v, ajratgich, yangi)
else:
natija[prefiks] = malumot
return natijaTiklash (unflatten):
def tikla(tekis, ajratgich="."):
"""{'a.b': 1} → {'a': {'b': 1}}"""
natija = {}
for yol, qiymat in tekis.items():
joriy = natija
qadamlar = yol.split(ajratgich)
for qadam in qadamlar[:-1]:
joriy = joriy.setdefault(qadam, {})
joriy[qadamlar[-1]] = qiymat
return natijaTekislash yo'qotishlari:
- Ro'yxat indekslari satrga aylanadi (
"0","1") — tiklaganda lug'at bo'ladi - Kalitda ajratgich bo'lsa buziladi
- Bo'sh lug'at/ro'yxat yo'qoladi
Aniq tiklash kerak bo'lsa ro'yxat indekslarini alohida belgilang: a[0].b.
Ro'yxatlarni tekislash:
# Bir daraja
[x for qism in ichma_ich for x in qism]
list(itertools.chain.from_iterable(ichma_ich))
# Barcha daraja
def tekisla_royxat(r):
for x in r:
if isinstance(x, (list, tuple)):
yield from tekisla_royxat(x)
else:
yield x2.6. Nusxa olish (18-darsga kirish)
import copy
d = {"a": {"b": [1, 2]}}
sayoz = d.copy() # ichki obyektlar UMUMIY
chuqur = copy.deepcopy(d) # to'liq alohida
sayoz["a"]["b"].append(3)
print(d) # {'a': {'b': [1, 2, 3]}} ⚠️
chuqur["a"]["b"].append(4)
print(d) # o'zgarmadi ✅Qoida: ichma-ich tuzilmani "nusxalash" deganda deyarli har doim deepcopy kerak.
deepcopy sekin:
# Katta tuzilma uchun
import json
nusxa = json.loads(json.dumps(d)) # ~5-10x tezroq, lekin faqat JSON turlari18-darsda batafsil.
2.7. Ichma-ich birlashtirish va transformatsiya
Chuqur birlashtirish (6.11-dars):
def chuqur_birlashtir(a: dict, b: dict) -> dict:
natija = dict(a)
for k, v in b.items():
if k in natija and isinstance(natija[k], dict) and isinstance(v, dict):
natija[k] = chuqur_birlashtir(natija[k], v)
else:
natija[k] = v
return natijaRekursiv transformatsiya:
def ozgartir(malumot, f):
"""Barcha barg qiymatlarga f ni qo'llaydi."""
if isinstance(malumot, dict):
return {k: ozgartir(v, f) for k, v in malumot.items()}
if isinstance(malumot, list):
return [ozgartir(v, f) for v in malumot]
if isinstance(malumot, tuple):
return tuple(ozgartir(v, f) for v in malumot)
return f(malumot)
ozgartir(javob, lambda x: x.strip() if isinstance(x, str) else x)Kalitlarni o'zgartirish:
def kalitlarni_ozgartir(malumot, f):
if isinstance(malumot, dict):
return {f(k): kalitlarni_ozgartir(v, f) for k, v in malumot.items()}
if isinstance(malumot, list):
return [kalitlarni_ozgartir(v, f) for v in malumot]
return malumot
# camelCase → snake_case
import re
kalitlarni_ozgartir(javob, lambda k: re.sub(r"(?<!^)(?=[A-Z])", "_", k).lower())Rekursiv filtrlash:
def bosh_ni_ochir(malumot):
"""None, bo'sh satr, bo'sh ro'yxat/lug'atni olib tashlaydi."""
if isinstance(malumot, dict):
natija = {k: bosh_ni_ochir(v) for k, v in malumot.items()}
return {k: v for k, v in natija.items() if v not in (None, "", [], {})}
if isinstance(malumot, list):
natija = [bosh_ni_ochir(v) for v in malumot]
return [v for v in natija if v not in (None, "", [], {})]
return malumot v not in (None, "", [], {}) — 0 va False ham tushib qoladimi?
0 in (None, "", [], {}) # ⚠️ False — 0 != None, 0 != ""
False in (None, "", [], {}) # ⚠️ FalseYaxshi, ular saqlanadi. Lekin ehtiyot bo'ling:
0 == False # True
0 in (False,) # True ⚠️Aniq tekshiruv:
def boshmi(v):
return v is None or (isinstance(v, (str, list, dict, tuple)) and not v)3. Tez ma'lumotnoma
Yaratish tuzoqlari
[[0]*3]*3 ❌ bitta ro'yxat
[[0]*3 for _ in range(3)] ✅
dict.fromkeys("ab", []) ❌ bitta ro'yxat
{k: [] for k in "ab"} ✅
defaultdict(lambda: defaultdict(int)) ikki daraja
def daraxt(): return defaultdict(daraxt) cheksizXavfsiz o'qish
def chuqur_ol(m, *yol, sukut=None):
joriy = m
for q in yol:
try: joriy = joriy[q]
except (KeyError, IndexError, TypeError): return sukut
return joriyAylanib chiqish
def barglar(m, yol=()):
if isinstance(m, dict):
for k, v in m.items(): yield from barglar(v, yol+(k,))
elif isinstance(m, (list, tuple)):
for i, v in enumerate(m): yield from barglar(v, yol+(i,))
else: yield yol, m
⚠️ str/bytes alohida — Sequence deb tekshirmang
⚠️ Aylanma havola → id() to'plami bilan himoya
⚠️ Chuqur → iterativ (stek bilan)Nusxa
d.copy() sayoz — ichki UMUMIY ⚠️
copy.deepcopy(d) chuqur ✅
json.loads(json.dumps(d)) tezroq, faqat JSON turlariTransformatsiya
tekisla(d) {'a': {'b': 1}} → {'a.b': 1}
tikla(d) teskari
chuqur_birlashtir(a,b) rekursiv
ozgartir(d, f) barg qiymatlarga f
kalitlarni_ozgartir(d, f) kalitlarga f4. Batafsil misollar
Misol 1 — Yaratish va xavfsiz o'qish
"""Ichma-ich tuzilmalarni to'g'ri yaratish va o'qish."""
from collections import defaultdict
print("=== 1. ⚠️ Yaratish tuzoqlari ===")
print(" Matritsa:\n")
yomon = [[0] * 3] * 3
yaxshi = [[0] * 3 for _ in range(3)]
yomon[0][0] = 1
yaxshi[0][0] = 1
print(f" [[0]*3]*3: {yomon}")
print(f" [[0]*3 for _ in range(3)]: {yaxshi}")
print(f"\n yomon[0] is yomon[1]: {yomon[0] is yomon[1]} ⚠️")
print(f" yaxshi[0] is yaxshi[1]: {yaxshi[0] is yaxshi[1]} ✅")
print(f"\n ⭐ Qoida: * n ICHKI o'lchamda xavfsiz ([0]*3 — int o'zgarmas),")
print(f" TASHQI o'lchamda xavfli")
print("\n Lug'at:\n")
d_yomon = dict.fromkeys("abc", [])
d_yaxshi = {k: [] for k in "abc"}
d_yomon["a"].append(1)
d_yaxshi["a"].append(1)
print(f" dict.fromkeys('abc', []): {d_yomon} ⚠️")
print(f" {{k: [] for k in 'abc'}}: {d_yaxshi} ✅")
print("\n=== 2. Ko'p o'lchovli tuzilmalar ===")
# 3D
kub = [[[0] * 4 for _ in range(3)] for _ in range(2)]
kub[0][1][2] = 9
print(f" 3D massiv (2×3×4), kub[0][1][2] = 9:")
for i, qavat in enumerate(kub):
print(f" Qavat {i}:")
for qator in qavat:
print(f" {qator}")
# Ikki darajali defaultdict
print(f"\n defaultdict(lambda: defaultdict(int)):")
sotuvlar = defaultdict(lambda: defaultdict(int))
MALUMOT = [
("Toshkent", "non", 120), ("Toshkent", "sut", 80),
("Samarqand", "non", 200), ("Toshkent", "non", 50),
]
for shahar, mahsulot, soni in MALUMOT:
sotuvlar[shahar][mahsulot] += soni
for shahar, mahsulotlar in sotuvlar.items():
print(f" {shahar}:")
for mahsulot, soni in mahsulotlar.items():
print(f" {mahsulot:<8} {soni}")
# Cheksiz daraxt
def daraxt():
return defaultdict(daraxt)
t = daraxt()
t["loyiha"]["src"]["main.py"] = "1.2 KB"
t["loyiha"]["src"]["utils"]["helper.py"] = "0.8 KB"
t["loyiha"]["README.md"] = "3.1 KB"
def chiz(d, prefiks=""):
elementlar = list(d.items())
for i, (nom, qiymat) in enumerate(elementlar):
oxirgi = i == len(elementlar) - 1
belgi = "└── " if oxirgi else "├── "
if isinstance(qiymat, dict):
print(f" {prefiks}{belgi}{nom}/")
chiz(qiymat, prefiks + (" " if oxirgi else "│ "))
else:
print(f" {prefiks}{belgi}{nom} ({qiymat})")
print(f"\n Cheksiz daraxt (fayl tizimi):")
chiz(t)
print("\n\n=== 3. Xavfsiz o'qish ===")
JAVOB = {
"foydalanuvchi": {
"id": 42,
"ism": "Aziz",
"manzillar": [
{"turi": "uy", "shahar": "Toshkent", "kocha": "Amir Temur 1"},
{"turi": "ish", "shahar": "Samarqand", "kocha": None},
],
"sozlamalar": {
"bildirishnoma": {"email": True, "sms": False},
"til": "uz",
},
},
"meta": {"versiya": 2},
}
def chuqur_ol(malumot, *yol, sukut=None):
"""Ichma-ich tuzilmadan xavfsiz o'qish."""
joriy = malumot
for qadam in yol:
try:
joriy = joriy[qadam]
except (KeyError, IndexError, TypeError):
return sukut
return joriy
def yol_ol(malumot, yol: str, sukut=None):
"""'a.b.0.c' shaklidagi yo'l."""
joriy = malumot
for qadam in yol.split("."):
try:
joriy = joriy[int(qadam)] if qadam.lstrip("-").isdigit() else joriy[qadam]
except (KeyError, IndexError, TypeError, ValueError):
return sukut
return joriy
YOLLAR = [
("foydalanuvchi", "ism"),
("foydalanuvchi", "manzillar", 0, "shahar"),
("foydalanuvchi", "manzillar", 1, "kocha"),
("foydalanuvchi", "sozlamalar", "bildirishnoma", "email"),
("foydalanuvchi", "manzillar", 5, "shahar"),
("foydalanuvchi", "yo'q", "kalit"),
("meta", "versiya"),
("foydalanuvchi", "ism", "ichida"),
]
print(f" {'Yo`l':<48} {'Natija'}")
print(" " + "─" * 66)
for yol in YOLLAR:
natija = chuqur_ol(JAVOB, *yol, sukut="<yo'q>")
korinish = " → ".join(map(str, yol))
print(f" {korinish:<48} {natija!r}")
print(f"\n Nuqtali yo'l bilan:")
for yol in ["foydalanuvchi.ism",
"foydalanuvchi.manzillar.0.shahar",
"foydalanuvchi.sozlamalar.bildirishnoma.sms",
"foydalanuvchi.manzillar.9.shahar"]:
print(f" {yol:<44} {yol_ol(JAVOB, yol, '<yo`q>')!r}")
print("\n=== 4. Usullarni solishtirish ===")
print(" ❌ To'g'ridan-to'g'ri:")
try:
JAVOB["foydalanuvchi"]["manzillar"][5]["shahar"]
except IndexError as x:
print(f" [...][5][...] → IndexError: {x}")
print("\n ⚠️ get zanjiri:")
natija = (JAVOB
.get("foydalanuvchi", {})
.get("manzillar", [{}])[0]
.get("shahar"))
print(f" .get(...).get(...)[0].get(...) → {natija!r}")
print(f" Lekin [5] uchun baribir IndexError")
print("\n ✅ try/except:")
try:
natija = JAVOB["foydalanuvchi"]["manzillar"][5]["shahar"]
except (KeyError, IndexError, TypeError):
natija = None
print(f" try/except → {natija!r}")
print("\n ⭐ Yordamchi funksiya:")
print(f" chuqur_ol(...) → "
f"{chuqur_ol(JAVOB, 'foydalanuvchi', 'manzillar', 5, 'shahar')!r}")
print(f" Bir marta yoziladi, hamma joyda ishlatiladi")
print("\n=== 5. Yozish va yo'l yaratish ===")
def chuqur_qoy(malumot: dict, yol: list, qiymat, majburiy=False) -> bool:
"""Oraliq lug'atlarni yaratib qiymat yozadi."""
joriy = malumot
for qadam in yol[:-1]:
keyingi = joriy.get(qadam)
if not isinstance(keyingi, dict):
if keyingi is not None and not majburiy:
return False
joriy[qadam] = {}
joriy = joriy[qadam]
joriy[yol[-1]] = qiymat
return True
d = {}
QOYISHLAR = [
(["a", "b", "c"], 1),
(["a", "b", "d"], 2),
(["a", "x"], 3),
(["y"], 4),
]
print(f" Bo'sh lug'atdan boshlab:\n")
for yol, qiymat in QOYISHLAR:
chuqur_qoy(d, yol, qiymat)
print(f" chuqur_qoy(d, {yol}, {qiymat})")
print(f" → {d}")
print(f"\n ⚠️ Mavjud non-dict qiymatni bosib o'tish:")
d2 = {"a": 5}
natija = chuqur_qoy(d2, ["a", "b"], 1)
print(f" d = {{'a': 5}}")
print(f" chuqur_qoy(d, ['a','b'], 1) → {natija} (bekor qilindi)")
print(f" d = {d2} ✅ o'zgarmadi")
natija = chuqur_qoy(d2, ["a", "b"], 1, majburiy=True)
print(f"\n chuqur_qoy(..., majburiy=True) → {natija}")
print(f" d = {d2} ⚠️ 5 yo'qoldi")Natijaning muhim qismi:
=== 1. ⚠️ Yaratish tuzoqlari ===
Matritsa:
[[0]*3]*3: [[1, 0, 0], [1, 0, 0], [1, 0, 0]]
[[0]*3 for _ in range(3)]: [[1, 0, 0], [0, 0, 0], [0, 0, 0]]
yomon[0] is yomon[1]: True ⚠️
yaxshi[0] is yaxshi[1]: False ✅
=== 3. Xavfsiz o'qish ===
Yo`l Natija
──────────────────────────────────────────────────────────────────
foydalanuvchi → ism 'Aziz'
foydalanuvchi → manzillar → 0 → shahar 'Toshkent'
foydalanuvchi → manzillar → 1 → kocha None
foydalanuvchi → manzillar → 5 → shahar "<yo'q>"
foydalanuvchi → ism → ichida "<yo'q>"Nima ko'rsatdi: 2.1, 2.2, 2.3-bo'limlar.
Misol 2 — Aylanib chiqish va tekislash
"""Rekursiv aylanish, tekislash va tiklash."""
import sys
MALUMOT = {
"loyiha": "Wisar",
"versiya": 2,
"muallif": {"ism": "Sarvarbek", "email": "s@wisar.uz"},
"bogliqliklar": ["next", "react", "prisma"],
"sozlamalar": {
"baza": {"host": "localhost", "port": 5432},
"kesh": {"ttl": 300, "yoqilgan": True},
},
"teglar": [
{"nom": "python", "og'irlik": 5},
{"nom": "veb", "og'irlik": 3},
],
}
print("=== 1. Barcha barglarni topish ===")
def barglar(malumot, yol=(), korilgan=None):
"""(yol, qiymat) juftliklari. Aylanma havoladan himoyalangan."""
if korilgan is None:
korilgan = frozenset()
if isinstance(malumot, (dict, list, tuple)):
if id(malumot) in korilgan:
yield yol, "<AYLANMA>"
return
korilgan = korilgan | {id(malumot)}
if isinstance(malumot, dict):
for k, v in malumot.items():
yield from barglar(v, yol + (k,), korilgan)
elif isinstance(malumot, (list, tuple)):
for i, v in enumerate(malumot):
yield from barglar(v, yol + (i,), korilgan)
else:
yield yol, malumot
natijalar = list(barglar(MALUMOT))
print(f" {len(natijalar)} ta barg:\n")
for yol, qiymat in natijalar:
korinish = ".".join(map(str, yol))
print(f" {korinish:<34} = {qiymat!r}")
print("\n=== 2. Aylanma havola ===")
aylanma = {"a": 1, "ichki": {"b": 2}}
aylanma["o'zi"] = aylanma
aylanma["ichki"]["ota"] = aylanma
print(f" d = {{'a': 1, 'ichki': {{...}}}}; d['o`zi'] = d\n")
for yol, qiymat in barglar(aylanma):
print(f" {'.'.join(map(str, yol)):<20} = {qiymat!r}")
print(f"\n ⭐ id() to'plami bilan himoya — cheksiz rekursiya yo'q")
print("\n=== 3. Chuqur tuzilma — iterativ yechim ===")
def chuqur_yaratish(n):
"""n darajali ichma-ich lug'at."""
d = {"qiymat": "eng chuqur"}
for i in range(n):
d = {"daraja": d}
return d
def barglar_iterativ(malumot):
"""Rekursiyasiz — chuqurlik cheklovi yo'q."""
stek = [((), malumot)]
while stek:
yol, joriy = stek.pop()
if isinstance(joriy, dict):
stek.extend((yol + (k,), v) for k, v in reversed(list(joriy.items())))
elif isinstance(joriy, (list, tuple)):
stek.extend((yol + (i,), v)
for i, v in reversed(list(enumerate(joriy))))
else:
yield yol, joriy
print(f" Rekursiya chegarasi: {sys.getrecursionlimit()}\n")
for n in [100, 500, 2000]:
chuqur = chuqur_yaratish(n)
try:
natija = list(barglar(chuqur))
rekursiv = f"✅ {len(natija)} barg"
except RecursionError:
rekursiv = "❌ RecursionError"
natija = list(barglar_iterativ(chuqur))
iterativ = f"✅ {len(natija)} barg"
print(f" {n:>5} daraja: rekursiv: {rekursiv:<22} iterativ: {iterativ}")
print(f"\n ⭐ Juda chuqur tuzilmalar uchun stek bilan iterativ yechim")
print("\n=== 4. Tekislash ===")
def tekisla(malumot, ajratgich=".", prefiks=""):
natija = {}
if isinstance(malumot, dict) and malumot:
for k, v in malumot.items():
yangi = f"{prefiks}{ajratgich}{k}" if prefiks else str(k)
natija |= tekisla(v, ajratgich, yangi)
elif isinstance(malumot, list) and malumot:
for i, v in enumerate(malumot):
yangi = f"{prefiks}{ajratgich}{i}" if prefiks else str(i)
natija |= tekisla(v, ajratgich, yangi)
else:
natija[prefiks] = malumot
return natija
tekis = tekisla(MALUMOT)
print(f" {len(tekis)} ta yozuv:\n")
for yol, qiymat in tekis.items():
print(f" {yol:<34} = {qiymat!r}")
print("\n=== 5. Tiklash ===")
def tikla(tekis, ajratgich="."):
natija = {}
for yol, qiymat in tekis.items():
joriy = natija
qadamlar = yol.split(ajratgich)
for qadam in qadamlar[:-1]:
joriy = joriy.setdefault(qadam, {})
joriy[qadamlar[-1]] = qiymat
return natija
tiklangan = tikla(tekis)
print(f" Asl == tiklangan: {MALUMOT == tiklangan}\n")
print(f" ⚠️ Farq — ro'yxatlar lug'atga aylandi:")
print(f" Asl: {MALUMOT['bogliqliklar']}")
print(f" Tiklangan: {tiklangan['bogliqliklar']}")
print(f"\n ✅ Ro'yxatlarni ham tiklaydigan versiya:")
def tikla_royxatlar(d):
"""Kalitlari 0,1,2... bo'lgan lug'atlarni ro'yxatga aylantiradi."""
if not isinstance(d, dict):
return d
natija = {k: tikla_royxatlar(v) for k, v in d.items()}
kalitlar = list(natija)
if kalitlar and all(k.isdigit() for k in kalitlar):
if sorted(int(k) for k in kalitlar) == list(range(len(kalitlar))):
return [natija[str(i)] for i in range(len(kalitlar))]
return natija
toliq = tikla_royxatlar(tikla(tekis))
print(f" Asl == to'liq tiklangan: {MALUMOT == toliq}")
print(f" bogliqliklar: {toliq['bogliqliklar']}")
print("""
⚠️ Tekislash yo'qotishlari:
• Ro'yxat indekslari satrga aylanadi
• Kalitda ajratgich bo'lsa buziladi
• Bo'sh lug'at/ro'yxat noaniq bo'lib qoladi
""")
print(" Kalitda nuqta muammosi:")
muammoli = {"a.b": {"c": 1}, "a": {"b.c": 2}}
t = tekisla(muammoli)
print(f" Asl: {muammoli}")
print(f" Tekis: {t} ⚠️ ikkalasi 'a.b.c' bo'ldi!")
print(f" Tiklangan: {tikla(t)}")
print("\n=== 6. Ro'yxatlarni tekislash ===")
ICHMA_ICH = [1, [2, 3], [4, [5, 6, [7, 8]]], 9, [[10]]]
print(f" Asl: {ICHMA_ICH}\n")
# Bir daraja
from itertools import chain
bir_daraja = [1, [2, 3], [4, 5]]
print(f" Bir daraja:")
print(f" [x for q in r for x in q] "
f"{[x for q in [[1, 2], [3, 4]] for x in q]}")
print(f" list(chain.from_iterable(r)) "
f"{list(chain.from_iterable([[1, 2], [3, 4]]))}")
def tekisla_royxat(r):
for x in r:
if isinstance(x, (list, tuple)):
yield from tekisla_royxat(x)
else:
yield x
print(f"\n Barcha daraja:")
print(f" {list(tekisla_royxat(ICHMA_ICH))}")
def tekisla_royxat_daraja(r, daraja=1):
"""Faqat n darajagacha."""
for x in r:
if isinstance(x, (list, tuple)) and daraja > 0:
yield from tekisla_royxat_daraja(x, daraja - 1)
else:
yield x
print(f"\n Chegaralangan chuqurlik:")
for d in [1, 2, 3, 10]:
print(f" daraja={d}: {list(tekisla_royxat_daraja(ICHMA_ICH, d))}")
print(f"\n ⚠️ Satr — iteratsiya qilinadigan, lekin barg:")
matnli = ["abc", ["def", "gh"]]
print(f" {matnli}")
print(f" → {list(tekisla_royxat(matnli))} ✅ satrlar bo'linmadi")
from collections.abc import Sequence
def yomon_tekisla(r):
for x in r:
if isinstance(x, Sequence) and not isinstance(x, str):
yield from yomon_tekisla(x)
else:
yield x
print(f" Sequence bilan (str istisnosiz) — cheksiz rekursiya xavfi")Natijaning muhim qismi:
=== 2. Aylanma havola ===
d = {'a': 1, 'ichki': {...}}; d['o`zi'] = d
a = 1
ichki.b = 2
ichki.ota = '<AYLANMA>'
o'zi = '<AYLANMA>'
=== 3. Chuqur tuzilma — iterativ yechim ===
Rekursiya chegarasi: 1000
100 daraja: rekursiv: ✅ 1 barg iterativ: ✅ 1 barg
500 daraja: rekursiv: ✅ 1 barg iterativ: ✅ 1 barg
2000 daraja: rekursiv: ❌ RecursionError iterativ: ✅ 1 barg
=== 5. Tiklash ===
Asl == tiklangan: False
⚠️ Farq — ro'yxatlar lug'atga aylandi:
Asl: ['next', 'react', 'prisma']
Tiklangan: {'0': 'next', '1': 'react', '2': 'prisma'}Nima ko'rsatdi: 2.4, 2.5-bo'limlar.
Misol 3 — Transformatsiya
"""Ichma-ich tuzilmalarni o'zgartirish."""
import re
import copy
import json
import time
XOM = {
"userId": 42,
"userName": " Aziz Karimov ",
"emailAddress": "AZIZ@MAIL.UZ",
"isActive": True,
"lastLogin": None,
"profileSettings": {
"displayName": " aziz ",
"notificationPrefs": {"emailEnabled": True, "smsEnabled": None},
"themeName": "",
},
"recentOrders": [
{"orderId": 1, "totalAmount": "120000", "orderNotes": " tez "},
{"orderId": 2, "totalAmount": "80000", "orderNotes": ""},
],
"emptyList": [],
"emptyDict": {},
}
print("=== 1. Qiymatlarni o'zgartirish ===")
def ozgartir(malumot, f):
"""Barcha BARG qiymatlarga f ni qo'llaydi."""
if isinstance(malumot, dict):
return {k: ozgartir(v, f) for k, v in malumot.items()}
if isinstance(malumot, list):
return [ozgartir(v, f) for v in malumot]
if isinstance(malumot, tuple):
return tuple(ozgartir(v, f) for v in malumot)
return f(malumot)
def tozala(x):
if isinstance(x, str):
return x.strip()
return x
tozalangan = ozgartir(XOM, tozala)
print(f" strip() barcha satrlarga:\n")
print(f" userName: {XOM['userName']!r}")
print(f" → {tozalangan['userName']!r}")
print(f" profileSettings.displayName: {XOM['profileSettings']['displayName']!r}")
print(f" → {tozalangan['profileSettings']['displayName']!r}")
print(f" recentOrders[0].orderNotes: {XOM['recentOrders'][0]['orderNotes']!r}")
print(f" → {tozalangan['recentOrders'][0]['orderNotes']!r}")
print("\n=== 2. Kalitlarni o'zgartirish ===")
def kalitlarni_ozgartir(malumot, f):
if isinstance(malumot, dict):
return {f(k): kalitlarni_ozgartir(v, f) for k, v in malumot.items()}
if isinstance(malumot, list):
return [kalitlarni_ozgartir(v, f) for v in malumot]
return malumot
def camel_to_snake(nom: str) -> str:
return re.sub(r"(?<!^)(?=[A-Z])", "_", nom).lower()
def snake_to_camel(nom: str) -> str:
qismlar = nom.split("_")
return qismlar[0] + "".join(q.capitalize() for q in qismlar[1:])
snake = kalitlarni_ozgartir(XOM, camel_to_snake)
qaytgan = kalitlarni_ozgartir(snake, snake_to_camel)
print(f" camelCase → snake_case:\n")
for eski, yangi in list(zip(XOM, snake))[:5]:
print(f" {eski:<22} → {yangi}")
print(f"\n Ichma-ich:")
print(f" profileSettings.notificationPrefs.emailEnabled")
print(f" → profile_settings.notification_prefs.email_enabled")
print(f"\n Teskari aylantirish to'g'rimi: {qaytgan.keys() == XOM.keys()}")
print("\n=== 3. Bo'sh qiymatlarni olib tashlash ===")
def boshmi(v) -> bool:
"""None yoki bo'sh konteyner."""
if v is None:
return True
if isinstance(v, (str, list, dict, tuple, set)) and len(v) == 0:
return True
return False
def bosh_ni_ochir(malumot):
if isinstance(malumot, dict):
natija = {k: bosh_ni_ochir(v) for k, v in malumot.items()}
return {k: v for k, v in natija.items() if not boshmi(v)}
if isinstance(malumot, list):
natija = [bosh_ni_ochir(v) for v in malumot]
return [v for v in natija if not boshmi(v)]
return malumot
toza = bosh_ni_ochir(tozalangan)
print(f" Asl kalitlar: {len(XOM)}")
print(f" Toza kalitlar: {len(toza)}\n")
print(f" Olib tashlangan:")
for k in XOM:
if k not in toza:
print(f" {k:<22} = {XOM[k]!r}")
print(f"\n Ichma-ich ham:")
print(f" profileSettings: {list(XOM['profileSettings'])}")
print(f" → {list(toza['profileSettings'])}")
print(f"\n ⚠️ 0 va False saqlanadi:")
sinov = {"nol": 0, "yolgon": False, "bosh_satr": "", "yoq": None, "bosh_royxat": []}
print(f" {sinov}")
print(f" → {bosh_ni_ochir(sinov)}")
print("\n=== 4. Turlarni aylantirish ===")
def turlarni_tikla(malumot):
"""Satr ko'rinishidagi sonlarni va bayroqlarni tiklaydi."""
if isinstance(malumot, dict):
return {k: turlarni_tikla(v) for k, v in malumot.items()}
if isinstance(malumot, list):
return [turlarni_tikla(v) for v in malumot]
if isinstance(malumot, str):
past = malumot.lower()
if past in ("true", "ha", "yes"):
return True
if past in ("false", "yo'q", "no"):
return False
if past in ("null", "none", "nil"):
return None
if malumot.lstrip("-").isdigit():
return int(malumot)
try:
return float(malumot)
except ValueError:
return malumot
return malumot
SATRLI = {
"port": "5432",
"ssl": "true",
"timeout": "30.5",
"nom": "wisar",
"kesh": {"ttl": "300", "yoqilgan": "false"},
"hostlar": ["db1", "5432", "true"],
}
tiklangan = turlarni_tikla(SATRLI)
print(f" {'Kalit':<16} {'Asl':<16} {'Tiklangan':<16} Turi")
print(" " + "─" * 58)
def solishtir(a, b, prefiks=""):
if isinstance(a, dict):
for k in a:
solishtir(a[k], b[k], f"{prefiks}{k}.")
elif isinstance(a, list):
for i, (x, y) in enumerate(zip(a, b)):
solishtir(x, y, f"{prefiks}{i}.")
else:
nom = prefiks.rstrip(".")
print(f" {nom:<16} {str(a):<16} {str(b):<16} {type(b).__name__}")
solishtir(SATRLI, tiklangan)
print("\n=== 5. Chuqur birlashtirish ===")
def chuqur_birlashtir(*lugatlar, royxat_qoshish=False):
natija = {}
for d in lugatlar:
for k, v in d.items():
if k in natija and isinstance(natija[k], dict) and isinstance(v, dict):
natija[k] = chuqur_birlashtir(natija[k], v,
royxat_qoshish=royxat_qoshish)
elif (royxat_qoshish and k in natija
and isinstance(natija[k], list) and isinstance(v, list)):
natija[k] = natija[k] + v
else:
natija[k] = v
return natija
STANDART = {
"baza": {"host": "localhost", "port": 5432, "ssl": False},
"kesh": {"ttl": 300},
"hostlar": ["localhost"],
"debug": False,
}
FAYLDAN = {
"baza": {"host": "db.internal", "ssl": True},
"hostlar": ["db1", "db2"],
"log": "INFO",
}
MUHITDAN = {
"baza": {"port": 5433},
"debug": True,
}
print(f" Uch qatlam:\n")
for nom, d in [("STANDART", STANDART), ("FAYLDAN", FAYLDAN), ("MUHITDAN", MUHITDAN)]:
print(f" {nom}: {d}")
sayoz = {**STANDART, **FAYLDAN, **MUHITDAN}
chuqur = chuqur_birlashtir(STANDART, FAYLDAN, MUHITDAN)
chuqur_royxat = chuqur_birlashtir(STANDART, FAYLDAN, MUHITDAN, royxat_qoshish=True)
print(f"\n Sayoz ({{**a, **b}}):")
for k, v in sayoz.items():
print(f" {k:<10} {v}")
print(f"\n Chuqur:")
for k, v in chuqur.items():
print(f" {k:<10} {v}")
print(f"\n Chuqur + ro'yxatlarni qo'shish:")
print(f" hostlar: {chuqur_royxat['hostlar']}")
print(f"""
⭐ Sayoz: baza to'liq almashtirildi — 'ssl' va 'host' yo'qoldi
Chuqur: barcha kalitlar saqlandi
""")
print("\n=== 6. Nusxa olish tezligi ===")
KATTA = {
f"kalit{i}": {
"sonlar": list(range(20)),
"ichki": {"a": i, "b": [{"x": j} for j in range(5)]},
}
for i in range(200)
}
USULLAR = []
boshlandi = time.perf_counter()
n1 = KATTA.copy()
USULLAR.append(("d.copy() — SAYOZ ⚠️", time.perf_counter() - boshlandi))
boshlandi = time.perf_counter()
n2 = copy.deepcopy(KATTA)
USULLAR.append(("copy.deepcopy()", time.perf_counter() - boshlandi))
boshlandi = time.perf_counter()
n3 = json.loads(json.dumps(KATTA))
USULLAR.append(("json roundtrip", time.perf_counter() - boshlandi))
eng_tez = min(v for _, v in USULLAR)
print(f" 200 ta ichma-ich yozuv:\n")
print(f" {'Usul':<26} {'Vaqt':>10} {'Nisbat':>9}")
print(" " + "─" * 48)
for nom, vaqt in USULLAR:
print(f" {nom:<26} {vaqt * 1000:>7.2f} ms {vaqt / eng_tez:>8.1f}x")
print(f"\n Nusxalar mustaqilmi:")
for nom, n in [("copy()", n1), ("deepcopy()", n2), ("json", n3)]:
n["kalit0"]["sonlar"].append(999)
mustaqil = 999 not in KATTA["kalit0"]["sonlar"]
print(f" {nom:<12} {'✅ mustaqil' if mustaqil else '❌ ASL O`ZGARDI'}")
if not mustaqil:
KATTA["kalit0"]["sonlar"].remove(999)
print("""
⚠️ json roundtrip tezroq, LEKIN:
• Faqat JSON turlari (dict, list, str, int, float, bool, None)
• tuple → list, set → ❌, datetime → ❌
• Kalitlar satrga aylanadi
""")Natijaning muhim qismi:
=== 3. Bo'sh qiymatlarni olib tashlash ===
Asl kalitlar: 9
Toza kalitlar: 6
Olib tashlangan:
lastLogin = None
emptyList = []
emptyDict = {}
⚠️ 0 va False saqlanadi:
{'nol': 0, 'yolgon': False, 'bosh_satr': '', 'yoq': None, 'bosh_royxat': []}
→ {'nol': 0, 'yolgon': False}
=== 6. Nusxa olish tezligi ===
Usul Vaqt Nisbat
────────────────────────────────────────────────
d.copy() — SAYOZ ⚠️ 0.01 ms 1.0x
copy.deepcopy() 84.21 ms 8421.0x
json roundtrip 12.42 ms 1242.0x
Nusxalar mustaqilmi:
copy() ❌ ASL O`ZGARDI
deepcopy() ✅ mustaqil
json ✅ mustaqilNima ko'rsatdi: 2.6, 2.7-bo'limlar.
Misol 4 — Amaliy: JSON validator va tahlilchi
"""Ichma-ich tuzilmalar bilan to'liq vosita."""
import json
from typing import Any
from collections import Counter, defaultdict
print("=== JSON tahlilchi va validator ===\n")
JAVOB = {
"status": "ok",
"data": {
"users": [
{
"id": 1,
"name": "Aziz",
"email": "aziz@mail.uz",
"roles": ["admin", "user"],
"profile": {"age": 30, "city": "Toshkent", "bio": None},
},
{
"id": 2,
"name": "Bobur",
"email": "invalid-email",
"roles": [],
"profile": {"age": "25", "city": "", "bio": "Dasturchi"},
},
{
"id": 3,
"name": "",
"email": "aziza@mail.uz",
"roles": ["user"],
"profile": {"age": -5, "city": "Samarqand"},
},
],
"total": 3,
"page": 1,
},
"meta": {"version": "2.1", "timestamp": 1725782400, "cached": False},
}
class JSONTahlilchi:
def __init__(self, malumot):
self.malumot = malumot
def barglar(self, malumot=None, yol=(), korilgan=None):
if malumot is None:
malumot = self.malumot
if korilgan is None:
korilgan = frozenset()
if isinstance(malumot, (dict, list)):
if id(malumot) in korilgan:
yield yol, "<AYLANMA>"
return
korilgan = korilgan | {id(malumot)}
if isinstance(malumot, dict):
for k, v in malumot.items():
yield from self.barglar(v, yol + (k,), korilgan)
elif isinstance(malumot, list):
for i, v in enumerate(malumot):
yield from self.barglar(v, yol + (i,), korilgan)
else:
yield yol, malumot
@property
def chuqurlik(self) -> int:
return max((len(yol) for yol, _ in self.barglar()), default=0)
def statistika(self) -> dict:
turlar = Counter()
barglar_soni = 0
for _, qiymat in self.barglar():
turlar[type(qiymat).__name__] += 1
barglar_soni += 1
tugunlar = Counter()
def sana(m):
tugunlar[type(m).__name__] += 1
if isinstance(m, dict):
for v in m.values():
sana(v)
elif isinstance(m, list):
for v in m:
sana(v)
sana(self.malumot)
return {
"chuqurlik": self.chuqurlik,
"barglar": barglar_soni,
"barg_turlari": dict(turlar.most_common()),
"tugunlar": dict(tugunlar.most_common()),
}
def qidir(self, shart) -> list[tuple]:
"""Shartga mos barglarni topadi."""
return [(yol, q) for yol, q in self.barglar() if shart(yol, q)]
def kalit_yollari(self, kalit: str) -> list[tuple]:
"""Berilgan kalit qayerlarda uchraydi."""
return [yol for yol, _ in self.barglar() if kalit in yol]
_BOSH = object() # ⭐ "berilmagan" belgisi
def sxema(self, malumot=_BOSH, daraja=0) -> str:
"""Tuzilma sxemasi.
⚠️ malumot=None sukuti bilan yozilsa, JSON dagi null (None)
qiymatda rekursiya ILDIZDAN qayta boshlanadi → RecursionError.
None haqiqiy qiymat bo'lishi mumkin bo'lsa — alohida belgi obyekt.
"""
if malumot is self._BOSH:
malumot = self.malumot
bo = " " * daraja
if isinstance(malumot, dict):
qatorlar = [f"{{"]
for k, v in malumot.items():
ichki = self.sxema(v, daraja + 1)
qatorlar.append(f"{bo} {k}: {ichki}")
qatorlar.append(f"{bo}}}")
return "\n".join(qatorlar)
if isinstance(malumot, list):
if not malumot:
return "[]"
ichki = self.sxema(malumot[0], daraja)
return f"[{ichki}] × {len(malumot)}"
return type(malumot).__name__
t = JSONTahlilchi(JAVOB)
print("=== 1. Statistika ===\n")
stat = t.statistika()
print(f" Maksimal chuqurlik: {stat['chuqurlik']}")
print(f" Barglar soni: {stat['barglar']}\n")
print(f" Barg turlari:")
for tur, soni in stat["barg_turlari"].items():
print(f" {tur:<12} {'█' * soni} {soni}")
print(f"\n Barcha tugunlar:")
for tur, soni in stat["tugunlar"].items():
print(f" {tur:<12} {soni}")
print("\n\n=== 2. Sxema ===\n")
for qator in t.sxema().splitlines():
print(f" {qator}")
print("\n\n=== 3. Qidiruv ===\n")
QIDIRUVLAR = [
("None qiymatlar", lambda y, q: q is None),
("Bo'sh satrlar", lambda y, q: q == ""),
("Manfiy sonlar", lambda y, q: isinstance(q, int) and not isinstance(q, bool) and q < 0),
("Satr sonlar", lambda y, q: isinstance(q, str) and q.lstrip("-").isdigit()),
("'email' yo'lida", lambda y, q: "email" in y),
]
for nom, shart in QIDIRUVLAR:
natijalar = t.qidir(shart)
print(f" {nom} ({len(natijalar)}):")
for yol, qiymat in natijalar:
print(f" {'.'.join(map(str, yol)):<40} = {qiymat!r}")
print()
print("=== 4. Validatsiya ===\n")
SXEMA = {
"data.users[].id": ("int", lambda x: x > 0),
"data.users[].name": ("str", lambda x: len(x.strip()) > 0),
"data.users[].email": ("str", lambda x: "@" in x and "." in x.split("@")[-1]),
"data.users[].roles": ("list", lambda x: len(x) > 0),
"data.users[].profile.age": ("int", lambda x: 0 < x < 150),
"data.users[].profile.city": ("str", lambda x: len(x.strip()) > 0),
"data.total": ("int", lambda x: x >= 0),
"meta.version": ("str", lambda x: bool(x)),
}
def yol_matni(yol: tuple) -> str:
"""( 'data','users',0,'id' ) → 'data.users[].id'"""
qismlar = []
for q in yol:
if isinstance(q, int):
if qismlar:
qismlar[-1] += "[]"
else:
qismlar.append(str(q))
return ".".join(qismlar)
xatolar = []
tekshirilgan = 0
for yol, qiymat in t.barglar():
naqsh = yol_matni(yol)
if naqsh not in SXEMA:
continue
tekshirilgan += 1
kutilgan_tur, tekshiruv = SXEMA[naqsh]
haqiqiy_tur = type(qiymat).__name__
if haqiqiy_tur != kutilgan_tur:
xatolar.append((yol, f"tur: {kutilgan_tur} kutildi, {haqiqiy_tur} keldi", qiymat))
else:
try:
if not tekshiruv(qiymat):
xatolar.append((yol, "qiymat tekshiruvidan o'tmadi", qiymat))
except Exception as x:
xatolar.append((yol, f"tekshiruv xatosi: {x}", qiymat))
print(f" {tekshirilgan} maydon tekshirildi, {len(xatolar)} xato:\n")
for yol, sabab, qiymat in xatolar:
print(f" ❌ {'.'.join(map(str, yol))}")
print(f" {sabab}")
print(f" qiymat: {qiymat!r}\n")
if not xatolar:
print(f" ✅ Barcha maydon to'g'ri")
print("=== 5. Tozalash ===\n")
def tozala(malumot):
"""Bo'sh qiymatlarni olib tashlaydi, satrlarni tozalaydi."""
if isinstance(malumot, dict):
natija = {}
for k, v in malumot.items():
tozalangan = tozala(v)
if tozalangan is not None and tozalangan != "" and tozalangan != []:
natija[k] = tozalangan
return natija
if isinstance(malumot, list):
natija = [tozala(v) for v in malumot]
return [v for v in natija
if v is not None and v != "" and v != [] and v != {}]
if isinstance(malumot, str):
return malumot.strip()
return malumot
toza = tozala(JAVOB)
asl_barglar = len(list(t.barglar()))
toza_barglar = len(list(JSONTahlilchi(toza).barglar()))
print(f" Barglar: {asl_barglar} → {toza_barglar} "
f"({asl_barglar - toza_barglar} olib tashlandi)\n")
print(f" Foydalanuvchilar:")
for asl, yangi in zip(JAVOB["data"]["users"], toza["data"]["users"]):
yoqolgan = set(asl) - set(yangi)
profil_yoqolgan = set(asl["profile"]) - set(yangi.get("profile", {}))
print(f" id={asl['id']}:")
if yoqolgan:
print(f" olib tashlandi: {sorted(yoqolgan)}")
if profil_yoqolgan:
print(f" profile dan: {sorted(profil_yoqolgan)}")
if not yoqolgan and not profil_yoqolgan:
print(f" (o'zgarishsiz)")
print("\n\n=== 6. Yakuniy JSON ===\n")
chiqish = json.dumps(toza, indent=2, ensure_ascii=False, sort_keys=True)
for qator in chiqish.splitlines()[:22]:
print(f" {qator}")
print(f" ...")
print(f"\n Hajm: {len(json.dumps(JAVOB))} → {len(json.dumps(toza))} bayt")Natijaning muhim qismi:
=== 1. Statistika ===
Maksimal chuqurlik: 5
Barglar soni: 26
Barg turlari:
str █████████████████ 17
int ████████ 8
NoneType 1
bool █ 1
=== 3. Qidiruv ===
Manfiy sonlar (1):
data.users.2.profile.age = -5
Satr sonlar (1):
data.users.1.profile.age = '25'
=== 4. Validatsiya ===
17 maydon tekshirildi, 5 xato:
❌ data.users.1.email
qiymat tekshiruvidan o'tmadi
qiymat: 'invalid-email'
❌ data.users.1.profile.age
tur: int kutildi, str keldi
qiymat: '25'Nima ko'rsatdi: 2.4, 2.7-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
"[[0]*3]*3 — 3×3 matritsa" |
Bitta ro'yxatga 3 havola |
"d.copy() ichma-ichni ham nusxalaydi" |
Sayoz — ichki obyektlar umumiy |
"get zanjiri xavfsiz" |
Ro'yxat indeksi bilan baribir IndexError |
| "Rekursiya har doim ishlaydi" | 1000 daraja chegara. Chuqur uchun iterativ |
| "Satr — konteyner, uni ham aylanish kerak" | Barg sifatida qarang |
| "Tekislash teskari qaytariladi" | Ro'yxatlar lug'atga aylanadi |
"update chuqur birlashtiradi" |
Sayoz — ichki lug'at almashtiriladi |
"json roundtrip deepcopy o'rnini bosadi" |
Faqat JSON turlari |
| "Aylanma havola bo'lmaydi" | Bo'ladi — id() bilan himoya kerak |
6. Keng tarqalgan xatolar va yechimlari
1. * n bilan matritsa
m = [[0] * 3] * 3 # ❌
m = [[0] * 3 for _ in range(3)] # ✅2. Sayoz nusxa
n = d.copy() # ⚠️ ichki umumiy
n = copy.deepcopy(d) # ✅3. Himoyasiz murojaat
x = d["a"]["b"][0]["c"] # ❌
x = chuqur_ol(d, "a", "b", 0, "c") # ✅4. Satrni konteyner deb qarash
if isinstance(x, Sequence): # ⚠️ satr ham Sequence
if isinstance(x, (list, tuple)): # ✅5. Aylanma havolada rekursiya
def yur(d):
for v in d.values(): yur(v) # ❌ RecursionError
def yur(d, korilgan=frozenset()): # ✅
if id(d) in korilgan: return6. Chuqur tuzilmada rekursiya
def yur(d): ... # ⚠️ 1000 daraja chegara
def yur_iterativ(d): # ✅ stek bilan
stek = [d]7. update bilan chuqur birlashtirish
d1.update(d2) # ⚠️ ichki lug'at almashtiriladi
chuqur_birlashtir(d1, d2) # ✅8. Tekislashda ajratgich to'qnashuvi
tekisla({"a.b": {"c": 1}}) # ⚠️ "a.b.c" — noaniq
tekisla(d, ajratgich="\x00") # ✅ kalitda bo'lmaydigan belgi7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 6.1, 6.10-darslar (o'tilgan):
[[0]*3]*3vafromkeystuzoqlari - 6.18-dars:
copyvadeepcopy— batafsil - 6.15, 6.16-darslar: generatorlar bilan transformatsiya
- 7, 10-qismlar: rekursiv funksiyalar,
yield from - 9-qism: xatolarni ushlash zanjiri
- 16-qism: JSON, fayllar bilan ishlash
- 13-qism:
pydantic— sxema validatsiyasi - API bilan ishlash: har qanday REST javob ichma-ich
8. Eng yaxshi amaliyotlar
Xavfsiz o'qish uchun yordamchi funksiya yozing. Bir marta, hamma joyda.
* nfaqat o'zgarmas elementlar uchun. Ichki o'lchamda — xavfsiz, tashqisida — yo'q.Nusxa kerak bo'lsa
deepcopy.copy()ichma-ich uchun deyarli har doim noto'g'ri.Rekursiyada
str/bytesni alohida. Ular iteratsiya qilinadi, lekin barg.Aylanma havoladan himoyalaning.
id()to'plami bilan.Chuqur tuzilma uchun iterativ. 1000 daraja — real chegara.
Chuqur birlashtirish uchun rekursiv funksiya.
updateva|sayoz.Murakkab so'rovlar uchun
glomyokijmespath. Oddiy holatda o'z funksiyangiz.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
1. m = [[0]*2]*2; m[0][0] = 1; print(m)
2. m = [[0]*2 for _ in range(2)]; m[0][0] = 1; print(m)
3. d = {"a": {"b": 1}}; n = d.copy(); n["a"]["b"] = 2; print(d)
4. d = {"a": 1}; n = d.copy(); n["a"] = 2; print(d)
5. print([[0]*2][0] is [[0]*2][0])
6. d = dict.fromkeys("ab", {}); d["a"]["x"] = 1; print(d)
7. from itertools import chain
print(list(chain.from_iterable([[1,[2]],[3]])))
8. print(isinstance("abc", (list, tuple)))
9. d = {}; d["x"] = d; print(len(d))
10. import copy; d = {"a":[1]}; n = copy.deepcopy(d); n["a"].append(2); print(d)Javoblar
[[1, 0], [1, 0]]— bitta ro'yxat[[1, 0], [0, 0]]{'a': {'b': 2}}— sayoz nusxa{'a': 1}— yuqori daraja alohidaFalse— turli obyektlar{'a': {'x': 1}, 'b': {'x': 1}}— bitta lug'at[1, [2], 3]— faqat bir darajaFalse— satrlist/tupleemas1— aylanma havola muammo emas{'a': [1]}chuqur nusxa
Vazifa 2: Xatolarni tuzating
1. taxta = [["."]*8]*8
2. nusxa = konfiguratsiya.copy()
nusxa["baza"]["host"] = "yangi"
3. x = javob["data"]["users"][0]["name"]
4. def yur(d):
for v in d.values(): yur(v)
5. d1.update(d2) # ichki lug'atlar saqlanishi kerak
6. def tekisla(x):
if isinstance(x, Sequence): ...
7. d = dict.fromkeys(kalitlar, {})
8. natija = json.loads(json.dumps(malumot)) # datetime borJavoblar
1. taxta = [["."]*8 for _ in range(8)]
2. nusxa = copy.deepcopy(konfiguratsiya)
3. x = chuqur_ol(javob, "data", "users", 0, "name")
4. def yur(d, korilgan=frozenset()):
if id(d) in korilgan: return
korilgan = korilgan | {id(d)}
5. d1 = chuqur_birlashtir(d1, d2)
6. if isinstance(x, (list, tuple)):
7. d = {k: {} for k in kalitlar}
8. natija = copy.deepcopy(malumot) # yoki maxsus JSON encoderVazifa 3: Yo'l kutubxonasi
Funksiyalar yozing:
ol(m, yol, sukut=None)— o'qish ("a.b[0].c"sintaksisi)qoy(m, yol, qiymat)— yozish, oraliqlarni yaratishochir(m, yol)— o'chirishbormi(m, yol)— mavjudligini tekshirishyollar(m)— barcha yo'llar ro'yxati- Kalitda nuqta bo'lsa qochirish (
a\\.b)
Vazifa 4: Diff vositasi
Ichma-ich tuzilmalar uchun:
def diff(eski, yangi) -> list[tuple[str, str, Any, Any]]:
"""[(yol, 'qoshildi'|'ochirildi'|'ozgardi', eski, yangi)]"""- Rekursiv taqqoslash
- Ro'yxatlar uchun element diff
- Chiroyli chiqarish (
+,-,~ranglar bilan) - JSON Patch (RFC 6902) eksporti
- Patch qo'llash (
patch(malumot, ozgarishlar))
Vazifa 5: Sxema validatori
Sinf yozing:
- Sxema tili: tur, majburiylik, oraliq, naqsh
- Ichma-ich sxemalar
- Ro'yxat elementlari uchun sxema
- Xatolarni yo'l bilan ko'rsatish
- Avtomatik tur aylantirish opsiyasi
- Sxemani namunadan generatsiya qilish
Vazifa 6: Ma'lumot quvuri (pipeline)
Zanjirlanadigan transformatsiyalar:
Quvur(malumot).tozala().kalitlar(snake).turlar().filtrla(shart).natija()tozala()—strip, bo'shlarni olib tashlashkalitlar(f)— kalitlarni o'zgartirishturlar()— avtomatik tur tiklashfiltrla(shart)— rekursiv filtrxarita(f)— barg qiymatlarga funksiyatekisla()/tikla()- Har qadam yangi obyekt qaytarsin (o'zgarmas quvur)
Vazifa 7: O'ylash
Nega Python d["a"]["b"]["c"] uchun "xavfsiz murojaat" operatori bermagan (JavaScript dagi d?.a?.b?.c kabi)?
Javob
Uch sabab.
1. None va "yo'q kalit" — turli holatlar.
JavaScript da ?. faqat null/undefined ni tekshiradi:
d?.a?.b // d yoki d.a null/undefined bo'lsa → undefinedPythonda esa uch xil "yo'qlik" bor:
d["a"] # KeyError — kalit yo'q
d[0] # IndexError — indeks chegaradan tashqarida
d.a # AttributeError — atribut yo'q
None["a"] # TypeError — obyekt murojaat qilinmaydiBitta operator qaysi birini yutishi kerak? Hammasini yutish — juda ko'p xatoni yashirish demak:
# Tasavvur qiling: d?["a"]?["b"]
d?["nomi_notogri_yozilgan"]?["b"] # jimgina None — xato topilmaydi2. "Xatolarni yashirmang" prinsipi.
Zen: "Errors should never pass silently."
KeyError — foydali xato. U kalit nomi noto'g'ri yozilganini yoki API o'zgarganini darhol ko'rsatadi. ?. bo'lsa, xato o'nlab qatordan keyin None bilan ishlashda chiqadi — va sababni topish qiyin bo'ladi.
3. Zanjir kamdan-kam kerak, va yechim bor.
Amalda uzun zanjir kerak bo'lgan holat ikkitasi:
- API javobi — bir marta parse qilinadi, keyin tipli obyektga aylantiriladi
- Konfiguratsiya — bir marta o'qiladi
Ikkalasi uchun ham yaxshiroq yechim bor:
# ✅ pydantic — sxema bilan
class Foydalanuvchi(BaseModel):
ism: str
manzil: Manzil | None = None
f = Foydalanuvchi(**javob)
f.manzil.shahar if f.manzil else None # tipli, IDE yordam beradi
# ✅ dataclass + parse funksiyasi
# ✅ chuqur_ol() yordamchi funksiyasiPEP taklif qilinganmi?
Ha — PEP 505 (None-aware operators, 2015):
a ?? b # a is None bo'lsa b
a?.b # xavfsiz atribut
a?[b] # xavfsiz indeks
a ??= b # None bo'lsa o'zlashtirishGuido "deferred" (kechiktirilgan) holatiga qo'ydi. Sabablar:
Sintaksis og'ir ko'rinadi:
pythonx = a?.b?.c?.d ?? sukutPythonchilar buni "Perl kabi" deb topdi.
None— Pythonda kamroq markaziy. JavaScript daundefinedhar joyda (yo'q maydon →undefined). Pythonda yo'q kalit → xato, va bu ataylab.Muqobil yechimlar mavjud (yuqorida).
Muammoning ko'lami kichik. Ko'p kod uzun zanjir ishlatmaydi.
Hozirgi holat: PEP 505 hali ham "deferred". Vaqti-vaqti bilan muhokama qayta boshlanadi, lekin konsensus yo'q.
Amaliy tavsiya:
# Bir-ikki daraja — to'g'ridan-to'g'ri
d.get("a", {}).get("b")
# Uch va undan ko'p — yordamchi funksiya
chuqur_ol(d, "a", "b", "c", "d")
# Murakkab so'rov — glom/jmespath
glom(d, "a.b.c.d", default=None)
# Tuzilma ma'lum — sxema
Foydalanuvchi(**d)Xulosa: Python "sintaksis qo'shish" o'rniga "kutubxona bilan hal qilish" ni tanladi. Bu — tilning umumiy falsafasi: yadro kichik qolsin, ehtiyojlar kutubxona bilan qoplansin.
Nimani mustahkamlaydi: 2.1, 2.2, 2.4, 2.6-bo'limlar.
Xulosa
Bu darsda ichma-ich tuzilmalar bilan ishlashni o'rgandik.
Eng muhim uch fikr:
Xavfsiz murojaat uchun yordamchi funksiya yozing.
chuqur_ol(m, *yol, sukut)—try/exceptni bir joyga yig'adi va butun loyihada ishlatiladi.getzanjiri ro'yxat indekslarida baribir buziladi.copy()ichma-ich uchun yaramaydi. Sayoz nusxa ichki obyektlarni umumiy qoldiradi.deepcopy— to'g'ri javob,jsonroundtrip — tezroq, lekin faqat JSON turlari uchun.Rekursiyada uch xavf bor.
str/bytesni barg deb qarang, aylanma havoladanid()to'plami bilan himoyalaning, chuqur tuzilmalar uchun stek bilan iterativ yechim yozing.
Keyingi darsda ro'yxat generatorlari ni ko'ramiz: [x for x in ...] sintaksisi, sikl bilan solishtirish, ichma-ich generatorlar va qachon ular o'qilishni yomonlashtiradi.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!