IlmHamroh
Python kursi/Paketlash va chiqarish1/8-dars18 daqiqa
Mundarija (22)

19.1-dars: Loyiha tuzilishi

19-QISM — PAKETLASH VA CHIQARISH · 1-dars


1. Kirish va motivatsiya

Shu paytgacha kodni asosan bitta faylda yoki bir necha faylda yozdik. Kichik loyiha uchun bu yetarli, lekin kod o'sganda va uni boshqalar bilan ulashish (kutubxona yoki vosita sifatida) kerak bo'lganda, loyiha tuzilishi muhim ahamiyat kasb etadi. To'g'ri tuzilish kodni tashkil qiladi, import muammolarini oldini oladi va paketlashni (keyingi darslar) osonlashtiradi. Noto'g'ri tuzilish esa import xatolari, sinov muammolari va chalkashlikka olib keladi.

Professional Python loyihasi aniq, standart tuzilishga ega — kod, testlar, konfiguratsiya va hujjatlar o'z joyida.

Real vaziyat. Bir dasturchi foydali kutubxona yozdi va uni ulashmoqchi bo'ldi. Lekin barcha kod bitta papkada aralashib yotardi: manba kod, testlar, skriptlar, ma'lumot fayllari. Uni paketlashga uringanda muammolar chiqdi: testlar manba kodni import qila olmadi, pip install noto'g'ri fayllarni oldi, va "menda ishlaydi, o'rnatilgach yo'q" muammosi paydo bo'ldi — chunki kod o'rnatilgan paketni emas, mahalliy papkani import qilardi. U src-layout ga o'tdi: manba kod src/ da, testlar tests/ da, konfiguratsiya ildizda. Barcha muammolar yo'qoldi — tuzilish ularni oldindan oldini oldi.

Bu darsda professional loyiha tuzilishini o'rganamiz.

Bu darsda:

  • Nima uchun tuzilish muhim
  • Paket va modul (__init__.py)
  • Import turlari (mutlaq va nisbiy)
  • src-layout vs tekis (flat) layout
  • Standart loyiha tuzilishi
  • __init__.py ning roli
  • Keng tarqalgan import muammolari
  • Amaliy: loyiha skeletini qurish

ℹ Misollarda paket tuzilishi vaqtinchalik papkada quriladi va import qilib tekshiriladi.


2. Nazariya — chuqur tushuntirish

2.1. Modul va paket

Tushuncha Nima
Modul Bitta .py fayl
Paket Modullar to'plami (papka + __init__.py)
Ost-paket Paket ichidagi paket
wisar/                  # paket
  __init__.py           # paketni belgilaydi
  core.py               # modul
  utils/                # ost-paket
    __init__.py
    matn.py             # modul

__init__.py fayli papkani paketga aylantiradi — Python uni import qilinadigan qiladi.

2.2. __init__.py ning roli

__init__.py paket import qilinganda bajariladi. U:

Vazifa Misol
Paketni belgilaydi Bo'sh bo'lsa ham yetarli
Ommaviy API ni ochadi from .core import salom
Versiyani saqlaydi __version__ = "1.0.0"
__all__ belgilaydi __all__ = ["salom"]
python
# wisar/__init__.py
__version__ = "1.0.0"
from .core import salom          # foydalanuvchi: from wisar import salom

__init__.py — paketning "yuzi": foydalanuvchi nima ko'rishini belgilaydi.

2.3. Import turlari

Tur Sintaksis Qachon
Mutlaq (absolute) from wisar.core import salom Tavsiya etiladi
Nisbiy (relative) from .core import salom Paket ichida
Nisbiy (yuqoriga) from ..utils import katta Ota-paketdan
python
# wisar/utils/matn.py ichida:
from wisar.core import salom     # mutlaq — aniq
from ..core import salom         # nisbiy — qisqa

Mutlaq importlar aniqroq va ishonchli; nisbiy importlar paket ichida qisqaroq. Ko'p uslub qo'llanmasi mutlaq importlarni afzal ko'radi.

2.4. src-layout vs tekis layout

Tekis (flat) layout:

