Asosiy qismga o'tish

Fayllar va formatlar: pathlib, JSON, CSV, SQLite

10-bob 16 kod bloki 3458 so'z

pathlib: yo'llar bilan ishlash

Eski usul — yo'llarni matn sifatida qo'shish. U platformaga bog'liq va xatolarga moyil.

python13 qator
import os
from pathlib import Path

eski = os.path.join("malumot", "2026", "hisobot.csv")
yangi = Path("malumot") / "2026" / "hisobot.csv"
print("os.path.join:", eski)
print("pathlib     :", yangi)

p = Path("/uy/talaba/malumot/hisobot.2026.csv")
print("\nqismlari:")
for nom, qiymat in [("nomi", p.name), ("kengaytma", p.suffix), ("hamma kengaytmalar", p.suffixes),
                    ("kengaytmasiz", p.stem), ("papka", p.parent), ("ildiz", p.parts[:2])]:
    print(f"  {nom:20} {qiymat}")
Chiqish
os.path.join: malumot/2026/hisobot.csv
pathlib     : malumot/2026/hisobot.csv

qismlari:
  nomi                 hisobot.2026.csv
  kengaytma            .csv
  hamma kengaytmalar   ['.2026', '.csv']
  kengaytmasiz         hisobot.2026
  papka                /uy/talaba/malumot
  ildiz                ('/', 'uy')

Foydali amallar:

python17 qator
from pathlib import Path
import tempfile

papka = Path(tempfile.mkdtemp())
(papka / "ichki").mkdir(parents=True, exist_ok=True)
(papka / "a.csv").write_text("ism,baho\nAziz,85\n", encoding="utf-8")
(papka / "b.csv").write_text("ism,baho\nBobur,90\n", encoding="utf-8")
(papka / "ichki" / "c.csv").write_text("ism,baho\nDilnoza,70\n", encoding="utf-8")
(papka / "eslatma.txt").write_text("bu CSV emas", encoding="utf-8")

print("faqat shu papkadagi CSV lar:", sorted(p.name for p in papka.glob("*.csv")))
print("ichkilari bilan birga      :", sorted(str(p.relative_to(papka)) for p in papka.rglob("*.csv")))
print("\nbor-yo'qligi:", (papka / "a.csv").exists(), "| papkami:", (papka / "ichki").is_dir())
print("hajmi:", (papka / "a.csv").stat().st_size, "bayt")
print("\no'qish bir qatorda:", (papka / "a.csv").read_text(encoding="utf-8").strip())

import shutil; shutil.rmtree(papka)
Chiqish
faqat shu papkadagi CSV lar: ['a.csv', 'b.csv']
ichkilari bilan birga      : ['a.csv', 'b.csv', 'ichki/c.csv']

bor-yo'qligi: True | papkami: True
hajmi: 17 bayt

o'qish bir qatorda: ism,baho
Aziz,85
Amal pathlib
Birlashtirish Path("a") / "b" / "c.txt"
O'qish / yozish p.read_text(encoding="utf-8"), p.write_text(...)
Papka yaratish p.mkdir(parents=True, exist_ok=True)
Qidirish p.glob("*.csv"), p.rglob("*.csv") (ichkilari bilan)
Mavjudlik p.exists(), p.is_file(), p.is_dir()
Kengaytmani almashtirish p.with_suffix(".json")

:::gotcha encoding ni har doim yozing open(yol) va read_text() kodlashni tizimdan oladi. Windows da u ko'pincha cp1251, Linux da utf-8. Ya'ni bir xil kod ikki kompyuterda turli natija beradi. Har doim encoding="utf-8" yozing — bu eng ko'p uchraydigan "menda ishlaydi" xatolaridan biri. :::

Buni ko'rsatamiz:

python12 qator
import tempfile, os
from pathlib import Path

p = Path(tempfile.mkdtemp()) / "uzbek.txt"
p.write_text("O'zbekiston — Toshkent shahri\n", encoding="utf-8")

print("utf-8 bilan   :", repr(p.read_text(encoding="utf-8").strip()))
try:
    print("latin-1 bilan :", repr(p.read_text(encoding="latin-1").strip()))
