Ачааллж байна...
Өмнөх хичээлд бид модуль — зүгээр л .py файл — гэж юу болохыг сурсан. Хоёр файл болгож хуваасан: api.py ба main.py.
Тэр нь ажилласан. Гэвч одоо асуулт: хэрэв төсөл ТОМРОВОЛ яах вэ?
Төсөөлөөд үз, таны хавтас ийм болов:
tsag-agaar/
├── venv/
├── main.py
├── api.py
├── geocode_api.py
├── weather_api.py
├── display.py
├── report.py
├── config.py
├── cache.py
├── models.py
├── validators.py
├── formatters.py
├── file_storage.py
├── json_storage.py
├── csv_export.py
├── utils.py
└── requirements.txtАрван таван файл, бүгд НЭГ ХАВТАСТ.
Тэр нь ажиллана. Гэвч дахин л асуудал: файл хайхад хэцүү. Аль нь API-тай холбоотой вэ? Аль нь хадгалалттай? Аль нь харуулахтай?
Шийдэл: файлуудыг ХАВТАСНУУДАД ангилах.
Тэр хавтаснуудыг PACKAGE гэж нэрлэдэг.
Номын сангийн зүйрлэлийг ашиглая (Бүлэг 9-ийн guided build-ыг санаж байна уу).
Жижиг номын сан — бүх ном НЭГ тавиур дээр. Хорин ном бол асуудалгүй.
Том номын сан — мянган ном. Нэг тавиур дээр байлгаж болохгүй.
Тиймээс тэднийг ХЭСГҮҮДЭД ангилна:
Уран зохиол хэсэг
Түүх хэсэг
Шинжлэх ухаан хэсэг
Хэсэг бүр дотор дахин дэд хэсгүүд байж болно: "Шинжлэх ухаан → Физик → Квант механик."
Одоо та номоо ОЛОХ гэж бүх санг ухах шаардлагагүй. Та зөв хэсэг рүү очно.
Package бол яг тэр хэсэг юм.
Модуль = ном (нэг файл)
Package = хэсэг (хавтас, дотор нь олон файл)
Тодорхойлолт нь маш энгийн:
Package бол Python модулиудыг агуулсан ХАВТАС юм.
Тэр л болоо.
(Хуучин Python-д тэр хавтас дотор __init__.py гэсэн файл ЗААВАЛ байх ёстой байсан. Одоо тэр нь ЗААВАЛ БИШ — гэхдээ түүний тухай доор ярина.)
Бүлэг 12.1-ийн цаг агаарын программыг package болгож зохион байгуулъя.
Хавтасны бүтэц:
tsag-agaar/
├── venv/
├── main.py
├── requirements.txt
└── tsag_agaar/ ← PACKAGE (хавтас)
├── __init__.py
├── api.py
└── display.pyАнзаараарай: tsag_agaar бол ХАВТАС, файл БИШ.
Одоо файлуудыг бичье.
tsag_agaar/api.py — интернэттэй ярина
python
# tsag_agaar/api.py
import requests
FORECAST_URL = "https://api.open-meteo.com/v1/forecast"
GEOCODE_URL = "https://geocoding-api.open-meteo.com/v1/search"
TIMEOUT = 10
def khot_khaikh(ner: str) -> dict | None:
parametruud = {"name": ner, "count": 1, "language": "en"}
try:
hariult = requests.get(GEOCODE_URL, params=parametruud, timeout=TIMEOUT)
hariult.raise_for_status()
uguudul = hariult.json()
except requests.exceptions.RequestException as alda:
print(f"Сүлжээний алдаа: {alda}")
return None
ur_dun = uguudul.get("results")
if not ur_dun:
return None
return ur_dun[0]
def tsag_agaar_avakh(lat: float, lon: float) -> dict | None:
parametruud = {
"latitude": lat,
"longitude": lon,
"current": "temperature_2m,wind_speed_10m",
"timezone": "auto",
}
try:
hariult = requests.get(FORECAST_URL, params=parametruud, timeout=TIMEOUT)
hariult.raise_for_status()
return hariult.json()
except requests.exceptions.RequestException as alda:
print(f"Сүлжээний алдаа: {alda}")
return Nonetsag_agaar/display.py — харуулна
python
# tsag_agaar/display.py
def khot_kheveleкh(khot: dict, tsag_agaar: dict) -> None:
odoo = tsag_agaar["current"]
print()
print("=" * 44)
print(f"{khot['name'].upper()}, {khot.get('country', '')}")
print("=" * 44)
print(f"Координат: {khot['latitude']}, {khot['longitude']}")
print(f"Цаг: {odoo['time']}")
print(f"Температур: {odoo['temperature_2m']}°C")
print(f"Салхи: {odoo['wind_speed_10m']} км/ц")
print("=" * 44)
def alda_kheveleкh(mesej: str) -> None:
print(f"\nАлдаа: {mesej}")tsag_agaar/__init__.py — одоохондоо ХООСОН
python
# tsag_agaar/__init__.pymain.py — package -ыг ашиглана
python
# main.py
from tsag_agaar.api import khot_khaikh, tsag_agaar_avakh
from tsag_agaar.display import khot_kheveleкh, alda_kheveleкh
def gol() -> None:
ner = input("Хотын нэр (англиар): ").strip()
if not ner:
alda_kheveleкh("Нэр хоосон байна.")
return
khot = khot_khaikh(ner)
if khot is None:
alda_kheveleкh(f"'{ner}' гэсэн хот олдсонгүй.")
return
tsag_agaar = tsag_agaar_avakh(khot["latitude"], khot["longitude"])
if tsag_agaar is None:
alda_kheveleкh("Цаг агаарын мэдээлэл авч чадсангүй.")
return
khot_kheveleкh(khot, tsag_agaar)
gol()Ажиллуулна уу:
powershell
python main.pyХотын нэр (англиар): Ulaanbaatar
============================================
ULAANBAATAR, Mongolia
============================================
Координат: 47.90771, 106.88324
Цаг: 2026-07-13T22:00
Температур: 18.7°C
Салхи: 8.3 км/ц
============================================Package ажиллалаа.
Хамгийн чухал мөрийг задалъя:
python
from tsag_agaar.api import khot_khaikh, tsag_agaar_avakhХэсэг хэсгээр нь:
tsag_agaar — PACKAGE (хавтасны нэр)
. — "доторх"
api — MODULE (файлын нэр, .py -гүй)
import khot_khaikh — тэр модулиас функц ав
Уншихдаа: "tsag_agaar package доторх api модулиас khot_khaikh -ыг ав."
Цэг нь "доторх" гэсэн утгатай. Тэр нь хавтасны бүтцийг дагана.
Гүн бүтэц ч бас ажиллана:
tsag_agaar/
├── __init__.py
├── api/
│ ├── __init__.py
│ ├── geocode.py
│ └── forecast.py
└── display.pypython
from tsag_agaar.api.geocode import khot_khaikh
from tsag_agaar.api.forecast import tsag_agaar_avakhЦэг бүр нэг давхарга гүн рүү.
Бусад бичлэг ч ажиллана:
python
import tsag_agaar.api
tsag_agaar.api.khot_khaikh("Ulaanbaatar") # урт!Эсвэл:
python
from tsag_agaar import api
api.khot_khaikh("Ulaanbaatar") # илүү тав тухтайПрактикт from package.module import функц нь хамгийн түгээмэл.
__init__.py — нууцлаг файлОдоо тэр файлын тухай ярья.
__init__.py гэж юу вэ?
Тэр нь PACKAGE ЭХЛЭХЭД АЖИЛЛАДАГ ФАЙЛ юм.
Санаж байна уу, Бүлэг 12.1-т бид "import хийхэд файл БҮХЭЛДЭЭ ажилладаг" гэж үзсэн? Package -д ч бас ижил зарчим:
import tsag_agaar гэж бичихэд Python нь tsag_agaar/__init__.py -г АЖИЛЛУУЛНА.
Ихэнх тохиолдолд тэр файл нь ХООСОН байдаг. Тэр нь бүрэн зөв.
Тэгвэл юуны төлөө байдаг вэ?
Хуучин шалтгаан (Python 3.3-аас өмнө): тэр файл байх нь "энэ хавтас бол PACKAGE" гэдгийг ЗАРЛАДАГ байсан. Түүнгүйгээр Python нь хавтсыг package гэж танихгүй байсан.
Одоо тэр шаардлага АРИЛСАН. __init__.py -гүй хавтас ч package болж чадна (түүнийг "namespace package" гэдэг).
Тэгвэл яагаад одоо ч ашигладаг вэ?
Шалтгаан 1: ТОДОРХОЙ БАЙДАЛ. __init__.py байвал — уншигч нь "энэ бол зориудаар үүсгэсэн package" гэж мэднэ. Түүнгүй бол — "магадгүй санамсаргүй хавтас."
Шалтгаан 2: import -ыг ХЯЛБАРЧЛАХ. Тэр нь хамгийн ашигтай хэрэглээ.
__init__.py -ийн ашигтай хэрэглээОдоохондоо main.py нь ийм байна:
python
from tsag_agaar.api import khot_khaikh, tsag_agaar_avakh
from tsag_agaar.display import khot_kheveleкh, alda_kheveleкhХоёр мөр, урт замууд.
__init__.py -г ашиглан түүнийг хялбарчилъя:
python
# tsag_agaar/__init__.py
from tsag_agaar.api import khot_khaikh, tsag_agaar_avakh
from tsag_agaar.display import khot_kheveleкh, alda_kheveleкhОдоо main.py:
python
# main.py
from tsag_agaar import (
khot_khaikh,
tsag_agaar_avakh,
khot_kheveleкh,
alda_kheveleкh,
)Нэг мөр, богино зам.
Юу болов?
__init__.py нь тэдгээр функцийг package-ийн ДЭЭД түвшинд "гаргаж" ирсэн. Одоо хэрэглэгч дотоод бүтцийг мэдэх шаардлагагүй.
Энэ бол ЧУХАЛ санаа. Package-ийн ХЭРЭГЛЭГЧ нь api.py ба display.py гэсэн файлууд байдгийг мэдэх шаардлагагүй. Тэр зөвхөн функцүүдийг л мэднэ.
Бүлэг 11.2-ын API-ийн зарчим дахин ажиллаж байна:
"API нь дотоод бүтцийг НУУНА. Та ХЭРХЭН ажилладгийг мэдэх ШААРДЛАГАГҮЙ."
__init__.py бол таны package-ийн ЦЭС.
Хэрэв та маргааш api.py -г geocode.py ба forecast.py болгож хуваавал — __init__.py -г л засна. Хэрэглэгчийн код ӨӨРЧЛӨГДӨХГҮЙ.
Одоо бодит, мэргэжлийн Python төсөл ЯМАР харагддагийг харъя.
myn-tosol/
├── venv/ ← НИКОГДА хуваалцахгүй (Бүлэг 1.3)
├── .gitignore ← юуг GitHub-д оруулахгүй вэ
├── README.md ← төслийн тайлбар
├── requirements.txt ← шаардлагууд (Бүлэг 1.3)
├── main.py ← эхлэх цэг
│
├── myn_tosol/ ← ҮНДСЭН PACKAGE
│ ├── __init__.py
│ ├── config.py ← тохиргоо, тогтмолууд
│ ├── models.py ← dataclass-ууд (Бүлэг 9)
│ │
│ ├── api/ ← дэд package
│ │ ├── __init__.py
│ │ ├── client.py ← requests-тэй ажиллана
│ │ └── errors.py ← алдааны class-ууд
│ │
│ ├── storage/ ← дэд package
│ │ ├── __init__.py
│ │ ├── json_store.py ← JSON хадгалалт (Бүлэг 6)
│ │ └── csv_export.py ← CSV экспорт (Бүлэг 6.3)
│ │
│ └── display/ ← дэд package
│ ├── __init__.py
│ ├── tables.py
│ └── reports.py
│
└── tests/ ← тестүүд
├── test_api.py
└── test_storage.pyХэдэн зүйлийг анзаараарай.
1. main.py нь ГАДНА байна. Тэр нь зөвхөн ЭХЛҮҮЛЭХ цэг. Богино, энгийн.
2. Бүх жинхэнэ код нь myn_tosol/ package дотор.
Яагаад? Учир нь ингэснээр таны кодыг ӨӨР төсөлд суулгаж болно. pip install myn-tosol гэж бичээд ашиглаж болно.
3. Дэд package -ууд нь ҮҮРГЭЭР ангилагдсан: api/, storage/, display/.
Бүлэг 6.5 ба 9.4-ийн "гурван давхарга" нь одоо ХАВТАСНУУД болов.
4. config.py — бүх тохиргоо НЭГ газарт: URL, timeout, файлын зам.
5. models.py — бүх dataclass НЭГ газарт.
6. tests/ — тестүүд тусдаа.
Энэ курс нь тест бичихийг заахгүй (тэр нь өөр бүтэн сэдэв), гэхдээ мэргэжлийн төсөлд тэдгээр нь ЗААВАЛ байдаг гэдгийг мэдэж байгаарай.
Одоо FastAPI төсөл ЯМАР харагддагийг харъя. Бүлэг 15-д та жижиг хувилбарыг бичнэ.
nomiin-san-api/
├── venv/
├── requirements.txt
├── main.py ← FastAPI app эхлэх цэг
│
└── app/
├── __init__.py
├── models.py ← Pydantic class-ууд (Бүлэг 9!)
├── database.py ← өгөгдөл хадгалах
│
└── routers/ ← endpoint-ууд
├── __init__.py
├── nomnuud.py ← @app.get("/nomnuud") гэх мэт
└── gishuud.py ← @app.get("/gishuud") гэх мэтТанил бүтэц үү?
models.py — Бүлэг 9-ийн dataclass/Pydantic class-ууд.
routers/ — Бүлэг 10.4-ийн decorator -ээр бүртгэгдсэн функцүүд.
Бүх зүйл нэгдэж байна.
config.py — тохиргоог төвлөрүүлэхПрактик зөвлөгөө: тогтмолуудыг НЭГ файлд төвлөрүүл.
python
# tsag_agaar/config.py
# Бүх тохиргоо, тогтмолууд
# API хаягууд
FORECAST_URL = "https://api.open-meteo.com/v1/forecast"
GEOCODE_URL = "https://geocoding-api.open-meteo.com/v1/search"
# Сүлжээ
TIMEOUT = 10
OROLDLOGO = 3
# Файлын зам
KESH_ZAM = "kesh.json"
# Харуулах
UURUG = 44Одоо api.py:
python
# tsag_agaar/api.py
import requests
from tsag_agaar.config import FORECAST_URL, GEOCODE_URL, TIMEOUT
def khot_khaikh(ner: str) -> dict | None:
...
hariult = requests.get(GEOCODE_URL, params=parametruud, timeout=TIMEOUT)
...Ашиг тус:
1. Нэг газарт. URL өөрчлөгдвөл — нэг мөр засна.
2. Хайхад амархан. "Timeout нь хэд вэ?" → config.py -г нээ.
3. Орчноос хамааран өөрчилж болно. Хөгжүүлэлт vs үйлдвэрлэл.
Бүлэг 6.5-ын ZAM = "zarlaga.json", Бүлэг 9.4-ийн ZAM = "nomiin_san.json" — тэдгээр нь энэ санааны эхлэл байсан.
Одоо нэг нарийн зүйл.
Absolute import (бүтэн зам):
python
from tsag_agaar.config import TIMEOUT
from tsag_agaar.api import khot_khaikhRelative import (харьцангуй зам):
python
from .config import TIMEOUT # НЭГ цэг = "энэ package дотор"
from ..models import Nom # ХОЁР цэг = "нэг давхарга дээш"Аль нь дээр вэ?
Absolute import нь ИЛҮҮ САЙН. Шалтгаан:
1. ТОД. from tsag_agaar.config import TIMEOUT — бүх зүйл тодорхой.from .config import TIMEOUT — "энэ" гэдэг нь хаана вэ? Файлын байрлалыг мэдэх хэрэгтэй.
2. ЗӨӨХӨД АМАРХАН. Файлыг өөр хавтас руу зөөвөл — relative import эвдэрнэ, absolute нь ажиллана.
3. Python-ы албан ёсны зөвлөмж (PEP 8) нь absolute -ыг илүүд үздэг.
Тиймээс энэ курс нь ЗӨВХӨН absolute import ашиглана.
Гэхдээ бусдын кодод relative import харах магадлалтай тул мэдэж байгаарай. . нь "энэ package", .. нь "эцэг package."
Нэг практик зүйл. Хэрэв та package доторх файлыг ШУУД ажиллуулах гэж оролдвол:
powershell
python tsag_agaar/api.pyTraceback (most recent call last):
File "tsag_agaar/api.py", line 5, in <module>
from tsag_agaar.config import FORECAST_URL, GEOCODE_URL, TIMEOUT
ModuleNotFoundError: No module named 'tsag_agaar'Гэнэтийн алдаа! tsag_agaar package нь тэнд байгаа шүү дээ.
Учир нь: та tsag_agaar/ хавтас ДОТРООС ажиллуулж байгаа тул Python нь тэр хавтсыг "одоогийн хавтас" гэж үзнэ. Тэгэхээр tsag_agaar package нь харагдахгүй.
Шийдэл 1: төслийн ҮНДСЭН хавтаснаас ажиллуул.
powershell
python main.py # ЗӨВШийдэл 2: -m тугтай ажиллуул.
powershell
python -m tsag_agaar.api # ЗӨВ-m нь "энэ модулийг package -ийн хэсэг гэж үзээд ажиллуул" гэсэн заавар.
Практик дүрэм: ҮРГЭЛЖ төслийн үндсэн хавтаснаас python main.py гэж ажиллуул.
Шударгаар хэлье: package нь ҮРГЭЛЖ хэрэгтэй БИШ.
Package БҮҮ үүсгэ:
Файл 2-5 ширхэг → зүгээр л нэг хавтаст байлга
Жижиг script, туршилт → нэг файл хангалттай
Package үүсгэ:
Файл 6-аас олон болвол
Файлууд нь ТОДОРХОЙ БҮЛГҮҮДЭД хуваагдаж байвол (API, хадгалалт, харуулах)
Кодоо ӨӨР төсөлд ашиглах бол
Хамтран ажиллаж байвал
Эрт оптимизаци бүү хий (Бүлэг 5.4-ийн сургамж). Энгийнээр эхэл, шаардлагатай бол зохион байгуул.
Хэрэв сонирхвол: дээрх tsag_agaar package-ыг өөрөө барьж, ажиллуулж үзээрэй. Дараа нь __init__.py -д import нэмээд, main.py -г богиносгож үзээрэй.
Дараа нь python tsag_agaar/api.py гэж ШУУД ажиллуулж, ModuleNotFoundError -ыг өөрийн нүдээр хараарай. Дараа нь python -m tsag_agaar.api гэж ажиллуулж, ажиллахыг нь хараарай.
Тэр туршилт нь package-ийн ажиллах зарчмыг бүрэн ойлгуулна.
Мөн хүсвэл: Бүлэг 9.4-ийн номын сангийн 400 мөрийн main.py -г package болгож хуваахыг оролдоод үзээрэй:
nomiin_san/
├── __init__.py
├── models.py ← Zuil, Nom, Setguul, DVD, Gishuun
├── san.py ← NomiinSan class
├── storage.py ← JSON хадгалах/ачаалах
└── display.py ← жагсаах, тайлан1. Package доторх файлыг шууд ажиллуулах
ModuleNotFoundError: No module named 'tsag_agaar'Төслийн ҮНДСЭН хавтаснаас python main.py гэж ажиллуул, эсвэл python -m package.module.
2. __init__.py -г мартах (хуучин Python)
Python 3.3+ дээр ажиллана. Гэхдээ тодорхой байдлын үүднээс ҮРГЭЛЖ нэм.
3. Дугуй import
python
# tsag_agaar/api.py
from tsag_agaar.display import khot_kheveleкh
# tsag_agaar/display.py
from tsag_agaar.api import khot_khaikhImportError: cannot import name ... (most likely due to a circular import)Бүлэг 12.1-ээс танил. Засвар: бүтцээ дахин бод. api.py нь display.py -г МЭДЭХ ЁСГҮЙ — салгалт эвдэрсэн байна.
4. Relative import -ыг main.py -д ашиглах
python
# main.py
from .tsag_agaar.api import khot_khaikhImportError: attempted relative import with no known parent packagemain.py нь package дотор БИШ тул relative import ажиллахгүй. Absolute ашигла.
5. __init__.py -д хэт олон зүйл хийх
python
# tsag_agaar/__init__.py
print("Package ачаалагдлаа") # import хийхэд АЖИЛЛАНА!
uguudul = achaalakh("kesh.json") # import хийхэд АЖИЛЛАНА!Бүлэг 12.1-ийн сургамж хэвээрээ: import нь файлыг АЖИЛЛУУЛДАГ.
__init__.py -д зөвхөн import бич. Ажил бүү хий.
6. Package-ийн нэрийг модулийнхтэй ижил болгох
tsag_agaar/
└── tsag_agaar.py ← будлиантай!from tsag_agaar.tsag_agaar import ... — уншихад аймшигтай. Тодорхой, өөр нэр өг.
Модуль = ФАЙЛ. Package = ХАВТАС (дотор нь модулиуд).
Import бичлэг: from package.module import функц. Цэг нь "доторх" гэсэн утгатай, хавтасны бүтцийг дагана.
Гүн бүтэц: from tsag_agaar.api.geocode import khot_khaikh — цэг бүр нэг давхарга.
__init__.py нь package эхлэхэд АЖИЛЛАДАГ файл. Ихэвчлэн ХООСОН байдаг.
Python 3.3+ дээр ЗААВАЛ БИШ, гэхдээ тодорхой байдлын үүднээс нэм.
Гол ашиг тус: import -ыг ХЯЛБАРЧЛАХ. Тэр нь package-ийн ЦЭС — дотоод бүтцийг нуудаг (Бүлэг 11.2-ын API зарчим).
__init__.py -д зөвхөн import бич, ажил бүү хий.
Мэргэжлийн бүтэц:
tosol/
├── main.py ← эхлэх цэг (богино!)
├── requirements.txt
└── tosol/ ← үндсэн package
├── __init__.py
├── config.py ← БҮХ тогтмол НЭГ газарт
├── models.py ← dataclass-ууд
├── api/ ← дэд package
├── storage/
└── display/Бүлэг 6.5 ба 9.4-ийн "гурван давхарга" нь одоо ХАВТАСНУУД болов.
config.py — URL, timeout, файлын зам бүгд нэг газарт. Өөрчлөхөд нэг мөр.
Absolute import (from tsag_agaar.config import TIMEOUT) нь relative (from .config import TIMEOUT) -ээс ДЭЭР: тод, зөөхөд амархан, PEP 8-ын зөвлөмж. Энэ курс зөвхөн absolute ашиглана.
Package доторх файлыг ШУУД ажиллуулж болохгүй → ModuleNotFoundError. Төслийн үндсэн хавтаснаас python main.py гэж ажиллуул.
Package нь ҮРГЭЛЖ хэрэгтэй БИШ. 2-5 файл → нэг хавтас хангалттай. 6+ файл, тодорхой бүлгүүд → package.
Дараагийн хичээлд бид эцэст нь if __name__ == "__main__": гэсэн нууцлаг мөрийг тайлна.
Бүлэг 12.1-т бид асуудлыг харсан: import хийхэд файл БҮХЭЛДЭЭ ажилладаг тул модуль дотор чөлөөт код байвал гэнэтийн зүйл болдог. Тэр мөр нь тэр асуудлыг БҮРМӨСӨН шийднэ.
Мөн та түүнийг бараг БҮХ мэргэжлийн Python файлын төгсгөлд харах болно — одоо та яагаад гэдгийг мэдэх болно.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.