aidoc.uz

3-qism · Professional Python·09-bob

Modullar, paketlar va virtual muhitlar

import qanday ishlaydi, sys.path va sys.modules, __name__ == '__main__', paketlar va src-layout, aylanma importlar, venv ichida nima bor, pip va uv, pyproject.toml, versiyalar va lock fayllar.

Bitta faylda dastur yozish — o'rganish uchun yaxshi. Lekin real loyiha — o'nlab modul, yuzlab tashqi kutubxona va bir necha muhit (sizning noutbukingiz, hamkasbingiz, server, GPU klaster). "Mening kompyuterimda ishlaydi" muammosining 90% shu bobdagi mavzularni bilmaslikdan keladi.

▶ Video dars· Corey Schafer· 27:01· ingliz tilida
Python Tutorial: UV - A Faster, All-in-One Package Manager to Replace Pip and Venv

uv bilan loyiha yaratish, paket qo'shish, Python versiyalari va lock fayllar — bobning 6–7-bo'limlaridagi ish jarayoni amalda.

YouTube'da ochish ↗

1. Modul — bu shunchaki .py fayl#

# matematika.py
PI = 3.14159
 
def aylana_yuzasi(r: float) -> float:
    return PI * r ** 2
# main.py
import matematika
 
print(matematika.aylana_yuzasi(2))
print(matematika.PI)

Import shakllari#

import math                          # modulni import; math.sqrt(...)
import numpy as np                   # taxallus bilan — jamiyat an'anasi
from math import sqrt, pi            # aniq nomlarni olish; sqrt(...)
from pathlib import Path
from collections import defaultdict as dd   # nomni o'zgartirish (kam ishlatiladi)
from math import *                   # ❌ hamma narsani — qayerdan kelgani noaniq

An'anaviy taxalluslar — ularni o'zgartirmang, butun dunyo shunday yozadi:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import torch.nn as nn
import torch.nn.functional as F

from X import * ishlatmang. U qaysi nom qayerdan kelganini yashiradi va nomlar to'qnashuviga olib keladi (masalan, numpydagi sum built-in sumni yopib qo'yadi).

Importlarni tartiblash (PEP 8)#

# 1. Standart kutubxona
import json
import os
from pathlib import Path
 
# 2. Uchinchi tomon kutubxonalari
import numpy as np
import pandas as pd
from anthropic import Anthropic
 
# 3. Loyihaning o'z modullari
from myproject.data import load_dataset
from myproject.models import Classifier

Har guruh orasida bo'sh qator. Ruff buni avtomatik tartiblaydi (ruff check --select I --fix).

2. import ichkarida nima qiladi#

  1. sys.modules'da qidiradi

    Agar modul allaqachon import qilingan bo'lsa — keshdan o'sha obyektni qaytaradi. Modul kodi faqat bir marta bajariladi, nechta joyda import qilinmasin.

  2. sys.path bo'yicha faylni topadi

    sys.path — papkalar ro'yxati. Python ularni tartib bilan ko'rib chiqadi va birinchi topilgan matematika.py yoki matematika/ paketini oladi.

  3. Modulni yuklaydi va bajaradi

    Fayl bytecode'ga kompilyatsiya qilinadi (__pycache__da keshlanadi), yuqoridan pastga bajariladi, natijada modul obyekti hosil bo'ladi.

  4. Nomni bog'laydi

    import matematika joriy faylda matematika nomini modul obyektiga bog'laydi.

import sys
print(sys.path)
# ['/home/aziz/proj',                       ← ishga tushirilgan skript papkasi (birinchi!)
#  '/home/aziz/.local/share/uv/python/.../lib/python3.13',   ← standart kutubxona
#  '/home/aziz/proj/.venv/lib/python3.13/site-packages']     ← o'rnatilgan paketlar

Modul kodi import paytida bajariladi#

# config.py
print("config yuklanmoqda...")      # import paytida chiqadi!
DB = connect_to_database()          # import paytida ulanadi!

Modul darajasida faqat ta'riflar (funksiyalar, klasslar, konstantalar) bo'lsin. Og'ir ishlar (ulanish, model yuklash, fayl o'qish) funksiya ichida bo'lsin va kerak bo'lganda chaqirilsin. Aks holda oddiy import sekin va yon ta'sirli bo'ladi, testlash qiyinlashadi.

3. if __name__ == "__main__":#