except UnicodeDecodeError as e:
    print("latin-1 bilan : XATO -", e)
import shutil; shutil.rmtree(p.parent)
Chiqish
utf-8 bilan   : "O'zbekiston — Toshkent shahri"
latin-1 bilan : "O'zbekiston â\x80\x94 Toshkent shahri"

latin-1 xato bermadi — u har qanday baytni "o'qiy oladi", lekin natija buzuq. Bu eng xavfli holat: xato yo'q, ma'lumot esa noto'g'ri.

JSON: tuzilgan ma'lumot

shu faylni yaratingsrc/hisobot/chiqarish.py

python40 qator
"""Natijani turli formatlarda yozish."""
import csv
import json
import logging
from pathlib import Path
from typing import Any

from .hisob import daraja_taqsimoti, guruh_ortachasi
from .modellar import Natija

log = logging.getLogger(__name__)


def xulosa(natija: Natija) -> dict[str, Any]:
    """Natijadan JSON ga yaroqli lug'at yasaydi."""
    return {
        "jami": natija.jami,
        "togri": len(natija.talabalar),
        "xato": len(natija.xatolar),
        "guruh_ortachasi": guruh_ortachasi(natija.talabalar),
        "darajalar": daraja_taqsimoti(natija.talabalar),
        "xatolar": [{"qator": q, "ism": i, "sabab": s} for q, i, s in natija.xatolar],
    }


def json_yoz(natija: Natija, yol: str | Path) -> None:
    p = Path(yol)
    p.write_text(json.dumps(xulosa(natija), ensure_ascii=False, indent=2), encoding="utf-8")
    log.info("JSON yozildi: %s", p)


def csv_yoz(natija: Natija, yol: str | Path) -> None:
    p = Path(yol)
    with p.open("w", encoding="utf-8", newline="") as f:
        yozuvchi = csv.DictWriter(f, fieldnames=["ism", "guruh", "baho", "sana", "daraja"])
        yozuvchi.writeheader()
        for t in natija.talabalar:
            yozuvchi.writerow({"ism": t.ism, "guruh": t.guruh, "baho": t.baho,
                               "sana": t.sana, "daraja": t.daraja.value})
    log.info("CSV yozildi: %s", p)
python10 qator
.venv/bin/python3 -c "
from hisobot.oqish import oqi, tozala
from hisobot.chiqarish import json_yoz, csv_yoz
n = tozala(oqi('sinov_malumot.csv'))
json_yoz(n, 'natija.json')
csv_yoz(n, 'natija.csv')
"
cat natija.json
echo "--- CSV ---"
cat natija.csv
Chiqish (qaytish kodi 0, 134 ms)
{
  "jami": 8,
  "togri": 6,
  "xato": 2,
  "guruh_ortachasi": {
    "A": 90.67,
    "B": 83.0,
    "C": 61.0
  },
  "darajalar": {
    "yaxshi": 3,
    "a'lo": 2,
    "qoniqarli": 1
  },
  "xatolar": [
    {
      "qator": 5,
      "ism": "Elyor",
      "sabab": "baho son emas: ''"
    },
    {
      "qator": 8,
      "ism": "Hasan",
      "sabab": "baho son emas: 'abc'"
    }
  ]
}--- CSV ---
ism,guruh,baho,sana,daraja
Aziz,A,85,2026-09-01,yaxshi
Bobur,A,92,2026-09-01,a'lo
Dilnoza,B,78,2026-09-02,yaxshi
Feruza,A,95,2026-09-03,a'lo
Gulnora,C,61,2026-09-03,qoniqarli
Iroda,B,88,2026-09-04,yaxshi
8 qatordan 2 tasi rad etildi

ensure_ascii=False muhim: usiz o'zbekcha harflar ʻ kabi ko'rinadi. Tekshiramiz:

python4 qator
import json
malumot = {"ism": "Feruza", "daraja": "a'lo", "izoh": "o'qishni tugatdi"}
print("ensure_ascii=True (sukut):", json.dumps(malumot))
print("ensure_ascii=False       :", json.dumps(malumot, ensure_ascii=False))
Chiqish
ensure_ascii=True (sukut): {"ism": "Feruza", "daraja": "a'lo", "izoh": "o'qishni tugatdi"}
ensure_ascii=False       : {"ism": "Feruza", "daraja": "a'lo", "izoh": "o'qishni tugatdi"}

