Modul, paket va import tizimi
Import aslida nima qiladi
import hisobot yozganingizda Python uch ish qiladi: faylni topadi, uni bajaradi, natijani
keshlaydi. Uchalasi ham muammo manbai bo'lishi mumkin, shuning uchun har birini ko'rib chiqamiz.
import sys, json print("keshlangan modullar soni:", len(sys.modules)) print("misol:", [m for m in list(sys.modules) if m.startswith("json")][:3]) print("json qayerdan yuklandi:", sys.modules["json"].__file__)
keshlangan modullar soni: 818 misol: ['json.scanner', 'json.decoder', 'json.encoder'] json qayerdan yuklandi: /usr/lib/python3.10/json/__init__.py
sys.modules — keshi. Bir modul bir marta bajariladi, keyin shu keshdan olinadi.
shu faylni yaratingsanagich.py
print(" [sanagich moduli bajarilmoqda]") QIYMAT = 42
python3 -c " import sanagich import sanagich import sanagich print('uch marta import qilindi, lekin:') print('QIYMAT =', sanagich.QIYMAT) "
[sanagich moduli bajarilmoqda] uch marta import qilindi, lekin: QIYMAT = 42
Xabar bir marta chiqdi. Bu muhim xulq: modul darajasidagi kod (fayl ichidagi, funksiyadan tashqaridagi kod) faqat birinchi importda ishlaydi.
Python modulni qayerdan qidiradi
import sys for i, yol in enumerate(sys.path[:6]): print(f" {i}. {yol or '(joriy papka)'}")
0. /mnt/c/Users/Admin/Desktop/Course Material/Python_Muhandisligi/ish 1. /mnt/c/Users/Admin/Desktop/Course Material/Python_Muhandisligi/ish 2. /mnt/c/Users/Admin/Desktop/Course Material/Python_Muhandisligi/book_src 3. /usr/lib/python310.zip 4. /usr/lib/python3.10 5. /usr/lib/python3.10/lib-dynload
Tartib muhim: Python yuqoridan pastga qaraydi va birinchi topilganini oladi. Shuning uchun
o'z faylingizni json.py deb nomlasangiz, standart json o'rniga sizniki yuklanadi.
Buni ko'rsatamiz:
shu faylni yaratingtuzoq/json.py
XABAR = "bu standart kutubxona EMAS, bu mening faylim"
cd tuzoq && python3 -c " import json print('json.__file__ =', json.__file__) print(getattr(json, 'XABAR', 'standart json')) try: json.dumps({'a': 1}) except AttributeError as e: print('XATO:', e) "
json.__file__ = /mnt/c/Users/Admin/Desktop/Course Material/Python_Muhandisligi/ish/tuzoq/json.py bu standart kutubxona EMAS, bu mening faylim XATO: module 'json' has no attribute 'dumps'
Standart json "yo'qoldi". Bu xato haqiqiy loyihalarda tez-tez uchraydi va topish qiyin, chunki xabar
mutlaqo boshqa joyda chiqadi.
:::gotcha Fayl nomlari
Hech qachon standart kutubxona nomlarini ishlatmang: json.py, csv.py, time.py, random.py,
types.py, string.py, email.py, logging.py, test.py. Tekshirish oson:
python3 -c "import X" — xato bermasa, bu nom band.
:::
Absolyut va nisbiy import
Paket ichida ikki usul bor:
shu faylni yaratingsrc/hisobot/tekshiruv.py
"""Qoidalar: qator to'g'rimi yoki yo'q.""" ENG_KATTA_BAHO = 100 def bahoni_tekshir(xom): """Matnni bahoga aylantiradi. Xato bo'lsa sabab bilan ValueError.""" try: baho = int(xom) except (TypeError, ValueError): raise ValueError(f"baho son emas: {xom!r}") from None if not 0 <= baho <= ENG_KATTA_BAHO: raise ValueError(f"baho 0..{ENG_KATTA_BAHO} oralig'ida bo'lishi kerak, berilgan: {baho}") return baho
shu faylni yaratingsrc/hisobot/oqish.py
"""CSV o'qish va qatorlarni tekshirish.""" import csv from hisobot.tekshiruv import bahoni_tekshir # absolyut import from .tekshiruv import ENG_KATTA_BAHO # nisbiy import — xuddi shu modul def oqi(yol): with open(yol, encoding="utf-8") as f: return list(csv.DictReader(f)) def tozala(qatorlar): """(to'g'ri qatorlar, xatolar) qaytaradi.""" yaxshi, xatolar = [], [] for i, q in enumerate(qatorlar, start=2): try: yaxshi.append({**q, "baho": bahoni_tekshir(q.get("baho"))}) except ValueError as e: xatolar.append((i, q.get("ism", "?"), str(e))) return yaxshi, xatolar
.venv/bin/python3 -c " from hisobot.oqish import oqi, tozala from hisobot.tekshiruv import ENG_KATTA_BAHO print('eng katta baho:', ENG_KATTA_BAHO) yaxshi, xatolar = tozala(oqi('sinov_malumot.csv')) print('to\'g\'ri:', len(yaxshi), '| xatolar:', len(xatolar)) for x in xatolar: print(' ', x) "
eng katta baho: 100 to'g'ri: 6 | xatolar: 2 (5, 'Elyor', "baho son emas: ''") (8, 'Hasan', "baho son emas: 'abc'")
Ikkala import usuli ham ishladi. Farqi:
| Usul | Yozuv | Qachon |
|---|---|---|
| Absolyut | from hisobot.tekshiruv import X |
Odatiy tanlov — aniq va ko'chirishga chidamli |
| Nisbiy | from .tekshiruv import X |
Paket ichida, paket nomi o'zgarishi mumkin bo'lsa |
Nisbiy import faqat paket ichida ishlaydi. To'g'ridan-to'g'ri ishga tushirilgan faylda u xato beradi:
.venv/bin/python3 src/hisobot/oqish.py
Traceback (most recent call last):
File "/mnt/c/Users/Admin/Desktop/Course Material/Python_Muhandisligi/ish/src/hisobot/oqish.py", line 5, in <module>
from .tekshiruv import ENG_KATTA_BAHO # nisbiy import — xuddi shu modul
ImportError: attempted relative import with no known parent package
Qaytish kodi 1. Sabab: fayl to'g'ridan-to'g'ri ishga tushirilganda u paket a'zosi emas, shunchaki skript — demak "nisbiy" nimaga nisbatan ekani noma'lum.
To'g'ri usul — -m bayrog'i bilan modul sifatida chaqirish:
shu faylni yaratingsrc/hisobot/__main__.py
"""python3 -m hisobot bilan ishga tushadi.""" import sys from .oqish import oqi, tozala from .hisob import guruh_ortachasi def main(argv=None): argv = sys.argv[1:] if argv is None else argv if not argv: print("ishlatish: python3 -m hisobot <fayl.csv>") return 2 yaxshi, xatolar = tozala(oqi(argv[0])) print(f"to'g'ri: {len(yaxshi)}, xato: {len(xatolar)}") for g, o in guruh_ortachasi(yaxshi).items(): print(f" {g}: {o}") return 0 if not xatolar else 1 if __name__ == "__main__": sys.exit(main())
.venv/bin/python3 -m hisobot sinov_malumot.csv .venv/bin/python3 -m hisobot
to'g'ri: 6, xato: 2 A: 90.67 B: 83.0 C: 61.0 ishlatish: python3 -m hisobot <fayl.csv>
Ikkinchi chaqiruv qaytish kodi 2 berdi — argument berilmagani uchun. Bu tasodifiy emas: buyruq qatori dasturlari muvaffaqiyatda 0, xatoda noldan farqli kod qaytaradi. 15-bobda buni kengaytiramiz.
Aylanma import (circular import)
Ikki modul bir-birini import qilsa nima bo'ladi?
shu faylni yaratingaylana_a.py
import aylana_b NOM = "A" def a_dan(): return f"A -> {aylana_b.NOM}"
shu faylni yaratingaylana_b.py
import aylana_a NOM = "B" def b_dan(): return f"B -> {aylana_a.NOM}"
python3 -c "import aylana_a; print(aylana_a.a_dan())"
A -> B
Bu ishladi, chunki import aylana_b moduli obyekt sifatida oladi va aylana_b.NOM ga faqat
funksiya chaqirilganda murojaat qiladi — o'shanda modul to'liq yuklangan bo'ladi.
Endi from ... import ... bilan sinaymiz:
shu faylni yaratingaylana_c.py
from aylana_d import NOM_D NOM = "C"
shu faylni yaratingaylana_d.py
from aylana_c import NOM NOM_D = "D"
python3 -c "import aylana_c"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/mnt/c/Users/Admin/Desktop/Course Material/Python_Muhandisligi/ish/aylana_c.py", line 1, in <module>
from aylana_d import NOM_D
File "/mnt/c/Users/Admin/Desktop/Course Material/Python_Muhandisligi/ish/aylana_d.py", line 1, in <module>
from aylana_c import NOM
ImportError: cannot import name 'NOM' from partially initialized module 'aylana_c' (most likely due to a circular import) (/mnt/c/Users/Admin/Desktop/Course Material/Python_Muhandisligi/ish/aylana_c.py)
Bu yiqildi. ImportError — aylana_c hali NOM ni belgilamagan paytda aylana_d uni so'radi.
Farqni tushunish muhim: import X kechiktiradi, from X import Y esa darhol qiymatni talab
qiladi.
Aylanma importning haqiqiy yechimi — uni yo'q qilish. Odatda u dizayn muammosini bildiradi: ikki modul bir-biriga juda bog'lanib qolgan. Umumiy qismni uchinchi modulga chiqaring.
__init__.py nima qiladi
shu faylni yaratingsrc/hisobot/__init__.py
"""CSV ma'lumotini tekshirib hisobot chiqaradigan asbob.""" from .hisob import guruh_ortachasi from .oqish import oqi, tozala from .tekshiruv import bahoni_tekshir __version__ = "0.3.0" __all__ = ["guruh_ortachasi", "oqi", "tozala", "bahoni_tekshir", "__version__"]
.venv/bin/python3 -c " import hisobot print('versiya:', hisobot.__version__) print('ochiq nomlar:', hisobot.__all__) print('to\'g\'ridan-to\'g\'ri ishlaydi:', hisobot.bahoni_tekshir('85')) "
versiya: 0.3.0 ochiq nomlar: ['guruh_ortachasi', 'oqi', 'tozala', 'bahoni_tekshir', '__version__'] to'g'ridan-to'g'ri ishlaydi: 85
Endi foydalanuvchi from hisobot.tekshiruv import bahoni_tekshir o'rniga from hisobot import
bahoni_tekshir yoza oladi. __init__.py — paketning ommaviy yuzi.
__all__ esa ikki ish qiladi: from hisobot import * nimani olishini belgilaydi va o'quvchiga
"mana bular rasmiy API" deb aytadi.
:::tip __init__.py ni yengil saqlang
Unga faqat import va versiya yozing, mantiq yozmang. Sababi: import hisobot har safar __init__.py
ni to'liq bajaradi. Unda og'ir ish bo'lsa (fayl o'qish, tarmoqqa chiqish), har import sekinlashadi.
:::
Buni o'lchaymiz:
import subprocess, time, statistics ISH_S = str(ISH) def olch(kod, n=5): vaqtlar = [] for _ in range(n): t0 = time.perf_counter() subprocess.run([f"{ISH_S}/.venv/bin/python3", "-c", kod], cwd=ISH_S, capture_output=True) vaqtlar.append((time.perf_counter() - t0) * 1000) return round(statistics.median(vaqtlar), 1) bosh = olch("pass", n=9) bilan = olch("import hisobot", n=9) print(f"bo'sh Python ishga tushishi : {bosh} ms") print(f"import hisobot bilan : {bilan} ms") print(f"paketning o'z narxi : {round(bilan - bosh, 1)} ms")
bo'sh Python ishga tushishi : 39.7 ms import hisobot bilan : 59.0 ms paketning o'z narxi : 19.3 ms
Xulosa
| Tushuncha | Asosiy fikr |
|---|---|
sys.modules |
Modul bir marta bajariladi, keyin keshdan olinadi |
sys.path |
Yuqoridan pastga qidiriladi; joriy papka birinchi |
| Nom to'qnashuvi | json.py deb nomlamang — standart kutubxonani berkitadi |
| Absolyut import | Odatiy tanlov: from hisobot.tekshiruv import X |
| Nisbiy import | Faqat paket ichida; to'g'ridan-to'g'ri ishga tushirilsa xato |
python3 -m paket |
__main__.py ni ishga tushiradi, nisbiy importlar ishlaydi |
| Aylanma import | import X chidaydi, from X import Y yiqiladi; ildizi — dizayn |
__init__.py |
Paketning ommaviy yuzi; yengil saqlang |
Talaba ishi
sys.pathning birinchi elementini o'zgartirib ko'ring (sys.path.insert). Qanday holatda bu kerak bo'ladi va nega undan qochish kerak?aylana_c/aylana_dni tuzating: umumiy qismniaylana_umumiy.pyga chiqaring.__init__.pygatime.sleep(0.5)qo'shing va yuqoridagi o'lchovni qayta ishga tushiring.import hisobotqancha sekinlashdi?python3 -m hisobotga mavjud bo'lmagan fayl nomini bering. Qanday xato chiqadi va foydalanuvchi uchun tushunarlimi? (8-bobda buni tuzatamiz.)
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.