loyiha/
  wisar/               # paket to'g'ridan-to'g'ri ildizda
    __init__.py
    core.py
  tests/
  pyproject.toml

src-layout (tavsiya):

loyiha/
  src/
    wisar/             # paket src/ ichida
      __init__.py
      core.py
  tests/
  pyproject.toml

src-layout afzalligi: testlar o'rnatilgan paketni import qiladi (mahalliy papkani emas), shuning uchun "o'rnatilgach ishlamaydi" muammosi oldindan ushlanadi.

2.5. Nima uchun src-layout afzal

Muammo (tekis) src-layout yechimi
Test mahalliy papkani import qiladi O'rnatilgan paketni import qiladi
"O'rnatilgach yo'q" jim o'tadi Erta ushlanadi
Joriy papka sys.path da Aralashuv yo'q
Tasodifan noto'g'ri fayl Aniq chegara

Tekis layout oddiyroq va kichik loyiha uchun yaxshi; src-layout paketlanadigan, jiddiy loyihalar uchun.

2.6. Standart loyiha tuzilishi

loyiha/
  src/
    wisar/
      __init__.py
      core.py
      utils/
        __init__.py
  tests/
    test_core.py
  docs/                # hujjatlar (19.7)
  pyproject.toml       # konfiguratsiya (19.2)
  README.md            # tavsif
  LICENSE              # litsenziya (19.8)
  .gitignore
Element Vazifa
src/paket/ Manba kod
tests/ Testlar
pyproject.toml Metama'lumot, bog'liqliklar
README.md Loyiha tavsifi
LICENSE Foydalanish shartlari

2.7. Import muammolari

Muammo Sabab Yechim
ModuleNotFoundError Paket sys.path da yo'q O'rnating (pip install -e .)
ImportError: attempted relative import Nisbiy import to'g'ridan-to'g'ri ishga tushirildi Paket sifatida ishga tushiring (python -m)
Test import qila olmaydi Noto'g'ri tuzilish src-layout + pip install -e .
Aylanma import (circular) A B ni, B A ni import qiladi Tuzilmani qayta ko'ring

pip install -e . (editable) — loyihani "tahrirlanadigan" holatda o'rnatadi: kod o'zgarishlari darhol ko'rinadi, lekin import to'g'ri ishlaydi.

2.8. __main__.py va ishga tushirish

Paketni to'g'ridan-to'g'ri ishga tushirish uchun __main__.py:

wisar/
  __init__.py
  __main__.py          # python -m wisar bilan ishga tushadi
python
# wisar/__main__.py
from wisar.core import main
main()
bash
python -m wisar        # __main__.py ni ishga tushiradi

python -m paket — paketni to'g'ri, sys.path muammolarisiz ishga tushiradi.


3. Tez ma'lumotnoma

loyiha/
  src/paket/
    __init__.py        # __version__, ommaviy API
    core.py
    __main__.py        # python -m paket
  tests/
  pyproject.toml
  README.md, LICENSE
python
# __init__.py
__version__ = "1.0.0"
from .core import salom             # ommaviy API

# import turlari:
from paket.core import salom        # mutlaq (tavsiya)
from .core import salom             # nisbiy (paket ichida)

Qoidalar

paket = papka + __init__.py
src-layout — paketlanadigan loyiha uchun
mutlaq importlar — aniqroq
pip install -e . — tahrirlanadigan o'rnatish
python -m paket — to'g'ri ishga tushirish
testlar tests/ da, kod src/ da

4. Batafsil misollar

Misollarda paket tuzilishi vaqtinchalik papkada quriladi va import qilib tekshiriladi.

Misol 1 — Paket va modul tuzilishi

python
"""paket = papka + __init__.py; modul = .py fayl; ost-paket; __init__.py ommaviy API va versiyani ochadi; import qilib tekshirish."""

import subprocess
import sys
import tempfile
from pathlib import Path