Ikkalasi ham to'g'ri JSON, lekin ikkinchisi odam o'qiy oladigan.

JSON nimani saqlay olmaydi

python16 qator
import json
from datetime import date, datetime
from decimal import Decimal

sinovlar = [
    ("matn", "salom"), ("son", 42), ("kasr", 3.14), ("mantiqiy", True), ("yo'q", None),
    ("ro'yxat", [1, 2]), ("lug'at", {"a": 1}),
    ("sana", date(2026, 9, 1)), ("to'plam", {1, 2, 3}), ("Decimal", Decimal("10.5")),
    ("kortej", (1, 2)),
]
for nom, qiymat in sinovlar:
    try:
        natija = json.dumps(qiymat)
        print(f"  {nom:10} -> {natija}")
    except TypeError as e:
        print(f"  {nom:10} -> XATO: {e}")
Chiqish
  matn       -> "salom"
  son        -> 42
  kasr       -> 3.14
  mantiqiy   -> true
  yo'q       -> null
  ro'yxat    -> [1, 2]
  lug'at     -> {"a": 1}
  sana       -> XATO: Object of type date is not JSON serializable
  to'plam    -> XATO: Object of type set is not JSON serializable
  Decimal    -> XATO: Object of type Decimal is not JSON serializable
  kortej     -> [1, 2]

tuple ro'yxatga aylandi (qaytarib olib bo'lmaydi), date, set va Decimal esa umuman yozilmadi. Yechim — default funksiyasi:

python15 qator
import json
from datetime import date, datetime
from decimal import Decimal

def aylantir(x):
    if isinstance(x, (date, datetime)):
        return x.isoformat()
    if isinstance(x, set):
        return sorted(x)
    if isinstance(x, Decimal):
        return str(x)
    raise TypeError(f"JSON ga aylantirib bo'lmaydi: {type(x).__name__}")

malumot = {"sana": date(2026, 9, 1), "guruhlar": {"B", "A"}, "narx": Decimal("10.50")}
print(json.dumps(malumot, default=aylantir, ensure_ascii=False))
Chiqish
{"sana": "2026-09-01", "guruhlar": ["A", "B"], "narx": "10.50"}

CSV tuzoqlari

python12 qator
import csv, io

xom = 'ism,izoh,baho\nAziz,"yaxshi, lekin kech topshirdi",85\nBobur,"u ""ajoyib"" dedi",90\n'
print("xom matn:")
print(xom)
print("csv moduli bilan o'qilgani:")
for q in csv.DictReader(io.StringIO(xom)):
    print("  ", q)

print("\nqo'lda split(',') bilan (XATO):")
for qator in xom.strip().splitlines()[1:]:
    print("  ", qator.split(","))
Chiqish
xom matn:
ism,izoh,baho
Aziz,"yaxshi, lekin kech topshirdi",85
Bobur,"u ""ajoyib"" dedi",90

csv moduli bilan o'qilgani:
   {'ism': 'Aziz', 'izoh': 'yaxshi, lekin kech topshirdi', 'baho': '85'}
   {'ism': 'Bobur', 'izoh': 'u "ajoyib" dedi', 'baho': '90'}

qo'lda split(',') bilan (XATO):
   ['Aziz', '"yaxshi', ' lekin kech topshirdi"', '85']
   ['Bobur', '"u ""ajoyib"" dedi"', '90']

split(",") vergulli matnni buzdi. CSV ni hech qachon qo'lda tahlil qilmang — csv moduli qo'shtirnoq, ichki vergul va ko'chirilgan qo'shtirnoqni to'g'ri hal qiladi.

Yozishda ham bitta tuzoq bor:

python12 qator
import csv, io, tempfile, os
from pathlib import Path