Har bir modulda __name__ degan maxsus o'zgaruvchi bor:

  • fayl to'g'ridan-to'g'ri ishga tushirilsa (python file.py) — "__main__";
  • fayl import qilinsa — modul nomi ("matematika").
# matematika.py
def aylana_yuzasi(r):
    return 3.14159 * r ** 2
 
 
if __name__ == "__main__":
    # faqat `python matematika.py` da ishlaydi, import qilinganda — yo'q
    print(aylana_yuzasi(2))

Bu bitta faylni ham kutubxona, ham skript sifatida ishlatish imkonini beradi. Har bir ishga tushiriladigan skriptda shu blok bo'lsin — ayniqsa multiprocessing (17-bob) busiz Windows/macOS'da cheksiz jarayonlar yaratib yuborishi mumkin.

python -m — modulni skript sifatida ishga tushirish#

python -m venv .venv          # venv modulini ishga tushirish
python -m pip install numpy   # aynan SHU python'ning pip'i
python -m pytest              # joriy papka sys.path'ga qo'shiladi
python -m http.server 8000    # oddiy veb-server
python -m myproject.train     # paket ichidagi modulni

python -m pip va oddiy pip farqi: birinchisi aynan qaysi Python ishlatilayotganini kafolatlaydi. Kompyuterda bir nechta Python bo'lsa, pip install boshqa Python'ga o'rnatib qo'yishi mumkin.

4. Paketlar#

Paket — modullar papkasi:

myproject/
├── __init__.py          # papkani paket qiladi (ixtiyoriy, lekin tavsiya etiladi)
├── data/
│   ├── __init__.py
│   ├── loading.py
│   └── cleaning.py
├── models/
│   ├── __init__.py
│   └── classifier.py
└── train.py
from myproject.data.loading import load_dataset
from myproject.models.classifier import Classifier
import myproject.data.cleaning as cleaning

__init__.py#

Paket import qilinganda __init__.py bajariladi. Uni ikki maqsadda ishlatishadi:

# myproject/data/__init__.py
"""Ma'lumotlarni yuklash va tozalash."""
 
from .cleaning import clean_text
from .loading import load_dataset
 
__all__ = ["clean_text", "load_dataset"]

Endi foydalanuvchi qisqaroq yozadi: from myproject.data import load_dataset. __all__ — paketning "ommaviy API"si ro'yxati.

__init__.pyni og'ir qilmang: unda katta kutubxonalarni import qilsangiz, paketning har qanday qismini import qilish sekinlashadi.

Nisbiy importlar#

# myproject/data/loading.py
from .cleaning import clean_text           # shu paketdan
from ..models.classifier import Classifier # bir daraja yuqoridan

Nisbiy importlar faqat paket ichida ishlaydi. Klassik xato: python myproject/data/loading.py deb fayl sifatida ishga tushirsangiz — ImportError: attempted relative import with no known parent package. To'g'risi: python -m myproject.data.loading.

Aylanma importlar (circular imports)#

# a.py
from b import g
def f(): return g()
 
# b.py
from a import f      # a hali to'liq yuklanmagan!
def g(): return 1

ImportError: cannot import name 'f' from partially initialized module 'a'.

Yechimlar (yaxshisidan yomoniga):

  1. Arxitekturani tuzating — umumiy kodni uchinchi modulga (common.py) ko'chiring. Aylanma bog'liqlik — odatda dizayn muammosi belgisi.
  2. Modulni import qiling, nomni emas: import b, keyin b.g() — nom chaqiruv paytida qidiriladi.
  3. Importni funksiya ichiga ko'chiring (oxirgi chora).

5. Loyiha tuzilmasi: src-layout#

Professional Python loyihalari odatda shunday tuziladi:

sentiment-classifier/
├── pyproject.toml          # loyiha tavsifi, bog'liqliklar, vosita sozlamalari
├── uv.lock                 # aniq versiyalar (avtomatik yaratiladi)
├── README.md
├── .gitignore              # .venv/, __pycache__/, .env, data/ ...
├── .env.example            # qaysi muhit o'zgaruvchilari kerakligi (qiymatlarsiz!)
├── src/
│   └── sentiment/
│       ├── __init__.py
│       ├── config.py
│       ├── data.py
│       ├── model.py
│       └── cli.py
├── tests/
│   ├── test_data.py
│   └── test_model.py
├── notebooks/              # tajribalar (22-bob)
│   └── 01-eda.ipynb
└── scripts/
    └── download_data.py