def main() -> None:
    with tempfile.TemporaryDirectory() as katalog:
        r = Path(katalog)
        paket = r / "wisar"
        (paket / "utils").mkdir(parents=True)

        # __init__.py — ommaviy API va versiya
        (paket / "__init__.py").write_text(
            '__version__ = "1.0.0"\nfrom .core import salom\n', encoding="utf-8")
        (paket / "core.py").write_text(
            'def salom(ism):\n    return f"Salom, {ism}!"\n', encoding="utf-8")
        (paket / "utils" / "__init__.py").write_text(
            'from .matn import katta\n', encoding="utf-8")
        (paket / "utils" / "matn.py").write_text(
            'def katta(s):\n    return s.upper()\n', encoding="utf-8")

        print("=== 1. Tuzilish ===")
        for yol in sorted(paket.rglob("*.py")):
            print(f"  {yol.relative_to(r).as_posix()}")

        print("\n=== 2. Import qilib tekshirish ===")
        kod = (
            "import wisar\n"
            "print('version:', wisar.__version__)\n"
            "print(wisar.salom('Aziz'))\n"
            "from wisar.utils import katta\n"
            "print('katta:', katta('salom'))\n"
            "print('paket (has __path__):', hasattr(wisar, '__path__'))\n"
        )
        natija = subprocess.run([sys.executable, "-c", kod], cwd=r, capture_output=True, text=True, encoding="utf-8")
        for qator in natija.stdout.splitlines():
            print(f"  {qator}")

        print("\n=== 3. __init__.py roli ===")
        print("  __init__.py papkani PAKETga aylantiradi")
        print("  __version__ va 'from .core import salom' — ommaviy API")
        print("  ⭐ foydalanuvchi: 'from wisar import salom' (core ichida ekanini bilmaydi)")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Tuzilish ===
  wisar/__init__.py
  wisar/core.py
  wisar/utils/__init__.py
  wisar/utils/matn.py

=== 2. Import qilib tekshirish ===
  version: 1.0.0
  Salom, Aziz!
  katta: SALOM
  paket (has __path__): True

=== 3. __init__.py roli ===
  __init__.py papkani PAKETga aylantiradi
  __version__ va 'from .core import salom' — ommaviy API
  ⭐ foydalanuvchi: 'from wisar import salom' (core ichida ekanini bilmaydi)

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

Misol 2 — Import turlari (mutlaq va nisbiy)

python
"""mutlaq (from paket.core import) va nisbiy (from .core import) importlar; ikkalasi ham ishlaydi; nisbiy faqat paket ichida; python -m bilan ishga tushirish."""

import subprocess
import sys
import tempfile
from pathlib import Path


def main() -> None:
    with tempfile.TemporaryDirectory() as katalog:
        r = Path(katalog)
        paket = r / "wisar"
        paket.mkdir()

        (paket / "__init__.py").write_text("", encoding="utf-8")
        (paket / "core.py").write_text('KOEFF = 10\n', encoding="utf-8")
        # mutlaq import ishlatadigan modul
        (paket / "mutlaq.py").write_text(
            'from wisar.core import KOEFF\n'
            'def hisobla(x):\n    return x * KOEFF\n', encoding="utf-8")
        # nisbiy import ishlatadigan modul
        (paket / "nisbiy.py").write_text(
            'from .core import KOEFF\n'
            'def hisobla(x):\n    return x * KOEFF\n', encoding="utf-8")

        print("=== 1. Mutlaq import (from wisar.core import) ===")
        kod = "from wisar.mutlaq import hisobla\nprint('mutlaq:', hisobla(5))\n"
        natija = subprocess.run([sys.executable, "-c", kod], cwd=r, capture_output=True, text=True, encoding="utf-8")
        print(f"  {natija.stdout.strip()}")

        print("\n=== 2. Nisbiy import (from .core import) ===")
        kod = "from wisar.nisbiy import hisobla\nprint('nisbiy:', hisobla(5))\n"
        natija = subprocess.run([sys.executable, "-c", kod], cwd=r, capture_output=True, text=True, encoding="utf-8")
        print(f"  {natija.stdout.strip()}")

        print("\n=== 3. ⚠️ Nisbiy importni to'g'ridan-to'g'ri ishga tushirish ===")
        natija = subprocess.run([sys.executable, str(paket / "nisbiy.py")], capture_output=True, text=True, encoding="utf-8")
        xato_bor = "ImportError" in natija.stderr or "attempted relative" in natija.stderr
        print(f"  'python nisbiy.py' xato beradi: {xato_bor}")
        print("  ⭐ nisbiy import faqat paket sifatida ishlaydi (python -m wisar.nisbiy)")

        print("\n=== 4. Xulosa ===")
        print("  mutlaq (from wisar.core): aniq, har joyda ishlaydi — tavsiya")
        print("  nisbiy (from .core): qisqa, faqat paket ichida")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Mutlaq import (from wisar.core import) ===
  mutlaq: 50