papka = Path(tempfile.mkdtemp())
for nom, newline in [("newline_yoq.csv", None), ("newline_bor.csv", "")]:
    with open(papka / nom, "w", encoding="utf-8", newline=newline) as f:
        w = csv.writer(f)
        w.writerow(["ism", "baho"])
        w.writerow(["Aziz", 85])
    xom = (papka / nom).read_bytes()
    print(f"{nom:18} bayt: {xom!r}")
import shutil; shutil.rmtree(papka)
Chiqish
newline_yoq.csv    bayt: b'ism,baho\r\nAziz,85\r\n'
newline_bor.csv    bayt: b'ism,baho\r\nAziz,85\r\n'

Linux da farq yo'q, Windows da esa newline=None har qatordan keyin bo'sh qator qo'shadi. Shuning uchun csv bilan yozganda har doim newline="" yozing.

SQLite: fayl ichidagi ma'lumotlar bazasi

CSV kichik ma'lumot uchun. Ma'lumot o'sganda va so'rov kerak bo'lganda SQLite ishlatiladi — u standart kutubxonada, server talab qilmaydi.

python32 qator
import sqlite3, tempfile, time
from pathlib import Path

yol = Path(tempfile.mkdtemp()) / "talabalar.db"
con = sqlite3.connect(yol)
con.execute("""
    CREATE TABLE talaba (
        id INTEGER PRIMARY KEY,
        ism TEXT NOT NULL,
        guruh TEXT NOT NULL,
        baho INTEGER NOT NULL CHECK (baho BETWEEN 0 AND 100)
    )
""")

qatorlar = [(f"Talaba{i}", "ABC"[i % 3], 50 + (i * 7) % 51) for i in range(10_000)]
t0 = time.perf_counter()
con.executemany("INSERT INTO talaba (ism, guruh, baho) VALUES (?, ?, ?)", qatorlar)
con.commit()
yozish_ms = (time.perf_counter() - t0) * 1000

t0 = time.perf_counter()
natija = con.execute(
    "SELECT guruh, COUNT(*), ROUND(AVG(baho), 2) FROM talaba GROUP BY guruh ORDER BY guruh"
).fetchall()
soro_ms = (time.perf_counter() - t0) * 1000

print(f"10 000 qator yozildi: {yozish_ms:.0f} ms | fayl hajmi: {yol.stat().st_size // 1024} KB")
print(f"guruh bo'yicha so'rov: {soro_ms:.1f} ms")
for guruh, soni, ortacha in natija:
    print(f"  {guruh}: {soni} talaba, o'rtacha {ortacha}")
con.close()
import shutil; shutil.rmtree(yol.parent)
Chiqish
10 000 qator yozildi: 17 ms | fayl hajmi: 224 KB
guruh bo'yicha so'rov: 1.4 ms
  A: 3334 talaba, o'rtacha 73.99
  B: 3333 talaba, o'rtacha 74.99
  C: 3333 talaba, o'rtacha 76.0

CHECK cheklovi muhim: baza noto'g'ri ma'lumotni qabul qilmaydi. Bu tekshiruvning oxirgi chizig'i:

python10 qator
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE t (baho INTEGER CHECK (baho BETWEEN 0 AND 100))")
for qiymat in (85, 150):
    try:
        con.execute("INSERT INTO t VALUES (?)", (qiymat,))
        print(f"  {qiymat}: qabul qilindi")
    except sqlite3.IntegrityError as e:
        print(f"  {qiymat}: rad etildi — {e}")
con.close()
Chiqish
  85: qabul qilindi
  150: rad etildi — CHECK constraint failed: baho BETWEEN 0 AND 100

:::gotcha SQL ni matn qo'shib yasamang f"SELECT * FROM t WHERE ism = '{ism}'" — bu SQL injection. Foydalanuvchi ' OR 1=1 -- yozsa, butun jadvalni ko'radi. Har doim ? parametrini ishlating: execute("... WHERE ism = ?", (ism,)). :::

python14 qator
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE t (ism TEXT, sir TEXT)")
con.executemany("INSERT INTO t VALUES (?, ?)", [("Aziz", "maxfiy1"), ("Bobur", "maxfiy2")])