Nega src/ ichida? Chunki unda testlar va skriptlar paketni joriy papkadan "tasodifan" emas, balki o'rnatilgan paket sifatida import qiladi — bu "mening kompyuterimda ishlaydi, CI'da ishlamaydi" xatolarini oldini oladi. uv init --package nom shunday tuzilmani avtomatik yaratadi.

6. Virtual muhitlar#

Muammo#

Loyiha A:  numpy 1.26 kerak (eski kutubxona tufayli)
Loyiha B:  numpy 2.1 kerak
Tizim:     faqat bitta numpy o'rnatilishi mumkin

Virtual muhit (venv) — har bir loyiha uchun alohida site-packages papkasi. U Python'ning to'liq nusxasi emas — faqat havola va o'z paketlari papkasi:

.venv/
├── bin/                 # (Windows'da Scripts/)
│   ├── python → /usr/.../python3.13      # asl Python'ga havola
│   ├── pip
│   └── activate         # terminalni shu muhitga o'tkazuvchi skript
├── lib/python3.13/site-packages/          # SHU loyihaning paketlari
└── pyvenv.cfg           # qaysi Python asosida yaratilgani

"Activate" qilish — shunchaki PATHning boshiga .venv/bin ni qo'shish, shunda python buyrug'i shu muhitdagi Python'ni topadi. Sehr yo'q.

Klassik usul: venv + pip#

python3 -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
python -m pip install numpy pandas
python -m pip freeze > requirements.txt
deactivate

Zamonaviy usul: uv#

uv init sentiment-classifier --package
cd sentiment-classifier
uv add pandas scikit-learn anthropic        # asosiy bog'liqliklar
uv add --dev pytest ruff mypy ipykernel     # faqat ishlab chiqish uchun
uv run python -m sentiment.cli              # .venv avtomatik yaratiladi/yangilanadi
uv sync                                     # boshqa kompyuterda: lock bo'yicha aynan bir xil muhit
uv lock --upgrade-package pandas            # bitta paketni yangilash
Vazifapip / venvuv
Muhit yaratishpython -m venv .venvavtomatik (uv run, uv sync)
Paket qo'shishpip install x + qo'lda requirements.txtuv add x (pyproject + lock yangilanadi)
Aniq takrorlashpip freeze (to'liq emas)uv.lock + uv sync
Python versiyasini boshqarishAlohida vosita (pyenv)uv python install 3.13
Tezlik—10–100× tezroq

7. pyproject.toml#

Zamonaviy Python loyihasining "pasporti":

[project]
name = "sentiment"
version = "0.1.0"
description = "Sharhlar sentimentini aniqlovchi klassifikator"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
    "anthropic>=0.70",
    "pandas>=2.2",
    "scikit-learn>=1.5",
]
 
[project.scripts]
sentiment = "sentiment.cli:main"     # `sentiment` buyrug'i → sentiment/cli.py dagi main()
 
[dependency-groups]
dev = ["pytest>=8", "ruff>=0.8", "mypy>=1.13"]
 
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
 
[tool.ruff]
line-length = 100
 
[tool.pytest.ini_options]
testpaths = ["tests"]

Bir faylda: metama'lumot, bog'liqliklar, buyruqlar va vositalar (ruff, pytest, mypy) sozlamalari.

Versiya cheklovlari#