=== 2. Nisbiy import (from .core import) ===
  nisbiy: 50

=== 3. ⚠️ Nisbiy importni to'g'ridan-to'g'ri ishga tushirish ===
  'python nisbiy.py' xato beradi: True
  ⭐ nisbiy import faqat paket sifatida ishlaydi (python -m wisar.nisbiy)

=== 4. Xulosa ===
  mutlaq (from wisar.core): aniq, har joyda ishlaydi — tavsiya
  nisbiy (from .core): qisqa, faqat paket ichida

Nima ko'rsatdi: 2.3-bo'lim.

Misol 3 — src-layout va o'rnatish

python
"""src-layout: paket src/ ichida; tekis layout bilan farq; nima uchun src-layout testlar uchun ishonchliroq; tuzilish namunasi."""

import subprocess
import sys
import tempfile
from pathlib import Path


def main() -> None:
    with tempfile.TemporaryDirectory() as katalog:
        r = Path(katalog)

        print("=== 1. src-layout tuzilishi ===")
        (r / "src" / "wisar").mkdir(parents=True)
        (r / "tests").mkdir()
        (r / "src" / "wisar" / "__init__.py").write_text('from .core import salom\n', encoding="utf-8")
        (r / "src" / "wisar" / "core.py").write_text('def salom(ism):\n    return f"Salom, {ism}!"\n', encoding="utf-8")
        (r / "tests" / "test_core.py").write_text('from wisar import salom\ndef test_salom():\n    assert salom("Aziz") == "Salom, Aziz!"\n', encoding="utf-8")
        (r / "pyproject.toml").write_text('[project]\nname = "wisar"\nversion = "1.0.0"\n', encoding="utf-8")
        (r / "README.md").write_text("# Wisar\n", encoding="utf-8")

        for yol in sorted(r.rglob("*")):
            if yol.is_file():
                print(f"  {yol.relative_to(r).as_posix()}")

        print("\n=== 2. src-layout bilan import (src yo'lda) ===")
        kod = "import sys; sys.path.insert(0, 'src')\nfrom wisar import salom\nprint(salom('Aziz'))\n"
        natija = subprocess.run([sys.executable, "-c", kod], cwd=r, capture_output=True, text=True, encoding="utf-8")
        print(f"  {natija.stdout.strip()}")

        print("\n=== 3. Tekis vs src-layout ===")
        print("  tekis: loyiha/wisar/ — paket ildizda, joriy papka sys.path'da")
        print("  src:   loyiha/src/wisar/ — paket src/ ichida, aralashuv yo'q")
        print("  ⭐ src-layout: testlar O'RNATILGAN paketni import qiladi (mahalliy emas)")
        print("  ⭐ 'o'rnatilgach ishlamaydi' muammosi oldindan ushlanadi")

        print("\n=== 4. pip install -e . g'oyasi ===")
        print("  'pip install -e .' — tahrirlanadigan o'rnatish")
        print("  kod o'zgarishlari darhol ko'rinadi, LEKIN import to'g'ri ishlaydi")
        print("  ⭐ rivojlanishda qulay, tuzilish to'g'ri")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. src-layout tuzilishi ===
  pyproject.toml
  README.md
  src/wisar/__init__.py
  src/wisar/core.py
  tests/test_core.py