xavfli_kirish = "' OR '1'='1"
print("1) Matn qo'shish bilan (XAVFLI):")
soro = f"SELECT * FROM t WHERE ism = '{xavfli_kirish}'"
print("   so'rov:", soro)
print("   natija:", con.execute(soro).fetchall())

print("\n2) Parametr bilan (XAVFSIZ):")
print("   natija:", con.execute("SELECT * FROM t WHERE ism = ?", (xavfli_kirish,)).fetchall())
con.close()
Chiqish
1) Matn qo'shish bilan (XAVFLI):
   so'rov: SELECT * FROM t WHERE ism = '' OR '1'='1'
   natija: [('Aziz', 'maxfiy1'), ('Bobur', 'maxfiy2')]

2) Parametr bilan (XAVFSIZ):
   natija: []

Birinchi so'rov hamma qatorni qaytardi. Ikkinchisi hech narsa — chunki bunday ismli talaba yo'q.

Formatlarni solishtiramiz

python36 qator
import csv, json, sqlite3, tempfile, time
from pathlib import Path

papka = Path(tempfile.mkdtemp())
malumot = [{"ism": f"Talaba{i}", "guruh": "ABC"[i % 3], "baho": 50 + (i * 7) % 51}
           for i in range(20_000)]

# CSV
t0 = time.perf_counter()
with (papka / "d.csv").open("w", encoding="utf-8", newline="") as f:
    w = csv.DictWriter(f, fieldnames=["ism", "guruh", "baho"]); w.writeheader(); w.writerows(malumot)
csv_yoz = (time.perf_counter() - t0) * 1000

# JSON
t0 = time.perf_counter()
(papka / "d.json").write_text(json.dumps(malumot, ensure_ascii=False), encoding="utf-8")
json_yoz = (time.perf_counter() - t0) * 1000

# SQLite
t0 = time.perf_counter()
con = sqlite3.connect(papka / "d.db")
con.execute("CREATE TABLE t (ism TEXT, guruh TEXT, baho INTEGER)")
con.executemany("INSERT INTO t VALUES (:ism, :guruh, :baho)", malumot)
con.commit(); con.close()
db_yoz = (time.perf_counter() - t0) * 1000

import pandas as pd
show(pd.DataFrame([
    {"format": "CSV", "yozish, ms": round(csv_yoz), "hajm, KB": (papka / "d.csv").stat().st_size // 1024,
     "tuzilma": "tekis jadval", "so'rov": "yo'q — hammasini o'qish kerak"},
    {"format": "JSON", "yozish, ms": round(json_yoz), "hajm, KB": (papka / "d.json").stat().st_size // 1024,
     "tuzilma": "ichma-ich", "so'rov": "yo'q — hammasini o'qish kerak"},
    {"format": "SQLite", "yozish, ms": round(db_yoz), "hajm, KB": (papka / "d.db").stat().st_size // 1024,
     "tuzilma": "jadvallar + indeks", "so'rov": "SQL, indeks bilan tez"},
]))
import shutil; shutil.rmtree(papka)
formatyozish, mshajm, KBtuzilmaso'rov
CSV11341tekis jadvalyo'q — hammasini o'qish kerak
JSON8966ichma-ichyo'q — hammasini o'qish kerak
SQLite38436jadvallar + indeksSQL, indeks bilan tez

Qaysi birini tanlash:

Holat Format
Excel da ochiladi, odam tahrirlaydi CSV
Tuzilishi ichma-ich, API bilan almashinuv JSON
Qator ko'p, qidirish/filtrlash kerak SQLite
Juda katta, ustun bo'yicha tahlil Parquet (pandas, pyarrow)

Testlar

shu faylni yaratingtests/test_chiqarish.py

python39 qator
import json

from hisobot.chiqarish import csv_yoz, json_yoz, xulosa


def test_xulosa_tuzilishi(talabalar):
    from hisobot.modellar import Natija
    x = xulosa(Natija(talabalar=talabalar, xatolar=[(5, "X", "baho son emas")]))
    assert x["jami"] == 4
    assert x["togri"] == 3
    assert x["xato"] == 1
    assert x["guruh_ortachasi"] == {"A": 90.0, "B": 70.0}
    assert x["xatolar"][0]["qator"] == 5


