06 β Modullar va muhit¶
Dasturlaring kattalashganda, butun kodni bitta faylga yozish noqulay bo'lib qoladi. Python kodni modullarga (alohida fayllarga) bo'lish va boshqalar yozgan tayyor kutubxonalardan foydalanish imkonini beradi. Bu modulda kodni qanday bo'lish, paketlarga guruhlash, tashqi kutubxonalarni o'rnatish, zamonaviy loyiha standartini (pyproject.toml) sozlash va loyihalarni toza saqlashni o'rganasan.
Bu modulda:
import, standart kutubxonadan foydalanish, o'z modulingni yozish,if __name__ == "__main__", paket strukturasi (__init__.py, nisbiy import,__all__, sub-paketlar),pipbilan kutubxona o'rnatish, virtual muhit (venv),pyproject.toml(PEP 621), editable install,uv/poetry, semantik versiyalash va muhit o'zgaruvchilari (os.environ,.env).
6.1 Modul nima? import¶
Modul β bu Python kodi bo'lgan .py fayl. Boshqa fayldagi kodni import orqali olib ishlatasan. Python o'zida ko'plab tayyor modullar bilan keladi (standart kutubxona).
import qilganingda Python modulni qator joylardan ma'lum tartib bilan qidiradi β quyidagi diagramma shu jarayonni ko'rsatadi:
import math # butun modulni import qilish
print(math.sqrt(16)) # 4.0 β modul nomi.funksiya
print(math.pi) # 3.14159...
Faqat kerakli qismini olish (from):
from math import sqrt, pi # faqat sqrt va pi
print(sqrt(25)) # 5.0 β endi math. yozish shart emas
print(pi)
Modulga qisqa nom berish (as):
import random as r # random ni r deb chaqiramiz
print(r.randint(1, 6)) # 1..6 oralig'ida tasodifiy son
Bir nechta foydali standart modul:
import math # matematik funksiyalar (sqrt, ceil, floor, pi...)
import random # tasodifiy sonlar va tanlovlar
import datetime # sana va vaqt
import random
print(random.choice(["olma", "banan", "uzum"])) # tasodifiy bittasi
print(random.randint(1, 100)) # 1..100 tasodifiy
Eslatma β
from modul import *dan saqlan. Gohofrom os import *ko'rinishidagi kodni uchratasan: bu modulning hamma nomini joriy fayl bo'shlig'iga to'kib tashlaydi va qaysi nom qaerdan kelganini chalkashtiradi. Professional kodda deyarli har doimimport osyoki aniqfrom os import getenvyoziladi.*import'i faqat modulning__all__ro'yxatidagi nomlarni oladi (buni 6.4-bo'limda ko'ramiz).
6.2 O'z modulingni yozish¶
Har qanday .py fayl β modul. Masalan hisob.py faylini yarat. Bu yerda funksiyalarni darrov type hint bilan yozamiz β Python 3.13 uslubi (int, float), shunda muharrirlaring xatoni oldindan ko'rsatadi va kod o'qish oson bo'ladi:
# hisob.py
def qosh(a: int, b: int) -> int:
return a + b
def kop(a: int, b: int) -> int:
return a * b
PI: float = 3.14159
Boshqa fayldan (masalan main.py) uni import qilasan:
# main.py (hisob.py bilan bir papkada)
import hisob
print(hisob.qosh(3, 5)) # 8
print(hisob.PI) # 3.14159
# yoki:
from hisob import qosh
print(qosh(10, 20)) # 30
Bu kodni tartibli saqlashning asosiy yo'li: bog'liq funksiyalarni alohida modullarga ajratasan (masalan
hisob.py,fayllar.py,foydalanuvchi.py), keyinmain.pyda birlashtirasan.
Loyiha o'sganda bog'liq modullarni bitta papkaga β paketga β guruhlaysan. Papka __init__.py faylini olganida paketga aylanadi va ichidagi modullarga nuqta bilan murojaat qilasan:
Paket strukturasini keyingi bo'limda chuqurroq ochamiz.
6.3 if __name__ == "__main__":¶
Bu satrni Python fayllarida tez-tez ko'rasan. Uning ma'nosi: "agar bu fayl to'g'ridan-to'g'ri ishga tushirilsa" (import qilinmasa).
# hisob.py
def qosh(a: int, b: int) -> int:
return a + b
if __name__ == "__main__":
# bu blok faqat 'python hisob.py' deganda ishlaydi,
# 'import hisob' qilinganda ishlamaydi
print("Test:", qosh(2, 3))
Nega kerak? Modulingni boshqa joydan import qilganda, undagi test/namoyish kodi avtomatik ishlab ketmasligi uchun. Funksiyalar import qilinadi, lekin
if __name__ == "__main__":ichidagi kod faqat fayl o'zi ishga tushirilganda bajariladi. Hozircha "fayl bevosita ishga tushganda ishlaydigan kod" deb tushun.
Har bir modulda Python avtomatik __name__ o'zgaruvchisini o'rnatadi. Fayl bevosita ishga tushganda u "__main__" ga teng bo'ladi, import qilinganda esa modul nomiga ("hisob"). Buni o'z ko'zing bilan ko'rsang ishonchli bo'ladi:
Endi python hisob.py desang __name__ = '__main__', import hisob qilsang __name__ = 'hisob' chiqadi. Aynan shu farq blokni ishlatadi yoki ishlatmaydi.
6.4 Paket strukturasi β __init__.py, nisbiy import, __all__¶
Loyiha bir nechta modulga o'sganda, ularni paket ichiga guruhlash kerak. Paket β bu __init__.py fayli bo'lgan papka. Quyidagi struktura odatiy:
mypkg/
βββ __init__.py # paketni belgilaydi, "fasad" vazifasini bajaradi
βββ hisob.py # modul
βββ matn.py # modul
βββ geom/ # sub-paket (paket ichidagi paket)
βββ __init__.py
βββ doira.py
Modullar ichida oddiy funksiyalar:
# mypkg/hisob.py
def qosh(a: int, b: int) -> int:
return a + b
def ayir(a: int, b: int) -> int:
return a - b
Nisbiy import (from . import ...). Paket ichidagi modullar bir-birini import qilganda nuqta bilan boshlanadigan nisbiy yo'ldan foydalanadi: bitta nuqta . β shu paket, ikkita nuqta .. β bir pog'ona yuqori. Bu paket nomini qattiq kodlamaslik (hardcode) imkonini beradi β paketni qayta nomlasang ham ishlaydi.
# mypkg/geom/__init__.py
from .doira import yuza # "." = shu sub-paket (geom)
__all__ = ["yuza"] # 'from mypkg.geom import *' nimani oladi
__init__.py β paketning fasadi. Asosiy __init__.py ichida kichik modullardan kerakli nomlarni yuqoriga "ko'taras" β shunda foydalanuvchi mypkg.hisob.qosh o'rniga to'g'ridan-to'g'ri mypkg.qosh yozadi:
# mypkg/__init__.py
from .hisob import qosh, ayir # "." = shu paket (mypkg)
from .matn import teskari
from .geom import yuza # sub-paketdan
# 'from mypkg import *' aynan shularni oladi (boshqasini emas):
__all__ = ["qosh", "ayir", "teskari", "yuza"]
# Paket versiyasi β keng tarqalgan konvensiya:
__version__ = "1.0.0"
Endi tashqaridan ishlatish toza va qisqa:
# main.py (mypkg papkasi yonida)
import mypkg
from mypkg import qosh, teskari # fasad orqali
from mypkg.geom import yuza # sub-paketdan
print(qosh(3, 5)) # 8
print(teskari("salom")) # molas
print(round(yuza(2), 3)) # 12.566
print(mypkg.__version__) # 1.0.0
__all__nima qiladi? Bu ro'yxat ikki ishni boshqaradi: (1)from mypkg import *qaysi nomlarni oladi va (2) paketning "rasmiy" ommaviy interfeysini hujjatlaydi. Ro'yxatdan tashqaridagi nomlar (masalan, ichki yordamchi funksiyalar)*bilan kelmaydi β bu kapsulalashning bir ko'rinishi.__all__bo'lmasa,*pastki chiziq bilan boshlanmagan hamma nomni oladi.Nisbiy yoki absolyut import? Paket ichida β nisbiy (
from . import hisob). Paketni tashqaridan ishlatganda β absolyut (from mypkg import qosh). Eslatma: nisbiy import faqat paket ichidagi modullarda ishlaydi; faylni to'g'ridan-to'g'ripython mypkg/hisob.pydeb ishga tushirsang nisbiy import xato beradi (chunki u "paket konteksti"ni yo'qotadi). Shuning uchun paket modullarinipython -m mypkg.hisobko'rinishida ishga tushirish odat.
6.5 pip β tashqi kutubxonalarni o'rnatish¶
Standart kutubxonadan tashqari, jamoa yozgan minglab kutubxonalar bor (internetda, PyPI omborida). Ularni pip bilan o'rnatasan (terminalda):
pip install requests # 'requests' kutubxonasini o'rnatadi (internet so'rovlari uchun)
pip install rich # chiroyli terminal chiqishi uchun
O'rnatilgandan keyin koddan ishlatasan:
Foydali buyruqlar:
pip list # o'rnatilgan kutubxonalar ro'yxati
pip install --upgrade requests # yangilash
pip uninstall requests # o'chirish
pip show requests # kutubxona haqida ma'lumot (versiya, bog'liqliklar)
Maslahat β
pipni modul sifatida chaqir. Bir nechta Python o'rnatilgan tizimdapip installqaysi Python'ga o'rnatayotganini bilish qiyin. Aniqlik uchunpython -m pip install requestsyoz β bu aynan shupythonningpipini ishlatadi. Bu eng ishonchli usul.
6.6 Virtual muhit (venv) β loyihalarni ajratish¶
Har loyihaning o'z kutubxonalar to'plami bo'lishi kerak. Aks holda turli loyihalar bir-biriga xalaqit beradi (biriga kerakli versiya boshqasini buzishi mumkin). Virtual muhit (venv) β har loyiha uchun alohida, izolyatsiyalangan Python muhiti.
# 1. Virtual muhit yaratish (loyiha papkasida):
python -m venv venv
# 2. Uni faollashtirish:
# Linux / macOS:
source venv/bin/activate
# Windows:
venv\Scripts\activate
# 3. Endi pip install shu muhitga o'rnatadi (tizimga emas):
pip install requests
# 4. Ishni tugatib, chiqish:
deactivate
Faollashtirilganda terminalda (venv) belgisi paydo bo'ladi β demak izolyatsiyalangan muhitdasan.
Nega muhim? Tasavvur qil: A loyihaga kutubxonaning 1-versiyasi, B loyihaga 2-versiyasi kerak. Virtual muhitsiz ular to'qnashadi. Har loyihaga alohida venv β har birida kerakli versiya. Bu professional amaliyot, har doim ishlat.
Quyidagi diagramma venv'siz to'qnashuv va venv bilan izolyatsiya o'rtasidagi farqni ko'rsatadi:
6.7 requirements.txt β loyiha bog'liqliklari¶
Loyihangda qaysi kutubxonalar kerakligini bitta faylda saqlaysan β requirements.txt. Shunda boshqa odam (yoki sen boshqa kompyuterda) hammasini bir buyruq bilan o'rnatadi:
# Joriy kutubxonalarni faylga yozish:
pip freeze > requirements.txt
# Boshqa joyda hammasini o'rnatish:
pip install -r requirements.txt
requirements.txt taxminan shunday ko'rinadi:
Loyihangni GitHub'ga qo'yganingda
requirements.txtni ham qo'sh β shunda boshqalar loyihangni oson ishga tushiradi.venv/papkasini esa qo'shma (u katta va har kompyuterda qayta yaratiladi).
pip freezening kamchiligi (antipattern haqida).pip freeze > requirements.txtmuhitdagi hamma paketni β sen bevosita talab qilganlarni ham, ularning ichki bog'liqliklarini ham β bir tekis ro'yxatga to'kadi. Natijada qaysi paket senga kerak, qaysisi shunchaki boshqasi tortib kelgan β bilib bo'lmaydi. Kichik skript uchun bu yetarli, lekin haqiqiy loyihada zamonaviy yo'l boshqacha: bevosita bog'liqliklarnipyproject.tomlda nomli ro'yxat sifatida saqlash. Buni keyingi bo'limda ko'ramiz.
6.8 pyproject.toml β zamonaviy loyiha standarti (PEP 621)¶
Bugungi Python loyihasining "pasporti" β pyproject.toml fayli. Bu standart (PEP 621) loyiha nomi, versiyasi, bog'liqliklari va metama'lumotlarini bitta odam o'qiy oladigan faylda jamlaydi. U requirements.txt ni ham, eski setup.py ni ham almashtiradi.
Loyiha ildizida pyproject.toml shunday ko'rinadi:
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "mening-loyiham"
version = "1.0.0"
description = "Kichik namuna loyiha"
readme = "README.md"
requires-python = ">=3.13"
authors = [
{ name = "Oqil Imomnazarov", email = "imomnazarovoqil@gmail.com" },
]
license = "MIT"
# Bevosita bog'liqliklar β sen TALAB qilgan kutubxonalar (ichki emas):
dependencies = [
"requests>=2.31",
"rich>=13.7",
]
[project.optional-dependencies]
# Faqat ishlab chiqishda kerak bo'ladigan qo'shimcha paketlar:
dev = [
"pytest>=8.0",
"ruff>=0.5",
]
[project.scripts]
# Terminalga buyruq qo'shadi: o'rnatgandan keyin 'salom' deb yozish mumkin
salom = "mypkg:main"
Buning afzalligi pip freeze ga nisbatan: bu yerda faqat sen tanlaganlar turadi (requests, rich), ularning ichki bog'liqliklari avtomatik hal qilinadi. Bog'liqliklar qaysi versiya oralig'ida ishlashini ham aniq ko'rsatasan (>=2.31).
O'rnatish endi sodda:
# Loyihani va uning bog'liqliklarini o'rnatish:
pip install .
# Dev qo'shimchalari bilan birga:
pip install ".[dev]"
pyproject.tomlqaerdan o'qiladi? Bu fayl Python ekotizimida umumiy:pip,uv,poetry,ruff,pytest,blackβ barchasi shu bir fayldan sozlama oladi (har biri o'z[tool.*]bo'limida). Bitta fayl β butun loyihaning markazi.
6.9 Editable install β pip install -e .¶
O'z paketingni yozayotganda uni qayta-qayta o'rnatib o'tirish zerikarli: kodni o'zgartirsang, yana pip install . qilishing kerak bo'lardi. Buni hal qiluvchi yo'l β editable (tahrirlash) rejimida o'rnatish:
-e (editable) bilan o'rnatganda Python paketni nusxalamaydi, balki uning manba papkasiga havola qo'yadi. Endi import mypkg har joydan ishlaydi, lekin sen kodni o'zgartirsang β qayta o'rnatishsiz darrov kuchga kiradi. Bu o'z kutubxonangni ishlab chiqayotganda standart amaliyot:
# Tipik ishlash tartibi:
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -e ".[dev]" # loyihani editable + dev paketlar bilan
# Endi kodni tahrirla, darrov sina:
python -c "import mypkg; print(mypkg.__version__)"
Nima uchun
-ekerak? Editable install paketni "ishlab chiqilayapti" deb belgilaydi: import yo'li to'g'ri ishlaydi (paket istalgan papkadan import qilinadi), ammo manba sening nazoratingda qoladi. Editable bo'lmagan oddiypip install .esa nusxa oladi β har o'zgarishdan keyin qayta o'rnatish kerak bo'ladi. Demak: kutubxonani ishlatuvchi β oddiypip install, kutubxonani yozuvchi βpip install -e.
6.10 uv va poetry β zamonaviy boshqaruvchilar¶
pip + venv + requirements.txt uchligi ishlaydi, lekin uch alohida vosita. Zamonaviy loyihalar ko'pincha hammasini bitta vosita bilan boshqaradi. Eng mashhuri ikkitasi:
uv β Rust'da yozilgan, juda tez (pip'dan o'nlab marta tez) yangi vosita. Virtual muhit, o'rnatish va loyiha boshqaruvini birlashtiradi:
# Yangi loyiha yaratish (pyproject.toml avtomatik tuziladi):
uv init mening-loyiham
cd mening-loyiham
# Bog'liqlik qo'shish (pyproject.toml ni o'zi yangilaydi):
uv add requests
uv add --dev pytest # dev guruhiga
# Loyihani ishga tushirish (venv'ni o'zi yaratib, faollashtiradi):
uv run main.py
poetry β biroz eskiroq, keng tarqalgan boshqaruvchi:
poetry new mening-loyiham # tayyor struktura yaratadi
cd mening-loyiham
poetry add requests # bog'liqlik qo'shadi
poetry install # hammasini o'rnatadi
poetry run python main.py # loyiha muhitida ishga tushiradi
Har ikkalasi ham lock-fayl (uv.lock yoki poetry.lock) yuritadi: bu aynan qaysi versiyalar o'rnatilganini belgilab qo'yadi β shunda jamoadagi hamma bir xil muhitni oladi (takrorlanuvchi build).
Nimani tanlash kerak? O'rganish bosqichida
pip+venvyetarli β ostidagi mexanizmni tushunasan. Loyiha o'sgandauvga o'tish tavsiya etiladi: tez, sodda vapyproject.tomlstandartiga to'liq mos. Bu kitobda bizpip+venvni ishlatamiz, lekin ish joyidauvni uchratishing ehtimoli yuqori.
6.11 Semantik versiyalash (SemVer)¶
Kutubxona versiyalari tasodifiy raqamlar emas. Eng keng tarqalgan kelishuv β semantik versiyalash (SemVer): MAJOR.MINOR.PATCH (masalan 2.4.1). Har bir qism aniq narsani anglatadi:
| Qism | Misol | Qachon oshadi | Mosligi |
|---|---|---|---|
| MAJOR | 2.4.1 |
Eski kodni buzadigan o'zgarish | mos kelmaydi |
| MINOR | 2.4.1 |
Yangi imkoniyat, orqaga mos | mos keladi |
| PATCH | 2.4.1 |
Xato tuzatish, orqaga mos | mos keladi |
Shuning uchun pyproject.toml da requests>=2.31 yozganingda: "2.31 yoki undan yuqori istalgan minor/patch ishlaydi, lekin 3.0 (major) β ehtiyot bo'l, u buzishi mumkin" degan ma'noni bildirasan. ^2.31 (caret) belgisi esa "2.x.x ichida istalgani, lekin 3.0 emas" deydi.
Versiyalarni dasturda taqqoslash uchun ularni sonlar uchligiga aylantirish kifoya. Buni dataclass bilan toza qilamiz (Python 3.13 uslubi β frozen=True o'zgarmas qiladi, order=True esa <, > taqqoslashlarini avtomatik beradi):
from dataclasses import dataclass
@dataclass(frozen=True, order=True)
class Versiya:
major: int
minor: int
patch: int
@classmethod
def matndan(cls, s: str) -> "Versiya":
major, minor, patch = (int(qism) for qism in s.split("."))
return cls(major, minor, patch)
def __str__(self) -> str:
return f"{self.major}.{self.minor}.{self.patch}"
a = Versiya.matndan("2.3.1")
b = Versiya.matndan("2.4.0")
print(a < b) # True β minor oshdi, b yangiroq
print(max(a, b)) # 2.4.0
def mos_keladimi(talab: Versiya, mavjud: Versiya) -> bool:
# ^2.3.1 mantiqi: major bir xil bo'lsin va mavjud >= talab
return mavjud.major == talab.major and mavjud >= talab
print(mos_keladimi(Versiya.matndan("2.3.1"), Versiya.matndan("2.9.0"))) # True
print(mos_keladimi(Versiya.matndan("2.3.1"), Versiya.matndan("3.0.0"))) # False
Senga nima beradi? O'z kutubxonangni nashr qilganda: xato tuzatsang PATCH oshir, yangi funksiya qo'shsang MINOR, eski interfeysni buzsang MAJOR. Shunda ishlatuvchilar versiya raqamiga qarab xavfsiz yangilay oladi.
pyproject.tomldagiversion = "1.0.0"aynan shu qoidaga bo'ysunadi.
6.12 Muhit o'zgaruvchilari β os.environ va .env¶
Maxfiy ma'lumot (API kalitlari, parollar, ulanish manzillari) va sozlamalarni koddan tashqarida saqlash kerak. Birinchidan β xavfsizlik (kalitni GitHub'ga yuklab qo'ymaslik uchun), ikkinchidan β moslashuvchanlik (bir kod, lekin dev/prod muhitda har xil sozlama). Standart yo'l β muhit o'zgaruvchilari.
os moduli orqali ularni o'qiysan:
import os
# 1-usul (xavfsiz): yo'q bo'lsa standart qiymat qaytaradi
api_kalit = os.getenv("API_KEY", "kalit-yoq")
rejim = os.getenv("APP_REJIM", "dev")
print(api_kalit, rejim)
# 2-usul: os.environ lug'at kabi ishlaydi (yo'q bo'lsa KeyError)
print(os.environ.get("PATH")) # tizim yo'li (har doim bor)
# Dasturdan o'zgaruvchi o'rnatish (faqat shu jarayon uchun):
os.environ["APP_REJIM"] = "prod"
Sozlamani match/case bilan tahlil qilish β toza va o'qiladigan (Python 3.10+ imkoniyati):
import os
def rejim_tavsifi(rejim: str) -> str:
match rejim.lower():
case "dev" | "development":
return "Ishlab chiqish rejimi"
case "prod" | "production":
return "Ishlab chiqarish rejimi"
case "test":
return "Test rejimi"
case _:
return "Noma'lum rejim"
print(rejim_tavsifi(os.getenv("APP_REJIM", "dev"))) # Ishlab chiqish rejimi
.env fayli. Har safar terminalda o'zgaruvchi o'rnatish noqulay. Odatda loyiha ildizida .env faylida saqlanadi:
Bu faylni hech qachon Git'ga yuklama β .gitignore ga .env qatorini qo'sh (ichida maxfiy kalitlar bor). Odatda .env.example (qiymatlarsiz namuna) ni esa Git'ga qo'yib, boshqalar nimani to'ldirish kerakligini biladi.
Amaliyotda .env ni python-dotenv kutubxonasi bilan o'qiydilar (pip install python-dotenv). Lekin mexanizmni tushunish uchun uni o'zimiz qo'lda yozib ko'ramiz β .env shunchaki KALIT=qiymat qatorlari:
import os
from pathlib import Path
def env_yukla(fayl: str = ".env") -> None:
""".env faylidagi KALIT=qiymat qatorlarini os.environ ga yuklaydi."""
yol = Path(fayl)
if not yol.exists():
return
for qator in yol.read_text(encoding="utf-8").splitlines():
qator = qator.strip()
if not qator or qator.startswith("#"): # bo'sh va izoh qatorlarini o'tkaz
continue
kalit, _, qiymat = qator.partition("=")
os.environ.setdefault(kalit.strip(), qiymat.strip())
env_yukla()
print(os.getenv("API_KEY", "yoq")) # 12345 (.env dan)
print(os.getenv("DEBUG", "false")) # true
Qoida: kod β ochiq (GitHub'da), sozlama β yopiq (
.env, lokal). Hech qachon parol yoki kalitni to'g'ridan-to'g'ri kodga yozma.os.getenv("KALIT", standart)β har doim standart qiymatni ber, shunda o'zgaruvchi yo'q bo'lsa ham dastur qulamaydi.
βοΈ Masalalar (26 ta)¶
Ba'zi masalalar terminalda buyruq bajarishni talab qiladi. Modul yozish masalalarida ikkita fayl yaratib sina.
Oson (1β7):
mathmodulini import qilib, 144 ning kvadrat ildizini chiqar.randommodulidanrandintbilan 1β6 oralig'ida tasodifiy son chiqar (zar tashlash).from math import piqilib, radiusi 5 bo'lgan doira yuzasini hisobla.random.choicebilan ro'yxatdan tasodifiy element tanla.import random as rqilib,r.randintbilan 3 ta tasodifiy son chiqar.- Terminalda
pip listni ishga tushirib, o'rnatilgan kutubxonalarni ko'r (kod emas, terminal). math.ceilvamath.floorbilan4.3ni yuqoriga va pastga yaxlitla.
O'rta (8β14):
hisob.pymoduli yarat (qosh,ayirfunksiyalari bilan), unimain.pydan import qilib ishlat.salom.pymodul yarat (salomlash(ism)funksiyasi), boshqa fayldanfrom salom import salomlashqilib chaqir.hisob.pygaif __name__ == "__main__":qo'shib, ichida test kodi yoz. Faylni to'g'ridan-to'g'ri ishga tushirib tekshir.random.shufflebilan[1,2,3,4,5]ro'yxatini aralashtir.datetimemodulidan foydalanib, bugungi sanani chiqar (datetime.date.today()).- Terminalda virtual muhit yarat (
python -m venv venv) va faollashtir. - Virtual muhitda biror kutubxona o'rnat (
pip install rich) vapip listbilan tekshir.
Murakkab (15β20):
- Ikkita modul yarat:
geometriya.py(doira_yuza,tortburchak_yuza) vamain.py(ularni import qilib ishlatadi). randombilan oddiy "son top" o'yini: kompyuter 1β100 oralig'ida son o'ylasin, foydalanuvchi topguncha "katta"/"kichik" deb yo'naltir.utils.pymoduli yarat: kamida 3 ta foydali funksiya (masalankatta_harf,teskari,unli_sanash),main.pydan hammasini ishlat.- Loyiha yarat: virtual muhit,
requirements.txt, vapip freezebilan uni to'ldir. randomvamathni birga ishlatib: 5 ta tasodifiy sonning kvadrat ildizlari yig'indisini hisobla.- Ikki moduldan iborat kichik loyiha:
bank.py(Hisobklassi β 5-moduldan) vamain.py(hisob yaratib, amallar bajaradi). Klassni modulga joylashtirib, import qilib ishlat.
Qo'shimcha (21β26) β paket, pyproject, muhit:
mypkg/paketi yarat:__init__.py,hisob.py(qosh,ayir) vamatn.py(teskari).__init__.pyda uchala funksiyani fasad sifatida ko'tarib,__all__belgila. Tashqimain.pydanfrom mypkg import qosh, teskariqilib ishlat.- 21-masaladagi paketga
geom/sub-paketini qo'sh (doira.pyichidayuza(r)).geom/__init__.pyda nisbiy import (from .doira import yuza) qilib, asosiy__init__.pydan ko'tar. - Kichik loyiha uchun
pyproject.tomlyoz (PEP 621):name,version,requires-python,dependencies(requests>=2.31) va[project.optional-dependencies]dagidev(pytest). Bu kod emas β TOML fayli. - Muhit o'zgaruvchisini o'qib chiqaruvchi funksiya yoz:
os.getenv("APP_REJIM", "dev")ni olib,match/casebilan "dev"/"prod"/"test" uchun mos tavsif qaytar. .envfaylini (KALIT=qiymatqatorlari) o'qibos.environga yuklovchienv_yukla()funksiyasini yoz (izoh va bo'sh qatorlarni o'tkazib).API_KEYni o'qib chiqar.- Versiya satrlarini (
["1.2.0", "1.10.0", "1.1.5"]) to'g'ri semantik tartibda sarala (string saralash xato beradi β sonlar uchligiga aylantir).
β Yechimlar¶
Ko'rsatish uchun ochish (1β20)
# 1
import math
print(math.sqrt(144)) # 12.0
# 2
import random
print(random.randint(1, 6))
# 3
from math import pi
print(pi * 5 ** 2) # 78.539...
# 4
import random
print(random.choice(["olma", "banan", "uzum"]))
# 5
import random as r
print(r.randint(1, 100), r.randint(1, 100), r.randint(1, 100))
# 6
# Terminalda: pip list
# 7
import math
print(math.ceil(4.3), math.floor(4.3)) # 5 4
# 8
# hisob.py:
# def qosh(a: int, b: int) -> int: return a + b
# def ayir(a: int, b: int) -> int: return a - b
# main.py:
import hisob
print(hisob.qosh(3, 5)) # 8
print(hisob.ayir(10, 4)) # 6
# 9
# salom.py:
# def salomlash(ism: str) -> None: print(f"Salom, {ism}!")
# main.py:
from salom import salomlash
salomlash("Aziz") # Salom, Aziz!
# 10
# hisob.py:
def qosh(a: int, b: int) -> int:
return a + b
if __name__ == "__main__":
print("Test:", qosh(2, 3)) # faqat 'python hisob.py' deganda chiqadi
# 11
import random
sonlar = [1, 2, 3, 4, 5]
random.shuffle(sonlar)
print(sonlar) # masalan [3, 1, 5, 2, 4]
# 12
import datetime
print(datetime.date.today()) # masalan 2026-06-11
# 13
# Terminalda:
# python -m venv venv
# source venv/bin/activate (Windows: venv\Scripts\activate)
# 14
# Terminalda (venv faol):
# pip install rich
# pip list
# 15
# geometriya.py:
# import math
# def doira_yuza(r: float) -> float: return math.pi * r * r
# def tortburchak_yuza(a: float, b: float) -> float: return a * b
# main.py:
import geometriya
print(geometriya.doira_yuza(5))
print(geometriya.tortburchak_yuza(4, 6))
# 16
import random
maxfiy = random.randint(1, 100)
while True:
taxmin = int(input("Taxminingiz (1-100): "))
if taxmin == maxfiy:
print("Topdingiz!")
break
elif taxmin < maxfiy:
print("Kattaroq son")
else:
print("Kichikroq son")
# 17
# utils.py:
# def katta_harf(s: str) -> str: return s.upper()
# def teskari(s: str) -> str: return s[::-1]
# def unli_sanash(s: str) -> int: return sum(1 for h in s.lower() if h in "aeiou")
# main.py:
from utils import katta_harf, teskari, unli_sanash
print(katta_harf("salom")) # SALOM
print(teskari("salom")) # molas
print(unli_sanash("salom")) # 2
# 18
# Terminalda:
# python -m venv venv
# source venv/bin/activate
# pip install requests
# pip freeze > requirements.txt
# 19
import random, math
sonlar = [random.randint(1, 100) for _ in range(5)]
print(sum(math.sqrt(s) for s in sonlar))
# 20
# bank.py:
# class Hisob:
# def __init__(self, balans: int = 0) -> None: self.balans = balans
# def qoy(self, s: int) -> None: self.balans += s
# def yech(self, s: int) -> None: self.balans -= s
# main.py:
from bank import Hisob
h = Hisob(1000)
h.qoy(500)
h.yech(200)
print(h.balans) # 1300
Masala 21
# mypkg/hisob.py:
# def qosh(a: int, b: int) -> int: return a + b
# def ayir(a: int, b: int) -> int: return a - b
#
# mypkg/matn.py:
# def teskari(s: str) -> str: return s[::-1]
#
# mypkg/__init__.py:
from .hisob import qosh, ayir
from .matn import teskari
__all__ = ["qosh", "ayir", "teskari"]
# main.py (mypkg yonida):
from mypkg import qosh, teskari
print(qosh(3, 5)) # 8
print(teskari("salom")) # molas
Masala 22
# mypkg/geom/doira.py:
# import math
# def yuza(r: float) -> float: return math.pi * r * r
#
# mypkg/geom/__init__.py:
from .doira import yuza # "." = geom sub-paketi
__all__ = ["yuza"]
# mypkg/__init__.py (avvalgilarga qo'shimcha):
from .geom import yuza
# __all__ ga "yuza" ni ham qo'sh: __all__ = ["qosh", "ayir", "teskari", "yuza"]
# main.py:
from mypkg.geom import yuza
print(round(yuza(2), 3)) # 12.566
Masala 23
Masala 24
import os
def rejim_tavsifi() -> str:
rejim = os.getenv("APP_REJIM", "dev")
match rejim.lower():
case "dev" | "development":
return "Ishlab chiqish rejimi"
case "prod" | "production":
return "Ishlab chiqarish rejimi"
case "test":
return "Test rejimi"
case _:
return f"Noma'lum rejim: {rejim}"
print(rejim_tavsifi()) # Ishlab chiqish rejimi (standart)
os.environ["APP_REJIM"] = "prod"
print(rejim_tavsifi()) # Ishlab chiqarish rejimi
Masala 25
import os
from pathlib import Path
def env_yukla(fayl: str = ".env") -> None:
yol = Path(fayl)
if not yol.exists():
return
for qator in yol.read_text(encoding="utf-8").splitlines():
qator = qator.strip()
if not qator or qator.startswith("#"):
continue
kalit, _, qiymat = qator.partition("=")
os.environ.setdefault(kalit.strip(), qiymat.strip())
# Sinov uchun .env yaratamiz:
Path(".env").write_text("# sozlama\nAPI_KEY=12345\nDEBUG=true\n", encoding="utf-8")
env_yukla()
print(os.getenv("API_KEY")) # 12345
print(os.getenv("DEBUG")) # true
Masala 26
versiyalar = ["1.2.0", "1.10.0", "1.1.5"]
# Xato (string saralash): "1.10.0" < "1.2.0" deb hisoblaydi!
print(sorted(versiyalar)) # ['1.1.5', '1.10.0', '1.2.0'] -- noto'g'ri
# To'g'ri: har versiyani sonlar uchligiga aylantirib sarala
def kalit(v: str) -> tuple[int, int, int]:
major, minor, patch = (int(x) for x in v.split("."))
return (major, minor, patch)
print(sorted(versiyalar, key=kalit)) # ['1.1.5', '1.2.0', '1.10.0'] -- to'g'ri
β OOP | Boshlovchilar README β | Keyingi: Xatolarni boshqarish β