=== 2. src-layout bilan import (src yo'lda) ===
  Salom, Aziz!

=== 3. Tekis vs src-layout ===
  tekis: loyiha/wisar/ — paket ildizda, joriy papka sys.path'da
  src:   loyiha/src/wisar/ — paket src/ ichida, aralashuv yo'q
  ⭐ src-layout: testlar O'RNATILGAN paketni import qiladi (mahalliy emas)
  ⭐ 'o'rnatilgach ishlamaydi' muammosi oldindan ushlanadi

=== 4. pip install -e . g'oyasi ===
  'pip install -e .' — tahrirlanadigan o'rnatish
  kod o'zgarishlari darhol ko'rinadi, LEKIN import to'g'ri ishlaydi
  ⭐ rivojlanishda qulay, tuzilish to'g'ri

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

Misol 4 — Amaliy: loyiha skeletini qurish

To'liq professional loyiha skeletini yaratuvchi skript yozamiz: src-layout, testlar, konfiguratsiya, __main__.py, README va boshqalar. Bu — yangi paketlanadigan loyiha boshlashning standart tuzilishi.

python
"""to'liq loyiha skeleti: src-layout, __init__.py (versiya+API), __main__.py, tests/, pyproject.toml, README; import va python -m bilan tekshirish."""

import subprocess
import sys
import tempfile
from pathlib import Path


def loyiha_yarat(ildiz: Path, nom: str) -> None:
    paket = ildiz / "src" / nom
    (paket / "utils").mkdir(parents=True)
    (ildiz / "tests").mkdir()

    (paket / "__init__.py").write_text(
        f'"""{nom} — Wisar namunaviy paketi."""\n'
        f'__version__ = "0.1.0"\n'
        f'from .core import salomla\n', encoding="utf-8")
    (paket / "core.py").write_text(
        'def salomla(ism: str) -> str:\n    return f"Salom, {ism}!"\n', encoding="utf-8")
    (paket / "__main__.py").write_text(
        f'from {nom}.core import salomla\n'
        'import sys\n'
        'ism = sys.argv[1] if len(sys.argv) > 1 else "dunyo"\n'
        'print(salomla(ism))\n', encoding="utf-8")
    (paket / "utils" / "__init__.py").write_text("", encoding="utf-8")
    (paket / "utils" / "matn.py").write_text('def katta(s: str) -> str:\n    return s.upper()\n', encoding="utf-8")
    (ildiz / "tests" / "test_core.py").write_text(
        f'from {nom} import salomla\ndef test_salomla():\n    assert salomla("Aziz") == "Salom, Aziz!"\n', encoding="utf-8")
    (ildiz / "pyproject.toml").write_text(
        f'[project]\nname = "{nom}"\nversion = "0.1.0"\nrequires-python = ">=3.11"\n', encoding="utf-8")
    (ildiz / "README.md").write_text(f"# {nom}\n\nWisar namunaviy paketi.\n", encoding="utf-8")
    (ildiz / ".gitignore").write_text(".venv/\n__pycache__/\n*.pyc\ndist/\n", encoding="utf-8")


def main() -> None:
    with tempfile.TemporaryDirectory() as katalog:
        r = Path(katalog)
        loyiha_yarat(r, "wisar")

        print("=== 1. Yaratilgan tuzilish ===")
        for yol in sorted(r.rglob("*")):
            if yol.is_file():
                print(f"  {yol.relative_to(r).as_posix()}")

        print("\n=== 2. Paketni import qilish ===")
        kod = "import sys; sys.path.insert(0, 'src')\nimport wisar\nprint('version:', wisar.__version__)\nprint(wisar.salomla('Aziz'))\n"
        natija = subprocess.run([sys.executable, "-c", kod], cwd=r, capture_output=True, text=True, encoding="utf-8")
        for qator in natija.stdout.splitlines():
            print(f"  {qator}")

        print("\n=== 3. python -m wisar bilan ishga tushirish ===")
        env = {"PYTHONPATH": str(r / "src")}
        import os
        env2 = {**os.environ, **env}
        natija = subprocess.run([sys.executable, "-m", "wisar", "Bek"], cwd=r, capture_output=True, text=True, encoding="utf-8", env=env2)
        print(f"  chiqish: {natija.stdout.strip()}")

        print("\n=== 4. Skelet elementlari ===")
        print("  src/wisar/ — manba kod; tests/ — testlar")
        print("  __init__.py — versiya+API; __main__.py — python -m")
        print("  pyproject.toml — metama'lumot 19.2-bob; README, LICENSE, .gitignore")
        print("  ⭐ standart tuzilish — paketlash 19.3-bob va nashr 19.4-bob uchun tayyor")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Yaratilgan tuzilish ===
  .gitignore
  pyproject.toml
  README.md
  src/wisar/__init__.py
  src/wisar/__main__.py
  src/wisar/core.py
  src/wisar/utils/__init__.py
  src/wisar/utils/matn.py
  tests/test_core.py

=== 2. Paketni import qilish ===
  version: 0.1.0
  Salom, Aziz!

=== 3. python -m wisar bilan ishga tushirish ===
  chiqish: Salom, Bek!

=== 4. Skelet elementlari ===
  src/wisar/ — manba kod; tests/ — testlar
  __init__.py — versiya+API; __main__.py — python -m
  pyproject.toml — metama'lumot 19.2-bob; README, LICENSE, .gitignore
  ⭐ standart tuzilish — paketlash 19.3-bob va nashr 19.4-bob uchun tayyor

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


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

Noto'g'ri fikr To'g'risi
"Barcha kodni bitta papkaga" Tuzilish import va paketlash uchun muhim
"__init__.py shart emas" Papkani paketga aylantiradi (implicit paketlar cheklovli)
"Nisbiy import har doim yaxshi" Mutlaq importlar aniqroq
"src-layout ortiqcha" Testlar uchun ishonchliroq
"Test kodni to'g'ridan import qiladi" pip install -e . bilan o'rnating
"python fayl.py har doim ishlaydi" Nisbiy importda xato
"Tuzilish keyin tuzatiladi" Boshdan to'g'ri qilish oson
"__main__.py keraksiz" python -m paket uchun

6. Keng tarqalgan xatolar va yechimlari

1. Hamma narsa bitta papkada

loyiha/*.py                        # ❌ kod, test, skript aralash
loyiha/src/paket/, tests/          # ✅ ajratilgan

2. __init__.py siz papka

paket/core.py                      # ⚠️ implicit paket (muammoli)
paket/__init__.py, core.py         # ✅ aniq paket

3. Nisbiy importni to'g'ridan ishga tushirish

bash
python paket/modul.py              # ❌ ImportError (nisbiy import)
python -m paket.modul              # ✅

4. Test o'rnatilmagan paketni import

python
# tests/ manba kodni topa olmaydi   # ❌
pip install -e .                   # ✅ tahrirlanadigan o'rnatish

5. sys.path ni qo'lda o'zgartirish

python
sys.path.insert(0, "../src")       # ❌ mo'rt
pip install -e .                   # ✅ to'g'ri o'rnatish

6. Aylanma import

python
# a.py: from b import x; b.py: from a import y   # ❌ circular
# ✅ umumiy kodni uchinchi modulga ajrating

7. __init__.py da og'ir kod

python
# __init__.py da katta hisob         # ⚠️ import sekinlashtiradi
# ✅ faqat API ni oching, hisobni funksiyada

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 18.1–18.3-darslar (o'tilgan): venv, pip — loyiha muhiti
  • 19.2-dars: pyproject.toml — loyiha metama'lumoti
  • 19.3-dars: paket yig'ish — bu tuzilishdan
  • 17.3-dars (o'tilgan): fixture, testlar — tests/ papkasi
  • 27-qism: arxitektura — katta loyiha tuzilishi

8. Eng yaxshi amaliyotlar

  1. src-layout ishlating (paketlanadigan loyiha uchun).

  2. Har paketda __init__.py — ommaviy API va versiyani oching.

  3. Mutlaq importlarni afzal ko'ring (aniqroq).

  4. Testlarni tests/ da, pip install -e . bilan o'rnating.

  5. python -m paket uchun __main__.py qo'shing.

  6. Kod, test, konfiguratsiya, hujjatlarni ajrating.

  7. Aylanma importlardan qoching (tuzilmani qayta ko'ring).

  8. Loyihani boshidan to'g'ri tuzilishda boshlang.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # papkani paketga nima aylantiradi?
2.  # modul nima?
3.  # 'from .core import x' qaysi import turi?
4.  # 'from paket.core import x' qaysi tur?
5.  # src-layout da paket qayerda?
6.  # __init__.py da __version__ nima uchun?
7.  # python -m paket qaysi faylni ishga tushiradi?
8.  # 'python paket/modul.py' nisbiy importda nima bo'ladi?
9.  # pip install -e . nima qiladi?
10. # tests/ papkasi nima uchun?
11. # __init__.py bo'sh bo'lsa ishlaydimi?
12. # mutlaq import afzalligimi yoki nisbiy?
Javoblar
  1. __init__.py fayli
  2. Bitta .py fayl
  3. Nisbiy (relative)
  4. Mutlaq (absolute)
  5. src/ papkasida
  6. Paket versiyasini saqlash uchun
  7. __main__.py
  8. ImportError (attempted relative import)
  9. Loyihani tahrirlanadigan holatda o'rnatadi
  10. Testlar uchun (koddan ajratilgan)
  11. Ha — papkani paketga aylantiradi
  12. Mutlaq (aniqroq, ishonchli)

Vazifa 2: Xatolarni tuzating

1.  loyiha/
      main.py
      test.py
      utils.py
      ma'lumot.csv       # hammasi aralash

2.  paket/
      core.py            # __init__.py yo'q

3.  # nisbiy import ishga tushirish:
    python paket/modul.py

4.  # test:
    import sys
    sys.path.insert(0, "../src")   # qo'lda path

5.  # a.py: from b import x
    # b.py: from a import y        # aylanma
Javoblar
1.  loyiha/
      src/paket/
        __init__.py
        core.py
        utils.py
      tests/test_core.py
      data/malumot.csv    # ajratilgan

2.  paket/
      __init__.py        # qo'shildi
      core.py

3.  python -m paket.modul   # paket sifatida

4.  pip install -e .          # sys.path emas, o'rnatish

5.  # umumiy.py ga x, y ni ajrating
    # a.py: from umumiy import x
    # b.py: from umumiy import y

Vazifa 3: Loyiha skeleti

loyiha_yarat(nom) skripti:

  1. src-layout, tests/, pyproject.toml, README.md, LICENSE, .gitignore
  2. __init__.py (versiya+API), __main__.py
  3. Namunaviy modul va test
  4. Import va python -m bilan tekshiring

Vazifa 4: Import tahlili

Loyihadagi importlarni tahlil qiling:

  1. Mutlaq va nisbiy importlarni sanang
  2. Aylanma importlarni toping
  3. Ishlatilmagan importlarni (18.4, ruff) toping
  4. Nisbiylarni mutlaqqa aylantiring

Vazifa 5: __init__.py dizayni

Paket uchun __init__.py:

  1. Ommaviy API ni aniqlang (from .core import ...)
  2. __all__ bilan eksportni belgilang
  3. __version__ qo'shing
  4. Ichki (_yashirin) modullarni yashiring

Vazifa 6: src-layout migratsiya

Tekis layout loyihani src-layout ga:

  1. Paketni src/ ga ko'chiring
  2. Testlarni yangilang
  3. pyproject.toml ni sozlang
  4. Import va testlar ishlashini tasdiqlang

Vazifa 7: O'ylash

src-layout uzoq bahs mavzusi bo'lgan: ba'zi dasturchilar uni "ortiqcha murakkablik" deb hisoblaydi, boshqalari "yagona to'g'ri yo'l" deydi. Nima uchun tuzilish tanlovi shunchalik muhim va bahsli, va "kelishuv ustidan aniqlik" (convention over configuration) tamoyili loyiha tuzilishida qanday namoyon bo'ladi?

Javob

Qisqa javob: Tuzilish tanlovi bahsli, chunki u oddiylik (tekis — kam papka) va ishonchlilik (src — muammolarni oldindan ushlaydi) orasidagi muvozanat. Kichik loyihada tekis yetarli, katta/paketlanadiganda src afzal. "Kelishuv ustidan aniqlik" (convention over configuration) — standart tuzilishga amal qilib, vositalar (test, build, IDE) uni avtomatik tushunishi. Standart tuzilish qaror yukini kamaytiradi va vositalar ekotizimiga mos keladi.

1. Nega tuzilish muhim

Sabab Tafsilot
Import to'g'riligi Noto'g'ri tuzilish — import xatolari
Paketlash Vositalar standart tuzilishni kutadi
Test ishonchliligi src — o'rnatilgan paketni sinaydi
Yangi a'zoga oson Standart — tanish
Vosita mosligi IDE, build, test avtomatik tushunadi

2. Tekis vs src bahsi

Tekis afzalligi src afzalligi
Oddiyroq (kam papka) Test o'rnatilgan paketni sinaydi
Kichik loyiha uchun yaxshi "O'rnatilgach yo'q" ni ushlaydi
Kam ko'chirish Aniq chegara
Tez boshlash Jiddiy loyiha uchun ishonchli

3. "Kelishuv ustidan aniqlik"

Tamoyil Loyiha tuzilishida
Standart tuzilish src/, tests/, pyproject.toml
Vositalar tushunadi pytest, build, IDE avtomatik
Kam sozlash Standartga amal qil — sozlash shart emas
Bashoratlilik Har loyiha tanish ko'rinadi

4. Muvozanat

Loyiha Tavsiya
Kichik skript Bitta fayl yoki tekis
O'rta kutubxona Tekis yoki src
Paketlanadigan/jiddiy src-layout
Katta jamoa Standart (src) muhim

5. Muhandislik saboqlari

  1. Tuzilish — texnik va ijtimoiy qaror (jamoa uchun)
  2. Standartlar qaror yukini kamaytiradi
  3. Vositalar ekotizimiga moslik muhim
  4. Oddiylik va ishonchlilik muvozanati

6. Xulosa

  1. Tuzilish import, paketlash, test uchun muhim
  2. Tekis — oddiy, src — ishonchli
  3. "Kelishuv ustidan aniqlik" — standart tuzilish
  4. Loyiha kattaligiga qarab tanlang

Nimani mustahkamlaydi: 2.1–2.8-bo'limlar.


Xulosa

Bu darsda professional loyiha tuzilishini o'rgandik.

Eng muhim uch fikr:

  1. Paket = papka + __init__.py. Modul — bitta .py fayl, paket — modullar to'plami (__init__.py fayli papkani paketga aylantiradi). __init__.py paketning "yuzi": ommaviy API ni ochadi (from .core import salom), versiyani saqlaydi (__version__) — foydalanuvchi from wisar import salom yozadi, kod core ichida ekanini bilmaydi. Mutlaq importlar (from wisar.core import ...) aniqroq va ishonchli; nisbiy (from .core import ...) paket ichida qisqaroq.

  2. src-layout — paketlanadigan loyiha uchun. Tekis layoutda paket ildizda (loyiha/wisar/), src-layoutda esa src/ ichida (loyiha/src/wisar/). src-layout afzalligi: testlar o'rnatilgan paketni import qiladi (mahalliy papkani emas), shuning uchun "o'rnatilgach ishlamaydi" muammosi oldindan ushlanadi. pip install -e . (editable) loyihani tahrirlanadigan holatda o'rnatadi — kod o'zgarishlari darhol ko'rinadi, import to'g'ri ishlaydi.

  3. Standart tuzilish va ishga tushirish. Professional loyiha: src/paket/ (kod), tests/ (testlar), pyproject.toml (metama'lumot), README.md, LICENSE, .gitignore. __main__.py bilan paketni python -m paket orqali to'g'ri (sys.path muammolarisiz) ishga tushirasiz. Nisbiy importni to'g'ridan-to'g'ri ishga tushirish (python paket/modul.py) xato beradi — paket sifatida (python -m) ishga tushiring. "Kelishuv ustidan aniqlik" — standart tuzilishga amal qilib, vositalar (test, build, IDE) uni avtomatik tushunadi.

Keyingi darsda loyiha metama'lumotini — pyproject.toml ni chuqurroq o'rganamiz: paket nomi, versiya, bog'liqliklar, kirish nuqtalari va build tizimini sozlash.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
19.1-dars: Loyiha tuzilishi — IlmHamroh