def test_json_yoz_oqiladi(tmp_path, talabalar):
    from hisobot.modellar import Natija
    yol = tmp_path / "n.json"
    json_yoz(Natija(talabalar=talabalar), yol)
    qayta = json.loads(yol.read_text(encoding="utf-8"))
    assert qayta["togri"] == 3


def test_json_uzbekcha_harflar(tmp_path):
    from hisobot.modellar import Natija, Talaba
    yol = tmp_path / "n.json"
    json_yoz(Natija(talabalar=[Talaba("Feruza", "A", 95, "2026-09-01")]), yol)
    matn = yol.read_text(encoding="utf-8")
    assert "a'lo" in matn
    assert "\\u" not in matn


def test_csv_yoz_sarlavha(tmp_path, talabalar):
    from hisobot.modellar import Natija
    yol = tmp_path / "n.csv"
    csv_yoz(Natija(talabalar=talabalar), yol)
    qatorlar = yol.read_text(encoding="utf-8").splitlines()
    assert qatorlar[0] == "ism,guruh,baho,sana,daraja"
    assert len(qatorlar) == 4
matn2 qator
.venv/bin/python3 -m pytest -q
python3 -m mypy
Chiqish (qaytish kodi 0, 5662 ms)
..............F...........................                               [100%]
=================================== FAILURES ===================================
________________________________ test_fayl_yoq _________________________________

tmp_path = PosixPath('/tmp/pytest-of-abulqosim/pytest-57/test_fayl_yoq0')

    def test_fayl_yoq(tmp_path):
        with pytest.raises(FileNotFoundError):
>           oqi(tmp_path / "yoq.csv")

tests/test_oqish.py:29: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

yol = PosixPath('/tmp/pytest-of-abulqosim/pytest-57/test_fayl_yoq0/yoq.csv')

    def oqi(yol: str | Path) -> list[dict[str, str]]:
        """CSV ni o'qiydi. Har qanday muammoda FaylXato qaytaradi."""
        p = Path(yol)
        log.debug("fayl o'qilmoqda: %s", p)
        try:
            matn = p.read_text(encoding="utf-8")
        except FileNotFoundError:
>           raise FaylXato(str(p), "fayl topilmadi") from None
E           hisobot.xatolar.FaylXato: faylni o'qib bo'lmadi: /tmp/pytest-of-abulqosim/pytest-57/test_fayl_yoq0/yoq.csv (fayl topilmadi)

src/hisobot/oqish.py:22: FaylXato
=========================== short test summary info ============================
FAILED tests/test_oqish.py::test_fayl_yoq - hisobot.xatolar.FaylXato: faylni ...
Success: no issues found in 8 source files

Xulosa

Tushuncha Asosiy fikr
pathlib / bilan birlashtiring; read_text, glob, rglob
encoding="utf-8" Har doim yozing — usiz kod platformaga bog'liq bo'ladi
latin-1 Xato bermaydi, lekin ma'lumotni buzadi — eng xavfli holat
ensure_ascii=False O'zbekcha harflar o'qiladigan bo'lib qoladi
JSON cheklovi date, set, Decimal yozilmaydi; tuple ro'yxatga aylanadi
CSV Qo'lda split(",") qilmang; yozishda newline=""
SQLite Standart kutubxonada; CHECK bilan cheklov qo'ying
SQL parametrlari ? ishlating — matn qo'shish injection ga olib keladi

Talaba ishi

  1. json_yoz ga date obyekti tushsa nima bo'ladi? default= bilan tuzating.
  2. 100 000 qatorli CSV yasang va uni csv.DictReader hamda pandas.read_csv bilan o'qib vaqtni solishtiring. Farq qancha?
  3. SQLite jadvaliga CREATE INDEX qo'shing va WHERE guruh = 'A' so'rovini indekssiz va indeks bilan o'lchang.
  4. xulosa() natijasini Parquet ga yozib ko'ring (pandas + pyarrow). Hajm CSV dan qanday farq qiladi?

Bu bobni bepul o'qidingiz.

Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.

Telegramda yozish Narxlar