YozuvMa'nosi
pandasIstalgan versiya (xavfli)
pandas>=2.22.2 yoki yangiroq
pandas>=2.2,<32.x, lekin 3.0 emas (katta o'zgarishlardan himoya)
pandas~=2.2>=2.2, <3.0 bilan bir xil
pandas==2.2.3Aynan shu (kutubxona uchun yomon, ilova uchun lock faylda)

Semantik versiyalash (SemVer): MAJOR.MINOR.PATCH — MAJOR o'zgarsa, eski kod buzilishi mumkin. Shuning uchun <3 kabi yuqori chegara ba'zan foydali.

Lock fayl nega kerak#

pyproject.toml — "qanday versiyalar mos keladi" (oraliq). uv.lock — "aynan qaysi versiyalar o'rnatilgan" (har bir paket va uning bog'liqliklari, hash'lari bilan). Lock fayl tufayli olti oydan keyin yoki boshqa kompyuterda uv sync aynan bir xil muhitni tiklaydi.

ML'da bu ayniqsa muhim: torch yoki transformersning kichik versiya o'zgarishi natijalarni o'zgartirishi mumkin. Takrorlanuvchanlik (reproducibility) — ilmiy ishning asosi.

8. Muhit o'zgaruvchilari va sirlar#

API kalitlari, parollar, ma'lumotlar bazasi manzillari hech qachon kodda yozilmasligi kerak:

client = Anthropic(api_key="sk-ant-api03-...")    # ❌ Git'ga tushadi, sizib chiqadi

To'g'ri yo'l — muhit o'zgaruvchilari:

import os
 
api_key = os.environ["ANTHROPIC_API_KEY"]          # yo'q bo'lsa — KeyError (yaxshi: darhol bilinadi)
debug = os.environ.get("DEBUG", "0") == "1"        # ixtiyoriy, standart qiymat bilan

Mahalliy ishlab chiqishda .env fayl qulay:

# .env  (Git'ga QO'SHILMAYDI!)
ANTHROPIC_API_KEY=sk-ant-...
DATABASE_URL=postgresql://localhost/dev
from dotenv import load_dotenv    # uv add python-dotenv
 
load_dotenv()                     # .env dagi qiymatlarni os.environ'ga yuklaydi

9. Amaliyot: kichik paket yaratamiz#

  1. Loyiha

    uv init textkit --package
    cd textkit
  2. Kod

    # src/textkit/__init__.py
    from .clean import clean_text, normalize_apostrophes
     
    __all__ = ["clean_text", "normalize_apostrophes"]
    # src/textkit/clean.py
    import re
     
    _APOSTROPHES = str.maketrans({"ʻ": "'", "‘": "'", "’": "'", "`": "'", "ʼ": "'"})
     
     
    def normalize_apostrophes(text: str) -> str:
        return text.translate(_APOSTROPHES)
     
     
    def clean_text(text: str) -> str:
        text = normalize_apostrophes(text)
        text = re.sub(r"\s+", " ", text)
        return text.strip()
    # src/textkit/cli.py
    import sys
     
    from textkit import clean_text
     
     
    def main() -> None:
        for line in sys.stdin:
            print(clean_text(line))
  3. Buyruqni ro'yxatdan o'tkazish

    pyproject.tomlga:

    [project.scripts]
    textkit = "textkit.cli:main"
  4. Ishga tushirish

    terminal
    echo ' Oʻzbekiston gʻalabasi ' | uv run textkit
    O'zbekiston g'alabasi

Endi bu paketni boshqa loyihada ham ishlatish mumkin: uv add ../textkit (mahalliy yo'l) yoki Git manzili orqali.

Nima noto'g'ri ketishi mumkin#

BelgiSababYechim
ModuleNotFoundError: No module named 'x' (o'rnatgan bo'lsangiz ham)Boshqa Python/muhit ishlatilmoqdawhich python, sys.executable; uv run yoki python -m pip
AttributeError: module 'numpy' has no attribute ...Loyihada numpy.py fayli borFaylni qayta nomlang, __pycache__ni o'chiring
attempted relative import with no known parent packagePaket ichidagi faylni to'g'ridan-to'g'ri ishga tushirishpython -m paket.modul
cannot import name ... from partially initialized moduleAylanma importUmumiy kodni alohida modulga ko'chiring
Import juda sekinModul darajasida og'ir ishlarFunksiyalarga ko'chiring, kechiktirilgan yuklash
Hamkasbda boshqa natijaVersiyalar farqiLock fayl + uv sync
externally-managed-environmentTizim Python'iga o'rnatish urinishiVirtual muhit
Kalit Git'da.env yoki kodda kalitKalitni bekor qiling, .gitignore
Amaliy topshiriq

1. sys.path tajribasi

Loyihangizda json.py nomli fayl yarating va boshqa faylda import json; json.dumps({}) qiling. Nima bo'ladi va nega? json.__file__ nimani ko'rsatadi? Tajribadan keyin faylni o'chiring.

Maslahatni ko'rsatish

Loyiha papkasida json.py yarating (ichida print('soxta json')), keyin import json qiling. Keyin uni o'chirib, __pycache__ ni ham tozalang.

Amaliy topshiriq

2. __name__ ni kuzating

a.py va b.py yarating, ikkalasiga ham print(f"{__file__}: {__name__}") yozing. b.py ichida import a qiling. python a.py va python b.py natijalarini solishtiring. import a ni ikki marta yozsangiz, adagi print necha marta chiqadi?

Maslahatni ko'rsatish

Ikkala faylga print(__name__) qo'ying; birini ikkinchisidan import qiling va ikkalasini navbat bilan ishga tushiring.

Amaliy topshiriq

3. Paketni qayta tuzish

Oldingi boblarda yozgan funksiyalaringizdan (clean_text, normalize, batched, chunk_text) mlutils paketini yarating: src-layout, pyproject.toml, __init__.pyda ommaviy API, kamida bitta CLI buyruq va tests/ papkasi (hozircha bo'sh — 16-bobda to'ldiramiz). uv sync va uv run bilan ishlashini tekshiring.

Maslahatni ko'rsatish

src/<nom>/ tuzilmasi, __init__.py da ommaviy API, project.scripts orqali buyruq, uv add --dev pytest.

Amaliy topshiriq

4. Sozlamalar moduli

config.py modulini yozing: .envdan (python-dotenv) ANTHROPIC_API_KEY (majburiy), MODEL (standart "claude-opus-5-5"), MAX_TOKENS (int, standart 1024), DEBUG (bool) ni o'qisin. Majburiy kalit yo'q bo'lsa, tushunarli xabar bilan xato bersin. Modul import paytida hech narsa chiqarmasin — get_settings() funksiyasi orqali ishlasin va natijani functools.cache bilan keshlasin.

Yodda saqlang
  • 01Modul — .py fayl; kodi birinchi importda bir marta bajariladi va sys.modules'da keshlanadi.
  • 02sys.path'ning birinchi elementi — skript papkasi: fayllarni kutubxona nomlari bilan atamang.
  • 03if __name__ == '__main__': — faylni ham modul, ham skript qiladi.
  • 04Paket — __init__.py li papka; professional loyihalarda src-layout.
  • 05Aylanma import — dizayn muammosi; umumiy kodni alohida modulga ko'chiring.
  • 06Har loyiha — o'z virtual muhiti; uv add / uv sync / uv run, pyproject.toml + uv.lock Git'da.
  • 07Sirlar — muhit o'zgaruvchilarida yoki .env da, hech qachon kodda; .env — .gitignore'da.

Mustahkamlash

Test va amaliy masalalar

Avval testni ishlang — har javobdan keyin izoh chiqadi. Keyin masalalarni shu yerning o'zida yechib, brauzerdagi haqiqiy Python bilan avtomatik tekshiring. Natijalaringiz kurs progressi sahifasida jamlanadi.

Test: topshirilmaganMasalalar: 0/3

Bilimni tekshirish

Bob bo'yicha test

12 ta savol · har javobdan keyin to'g'ri yoki xatoligi va izoh ko'rsatiladi · oxirida natija foizda.

Amaliy masalalar

Kodni yozing va «Tekshirish»ni bosing (yoki Ctrl/⌘ + Enter). Kodingiz shu brauzerda saqlanib turadi.

01Sozlamalarni muhitdan o'qish

load_settings(env) — env lug'atidan (amalda os.environ) sozlamalarni o'qib lug'at qaytarsin:

  • ANTHROPIC_API_KEY — majburiy; yo'q yoki bo'sh bo'lsa RuntimeError (xabarda kalit nomi bo'lsin);
  • MODEL — standart "claude-opus-5-5";
  • MAX_TOKENS — int, standart 1024;
  • DEBUG — "1"/"true" → True, aks holda False.

Natija kalitlari: api_key, model, max_tokens, debug.

02Versiya cheklovini tekshirish

satisfies(version, spec) — "2.2.3" kabi versiya ">=2.2,<3" kabi cheklovga mosmi tekshirsin. Faqat >=, <, == operatorlari va vergul bilan ajratilgan shartlar. Versiyalarni sonlar tuple'i sifatida solishtiring ("2.10" > "2.9"!).

03.gitignore tekshiruvchi

must_ignore(paths) — Git'ga qo'shilmasligi kerak bo'lgan fayllar ro'yxatini (asl tartibda) qaytarsin: .venv/ yoki __pycache__/ ichidagilar, .env (lekin .env.example emas), .pyc fayllar.