Ачааллж байна...
Бүлэг 4 дуусч байна. Та type hint гэж юу болох (Хичээл 1), үндсэн бичлэгүүд (Хичээл 2), None -тэй хэрхэн ажиллах (Хичээл 3) — бүгдийг үзсэн. Одоо тэдгээрийг НЭГ ЗУРШИЛ болгон нэгтгэх цаг болжээ.
Тэр зуршил бол: функц бүрийг БҮРЭН hint-лэх. Параметр бүр төрөлтэй, буцаах утга нь сумтай. Хагас биш, бүрэн.
Мөн би энэ хичээлд албан ёсоор нэг зүйлийг зарлана: энэ хичээлээс эхлэн, курсийн төгсгөл хүртэл, бүх код бүрэн hint-тэй байх болно. Бүлэг 5-ын tuple, Бүлэг 6-ын JSON, Бүлэг 9-ийн dataclass, Бүлэг 12-ын цаг агаарын программ, Бүлэг 15-ын FastAPI capstone — бүгд. Энэ бол мэргэжлийн стандарт бөгөөд бид түүнийг эндээс эхлүүлж, дадал болгоно.
Хэрэв энэ нь эхэндээ ядаргаатай санагдвал — тэр нь хэвийн. Гурав дөрвөн хичээлийн дараа та hint-гүй код харахад эвгүй санагдаж эхлэх болно. Тэр мөч ирэхэд та мэргэжлийн Python программист болж эхэлсэн гэсэн үг.
Функцийн гарчгийг гэрээ гэж бодоорой.
Гэрээ гэдэг нь хоёр талын хооронд байгуулагддаг. Нэг тал нь функцийг БИЧСЭН хүн, нөгөө тал нь функцийг ДУУДАХ хүн (тэр нь та өөрөө хэдэн сарын дараа байж болно).
Бүрэн hint-тэй гарчиг нь ийм гэрээ юм:
python
def khaikh(devter: dict[str, str], ner: str) -> str | None:Гэрээний нөхцөлүүд:
"Та надад ХОЁР зүйл өгөх ёстой."
"Эхнийх нь: key нь string, value нь string байдаг dictionary."
"Хоёр дахь нь: string."
"Хариуд нь би string ӨГНӨ, ЭСВЭЛ юу ч биш өгнө. Тиймээс шалгаарай."
Hint-гүй гарчиг нь ямар ч нөхцөлгүй гэрээ:
python
def khaikh(devter, ner):"Надад хоёр зүйл өг. Ямар зүйл вэ? Мэдэхгүй. Би юу буцаах вэ? Тэр ч бас нууц."
Ямар гэрээнд гарын үсэг зурахыг та өөрөө сонго.
Бүрэн hint-тэй функц нь гурван шаардлагыг хангана.
1. Параметр бүр төрөлтэй.
python
def f(a: int, b: str, c: list[int]) -> ...:Нэг ч параметр хоосон үлдэхгүй. Хэрэв гурван параметрийн хоёр нь л hint-тэй бол функц хагас гэрээтэй — тэр нь бүрэн гэрээгүйгээс төдийлөн дээрдэхгүй.
2. Буцаах утга сумтай.
python
def f(...) -> int:
def f(...) -> str | None:
def f(...) -> None:
def f(...) -> list[dict[str, int]]:-> None -ыг мартаж болохгүй. Юу ч буцаадаггүй функц ч гэсэн ТЭР БАРИМТЫГ зарлах ёстой. "Энэ функц зөвхөн үйлдэл хийдэг, утга буцаадаггүй" гэдэг нь чухал мэдээлэл.
3. Default утгатай параметрүүд ч мөн hint-тэй.
python
def f(ner: str, hemjee: int = 5, tugeemel: bool = False) -> None:Дарааллыг анзаараарай: нэр, цэгтэй таслал, төрөл, тэнцүү тэмдэг, default утга. Тэр дараалал хатуу.
Мөн PEP 8 стандартын нарийвчлал: hint-тэй default утгын тэнцүү тэмдгийн орчим ЗАЙ ТАВЬДАГ, hint-гүй бол ТАВЬДАГГҮЙ:
python
def f(hemjee: int = 5) -> None: # hint-тэй — зайтай
def f(hemjee=5) -> None: # hint-гүй — зайгүйЭнэ бол жижиг нарийвчлал, гэхдээ мэргэжлийн код ингэж бичигддэг.
Курс 1-ийн харилцагчийн дэвтрийн кодыг сэргээе. Энэ бол таны өөрийн бичсэн код байсан.
Өмнө нь (Курс 1):
python
def kharilagch_nemekh(devter, ner, utas):
devter[ner] = utas
return devter
def kharilagch_khaikh(devter, ner):
return devter.get(ner)
def kharilagch_ustgakh(devter, ner):
if ner in devter:
del devter[ner]
return True
return False
def buk_khevlekh(devter):
for ner, utas in devter.items():
print(f"{ner}: {utas}")Одоо (бүрэн hint-тэй):
python
def kharilagch_nemekh(
devter: dict[str, str], ner: str, utas: str
) -> dict[str, str]:
devter[ner] = utas
return devter
def kharilagch_khaikh(devter: dict[str, str], ner: str) -> str | None:
return devter.get(ner)
def kharilagch_ustgakh(devter: dict[str, str], ner: str) -> bool:
if ner in devter:
del devter[ner]
return True
return False
def buk_khevlekh(devter: dict[str, str]) -> None:
for ner, utas in devter.items():
print(f"{ner}: {utas}")Дөрвөн функцийн гарчгийг нэг нэгээр нь уншъя.
kharilagch_nemekh(devter: dict[str, str], ner: str, utas: str) -> dict[str, str] — "дэвтэр, нэр, утас ав; дэвтэр буцаа." Гурван параметр, гурвуулаа тодорхой. Буцаах нь ижил төрлийн dictionary.
kharilagch_khaikh(devter: dict[str, str], ner: str) -> str | None — "дэвтэр, нэр ав; утас БУЮУ юу ч биш буцаа." Энэ | None нь дуудагчид "шалгаарай" гэж хэлж байна. .get() нь None буцаадаг тул hint нь үнэн.
kharilagch_ustgakh(devter: dict[str, str], ner: str) -> bool — "дэвтэр, нэр ав; амжилттай эсэхийг үнэн/худал байдлаар буцаа." -> bool нь маш чухал: дуудагч энэ функцийн үр дүнг if дотор шалгах ёстой гэдгийг ойлгож байна.
buk_khevlekh(devter: dict[str, str]) -> None — "дэвтэр ав; юу ч буцаахгүй." -> None нь "энэ функцийн үр дүнг хувьсагчид олгох нь утгагүй" гэж хэлж байна.
Анзаараарай: функцийн БИЕ огт өөрчлөгдөөгүй. Бид ганц ч мөр логик өөрчлөөгүй. Зөвхөн гарчгийг л баяжуулсан. Type hint нь программын ажиллагаанд ямар ч нөлөө үзүүлдэггүй гэдгийг санаж байгаа байх — энэ бол түүний практик нотолгоо.
Дээрх эхний функц хоёр мөр болсныг анзаарсан байх:
python
def kharilagch_nemekh(
devter: dict[str, str], ner: str, utas: str
) -> dict[str, str]:Яагаад ингэв? Учир нь нэг мөрөнд бичвэл хэт урт болно. Мэргэжлийн Python стандарт (PEP 8) нь мөрийг 79 тэмдэгтээс богино байлгахыг зөвлөдөг (олон төсөл 88 эсвэл 100-ыг зөвшөөрдөг).
Урт гарчиг бичих хоёр арга бий.
Арга 1 — параметрүүдийг нэг мөрөнд, хаалтыг тусад нь:
python
def kharilagch_nemekh(
devter: dict[str, str], ner: str, utas: str
) -> dict[str, str]:Арга 2 — параметр бүрийг өөрийн мөрөнд (параметр олон бол илүү тод):
python
def zarlaga_nemekh(
zarlaguud: list[dict[str, str | int]],
ner: str,
dun: int,
angilal: str = "бусад",
) -> list[dict[str, str | int]]:
...Хоёр дахь аргад сүүлчийн параметрийн ард ч гэсэн таслал байгааг анзаараарай (angilal: str = "бусад",). Түүнийг trailing comma гэж нэрлэдэг бөгөөд тэр нь ирээдүйд шинэ параметр нэмэхэд нэг мөр л өөрчлөгддөг тул мэргэжлийн зуршил юм.
Аль аргыг ч ашиглаж болно. Ерөнхий дүрэм: параметр гурав хүртэл бол Арга 1, түүнээс олон бол Арга 2.
Одоо Түвшин 1-ийн guided build руу буцаж, түүнийг бүрэн hint-лэе. Энэ бол таны өөрийн бичсэн бодит программ.
python
# main.py
# Текст статистикийн хэрэгсэл — бүрэн type hint-тэй
def fail_unshikh(zam: str) -> str:
with open(zam, "r", encoding="utf-8") as f:
return f.read()
def ug_tseverlekh(ug: str) -> str:
ug = ug.lower()
temdegtuud = ".,!?:;()\"'—-"
for temdegt in temdegtuud:
ug = ug.replace(temdegt, "")
return ug
def ugend_salgakh(tekst: str) -> list[str]:
tureg_ugs = tekst.split()
ugs: list[str] = []
for ug in tureg_ugs:
tseverkhen = ug_tseverlekh(ug)
if tseverkhen:
ugs.append(tseverkhen)
return ugs
def davtamj_toolokh(ugs: list[str]) -> dict[str, int]:
toolch: dict[str, int] = {}
for ug in ugs:
toolch[ug] = toolch.get(ug, 0) + 1
return toolch
def khamgiin_olon(
toolch: dict[str, int], hemjee: int = 5
) -> list[tuple[str, int]]:
hosud = list(toolch.items())
erembelsen = sorted(hosud, key=lambda hos: hos[1], reverse=True)
return erembelsen[:hemjee]
def khamgiin_urt(ugs: list[str]) -> str:
return max(ugs, key=len)
def mur_toolokh(tekst: str) -> int:
murууd = tekst.split("\n")
return len([mur for mur in murууd if mur.strip()])
def tailan_khevlekh(zam: str, davtamjiin_too: int = 5) -> None:
tekst = fail_unshikh(zam)
ugs = ugend_salgakh(tekst)
if not ugs:
print("Файл хоосон байна.")
return
toolch = davtamj_toolokh(ugs)
olon = khamgiin_olon(toolch, hemjee=davtamjiin_too)
print("=" * 40)
print(f"ФАЙЛ: {zam}")
print("=" * 40)
print(f"Мөрийн тоо: {mur_toolokh(tekst)}")
print(f"Нийт үг: {len(ugs)}")
print(f"Өвөрмөц үг: {len(set(ugs))}")
print(f"Хамгийн урт үг: {khamgiin_urt(ugs)}")
print()
print(f"Хамгийн олон давтагдсан {davtamjiin_too} үг:")
for baiirlal, (ug, too) in enumerate(olon, start=1):
print(f" {baiirlal}. {ug} — {too} удаа")
print("=" * 40)
tailan_khevlekh("tekst.txt")Хэдэн зүйлийг тодотгоё.
ugs: list[str] = [] — энэ бол Хичээл 4.2-т ярьсан "хоосон цуглуулгад hint хэрэгтэй" тохиолдол. Хэрэв зөвхөн ugs = [] гэж бичвэл editor нь юу орох гэж байгааг мэдэхгүй. Hint нэмснээр ugs.append(123) гэж бичихэд editor нь анхааруулна.
toolch: dict[str, int] = {} — ижил шалтгаан.
-> list[tuple[str, int]] — энэ бол хамгийн сонирхолтой hint. khamgiin_olon нь юу буцаадаг вэ? toolch.items() -ээс гарсан хосуудыг эрэмбэлж, зүсэж буцаадаг. Тэдгээр хос нь tuple бөгөөд тус бүр нь string (үг) ба int (тоо) агуулна. Тэгэхээр tuple[str, int]. Тэдгээр tuple-үүдийн жагсаалт → list[tuple[str, int]].
Энэ hint нь ЯГ ТИЙМ ЯГААДЫГ тайлбарлаж байна: яагаад for baiirlal, (ug, too) in enumerate(olon, start=1): гэсэн мөрөнд хоёр давхар unpacking хийж байгааг. Hint нь бүтцийг тод харуулсан.
hemjee: int = 5 — default утгатай параметр, hint-тэй, тэнцүү тэмдгийн орчим зайтай.
-> None нь tailan_khevlekh дээр — тэр функц зөвхөн хэвлэдэг.
Одоо type hint-ийн жинхэнэ өгөөжийг харуулъя. Дээрх кодыг VS Code дээр нээгээд, khamgiin_urt функцийг ажиглаарай:
python
def khamgiin_urt(ugs: list[str]) -> str:
return max(ugs, key=len)Энэ hint нь -> str гэж амлаж байна. Гэвч санаж байна уу, max нь ХООСОН жагсаалт дээр алдаа гаргадаг? Тэгэхээр энэ функц нь заримдаа огт буцахгүй — унана.
Hint нь тэр асуудлыг ИЛЭРХИЙЛЭХГҮЙ. -> str гэдэг нь "буцаавал string байна" гэсэн үг, "заавал буцаана" гэсэн үг биш. Alдаа гаргах нь өөр асуудал.
Гэхдээ энд илүү сонирхолтой зүйл байна. Хэрэв бид функцийг ингэж бичсэн бол:
python
def khamgiin_urt(ugs: list[str]) -> str | None:
if not ugs:
return None
return max(ugs, key=len)Одоо гарчиг нь бүх үнэнийг хэлж байна: "жагсаалт хоосон байж болно, тэр үед би юу ч буцаахгүй." Дуудагч шалгах ёстой гэдгийг мэдэж байна.
Аль хувилбар зөв бэ? Энэ бол ДИЗАЙНЫ шийдвэр, hint-ийн асуудал биш. Хоёр зөв хандлага бий:
Хандлага 1 — None буцаах: функц эвлэгээр "юу ч алга" гэж хэлнэ. Дуудагч шалгана.
Хандлага 2 — алдаа гаргах: функц "энэ хоосон жагсаалт өгөх нь БУРУУ, ингэж дуудаж болохгүй" гэж чанга дуугарна. Бүлэг 13-т raise -ийг үзэхэд бид энэ хандлагыг гүнзгий авч үзнэ.
Бидний программд tailan_khevlekh нь if not ugs: return гэж аль хэдийн шалгаж байгаа тул khamgiin_urt нь хэзээ ч хоосон жагсаалт хүлээж авахгүй. Тиймээс -> str нь энэ контекстэд зөв.
Гол сургамж: hint бичих явц нь таныг өөрийн кодын талаар БОДОХОД хүргэдэг. "Энэ функц заримдаа None буцаадаг уу?" гэсэн асуулт нь та hint бичихгүй бол хэзээ ч төрөхгүй. Тэр асуулт нь өөрөө үнэ цэнэтэй — hint нь зөвхөн баримт бичиг биш, бодох хэрэгсэл юм.
Заримдаа жинхэнэ өгөгдөл нь цэвэрхэн нэг төрөлтэй байдаггүй. Жишээ нь зарлагын бүртгэл (Бүлэг 6-ийн guided build):
python
zarlaga = {"ner": "Ном", "dun": 15000, "angilal": "боловсрол"}Энэ dictionary-ийн value-ууд нь ХОЛИМОГ: хоёр нь string, нэг нь int. Hint нь юу байх вэ?
python
zarlaga: dict[str, str | int] = {"ner": "Ном", "dun": 15000, "angilal": "боловсрол"}dict[str, str | int] — "key нь string, value нь string ЭСВЭЛ бүхэл тоо."
Энэ ажиллана, гэхдээ шударгаар хэлье: энэ бол муухай hint. Тэр нь "value нь string эсвэл тоо" гэж хэлж байгаа ч ЯМАР key ЯМАР төрөлтэй болохыг хэлээгүй. Кодыг уншиж байгаа хүн zarlaga["dun"] нь тоо гэдгийг мэдэхгүй.
Мөн editor нь тусалж чадахгүй:
python
niit = zarlaga["dun"] + 100Editor нь zarlaga["dun"] нь str | int гэж үзнэ. String дээр + 100 хийж болохгүй тул анхааруулна — хэдийгээр бид тэр нь үргэлж тоо байх гэдгийг мэдэж байгаа ч.
Энэ бол dataclass хэрэгтэй байгаагийн шинж. Бүлэг 9-д та ингэж бичиж чадна:
python
@dataclass
class Zarlaga:
ner: str
dun: int
angilal: strДараа нь hint нь list[Zarlaga] болно — тод, нарийн, editor нь бүрэн тусална. Одоохондоо энэ мэдээллийг зөвхөн санаж яваарай: hint нь муухай болж эхэлбэл, тэр нь илүү сайн бүтэц хэрэгтэй байгаагийн дохио.
Бүлэг 6-ийн guided build-д бид dict[str, str | int] -ийг ашиглана (учир нь dataclass-ыг хараахан үзээгүй), гэхдээ Бүлэг 9-д ижил кодыг dataclass-аар дахин бичиж, ялгааг харна. Тэр харьцуулалт нь маш тодорхой байх болно.
Шударгаар хэлье: hint бичих ёсгүй хэдэн газар бий.
1. Loop-ийн хувьсагч.
python
for ug in ugs: # hint хэрэггүй
print(ug)Editor нь ugs: list[str] гэдгийг мэдэж байгаа тул ug нь str гэж өөрөө дүгнэнэ.
2. Ойлгомжтой утгатай хувьсагч.
python
ner = "Болд" # hint хэрэггүй
too = 25 # hint хэрэггүйEditor нь утгаас нь харна.
3. Функцийн дотоод түр хувьсагчид.
python
def f(ugs: list[str]) -> int:
niit = len(ugs) # hint хэрэггүй
return niit * 2Тэгвэл хаана ЗААВАЛ бичих вэ?
Функцийн параметр бүрд — үргэлж, үл хамаарах зүйлгүй.
Функцийн буцаах утганд — үргэлж, -> None ч гэсэн.
Хоосон цуглуулгад — ugs: list[str] = [], toolch: dict[str, int] = {}.
Утга нь тодорхойгүй хувьсагчид — utas: str | None = None.
Энэ дөрвөн дүрмийг дагавал таны код мэргэжлийн харагдана, тэгээд editor тань бүрэн хүчээрээ ажиллана.
Хэрэв сонирхвол: өөрийн Курс 1-ийн ямар нэг программаа нээгээд, БҮХ функцийг нь бүрэн hint-лэж үзээрэй. Тоо таах тоглоом, хийх ажлын жагсаалт, тэмдэглэлийн дэвтэр — аль нь ч болно.
Hint нэмэх явцад та магадгүй хэдэн гэнэтийн зүйл олно: "энэ функц заримдаа None буцаадаг юм байна", "энэ параметр нь тоо байх ёстой байсан ч би string дамжуулж байсан юм байна." Тэдгээр илрүүлэлт нь энэ дасгалын жинхэнэ шагнал.
Мөн хүсвэл: pip install mypy (идэвхтэй venv дотор!) гээд, mypy main.py гэж ажиллуулж үзээрэй. Тэр нь таны hint-үүдийг шалгаж, зөрчил байвал жагсаана. Энэ курсэд mypy нь заавал биш — гэхдээ нэг удаа туршиж үзэх нь сонирхолтой.
1. -> None мартах
python
def buk_khevlekh(devter: dict[str, str]):
for ner, utas in devter.items():
print(f"{ner}: {utas}")Алдаа гарахгүй. Гэхдээ гэрээ ХАГАС байна. Уншигч "энэ функц юу буцаадаг юм бол" гэж бодох болно. -> None бич — тэр нь "юу ч буцаахгүй" гэсэн БҮРЭН хариулт.
2. Зөвхөн зарим параметрийг hint-лэх
python
def kharilagch_nemekh(devter: dict[str, str], ner, utas: str) -> dict[str, str]:Алдаа гарахгүй, гэхдээ ner нь орхигдсон. Editor нь ner -ийн талаар юу ч мэдэхгүй. Бүрэн гэрээ гэдэг нь БҮРЭН гэсэн үг — нэг ч параметр орхигдохгүй.
3. Тэнцүү тэмдгийн зай (PEP 8)
python
def f(hemjee: int=5) -> None: # буруу
def f(hemjee: int = 5) -> None: # зөвАлдаа гарахгүй, гэхдээ мэргэжлийн стандартын эсрэг. Hint байвал зайтай, hint байхгүй бол зайгүй (def f(hemjee=5)).
4. Худал hint үлдээх
python
def khaikh(devter: dict[str, str], ner: str) -> str:
return devter.get(ner)Python ажиллуулна, гэхдээ hint нь ХУДАЛ — .get() нь None буцаадаг. mypy нь гомдоно:
main.py:2: error: Incompatible return value type (got "str | None", expected "str")Энэ бол хамгийн муу алдааны төрөл: гэрээ нь худал байвал уншигч түүнд итгэж, None шалгахгүй, дараа нь AttributeError гарна. Засвар: -> str | None.
5. Hint-д хувьсагч бичих
python
tsug = str
def f(ner: tsug) -> None:
...Ажиллана, гэхдээ ойлгомжгүй. Hint-д ШУУД төрөл бич: ner: str.
Бүрэн hint гэдэг нь: параметр БҮР төрөлтэй, буцаах утга сумтай (-> None ч гэсэн), default утгатай параметр ч hint-тэй.
Дараалал: нэр: төрөл = default. Hint байвал тэнцүү тэмдгийн орчим зайтай (hemjee: int = 5), байхгүй бол зайгүй (hemjee=5).
Урт гарчгийг олон мөрөнд хуваа. Параметр гурваас олон бол тус бүрийг өөрийн мөрөнд, trailing comma-тай.
Функцийн гарчиг бол ГЭРЭЭ. Hint нь тэр гэрээг тодорхой болгодог.
Hint бичих явц нь таныг өөрийн кодын талаар БОДОХОД хүргэдэг — "энэ заримдаа None буцаадаг уу?" гэсэн асуулт нь өөрөө үнэ цэнэтэй.
Hint нь МУУХАЙ болж эхэлбэл (dict[str, str | int]), тэр нь илүү сайн бүтэц (dataclass, Бүлэг 9) хэрэгтэй байгаагийн дохио.
Hint бичихгүй газрууд: loop-ийн хувьсагч, ойлгомжтой утгатай хувьсагч, дотоод түр хувьсагч.
Hint ЗААВАЛ бичих газрууд: функцийн параметр бүр, функцийн буцаалт, хоосон цуглуулга, тодорхойгүй утгатай хувьсагч.
Энэ хичээлээс эхлэн курсийн БҮХ код бүрэн hint-тэй байна.
Бүлэг 4 дууслаа. Та одоо орчин үеийн Python-ы хамгийн танигдсан шинжийг эзэмшлээ. FastAPI-гийн documentation дээрх def read_item(item_id: int, q: str | None = None): гэсэн мөр нь танд одоо БҮРЭН ойлгомжтой — параметр, төрөл, union, default утга, бүгд танил.
Дараагийн Бүлэг 5-д бид өгөгдлийн бүтцүүд рүү орно. Tuple — өөрчлөгдөшгүй дараалал, яагаад тэр нь давуу тал болдог. Set — давхардалгүй цуглуулга. Үүрлэсэн бүтэц — dictionary доторх жагсаалт, жагсаалт доторх dictionary, тэр нь яг JSON-ы хэлбэр (Бүлэг 6). Эцэст нь: аль бүтцийг хэзээ сонгох вэ гэсэн шийдвэрийн гарын авлага.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.