Ачааллж байна...
Өмнөх хичээлд бид type hint гэж юу болох, яагаад бий болсон, Python түүнийг хэрхэн хардаг (үнэндээ ХАРДАГГҮЙ) талаар ойлголттой болсон. Одоо бодит бичлэг рүү орно.
Энэ хичээл бол ойлголтын биш, ДАДЛАГЫН хичээл. Бид үндсэн төрлүүдийн hint (int, str, float, bool), цуглуулгын hint (list[int], dict[str, int]), болон хувьсагчид hint өгөх аргыг үзнэ. Олон жишээ байна, тэдгээрийг зөвхөн уншихаас илүү өөрийн editor дээр бичиж үзвэл хамгийн үр дүнтэй.
Мөн энэ хичээлд та editor тань type hint-ийн ачаар хэрхэн УХААЛАГ болохыг өөрийн нүдээр харна — тэр нь энэ бүх ажлын хамгийн шууд шагнал юм.
Өмнөх хичээлээс шошгоны зүйрлэлийг үргэлжлүүлье. Хайрцган дээр "агуулга: тоо" гэж бичих нь эхлэл. Гэвч агуулахын ажилчид илүү нарийвчлалыг хүсдэг.
"Хайрцаг доторх зүйл: ном" гэсэн шошго ойлгомжтой.
"Хайрцаг доторх зүйл: номнууд" гэсэн шошго ч бас ойлгомжтой, гэхдээ ялгаатай — энэ нь олон юм гэсэн үг.
"Хайрцаг доторх зүйл: номнуудын жагсаалт, тус бүр нь номын нэр (текст)" — энэ бол хамгийн бүрэн шошго.
Python-ы hint яг ийм давхаргалагдана. int нь нэг тоо. list нь жагсаалт. list[int] нь тоонуудын жагсаалт. Дөрвөлжин хаалт нь "юугаар дүүрсэн бэ" гэсэн асуултад хариулж байна.
Энэ хичээлийн турш бид энгийнээс нарийн руу явна.
Python-д хамгийн түгээмэл дөрвөн төрөл байна, тэдгээр нь Курс 1-ээс бүгд танил.
python
ner: str = "Болд"
nas: int = 25
undur: float = 1.75
idevkhtei: bool = TrueМөр бүрийг задалъя.
ner: str = "Болд" — энд ГУРВАН хэсэг байна. ner бол хувьсагчийн нэр. : str бол type hint — цэгтэй таслалын ард төрөл. = "Болд" бол утга олголт.
Дараалал нь ҮРГЭЛЖ ийм: нэр, цэгтэй таслал, төрөл, тэнцүү тэмдэг, утга. Цэгтэй таслал нь hint-ийг, тэнцүү тэмдэг нь утгыг тэмдэглэдэг. Тэднийг андуурч болохгүй.
Дөрвөн төрлийг товч сануулъя (бүгд Курс 1-ээс танил):
str — текст. "Болд", "Улаанбаатар", "".
int — бүхэл тоо. 25, 0, -100, 1000000.
float — бутархай тоо. 1.75, 0.5, 3.14, -0.001.
bool — үнэн/худал. Зөвхөн True эсвэл False.
Одоо чухал зүйл: хувьсагчид hint өгөх нь заавал БИШ. Ихэнх тохиолдолд Python (болон editor) нь утгаас нь төрлийг өөрөө таамаглаж чадна:
python
ner = "Болд"Editor нь "Болд" бол string гэдгийг харж, ner нь str гэж дүгнэнэ. Hint бичих шаардлагагүй. Тиймээс практикт хувьсагчийн hint нь ХОВОР бичигддэг.
Тэгвэл хаана бичдэг вэ? Функцийн параметр ба буцаалт дээр. Тэнд Python нь юу ч таамаглаж чадахгүй — учир нь параметрт ямар утга ирэхийг функц өөрөө мэдэхгүй. Яг тиймээс энэ курсийн бүх hint нь функц дээр төвлөрнө.
Гэхдээ хувьсагчийн hint нь ХОЁР тохиолдолд хэрэгтэй болдог, тэднийг доор үзнэ.
Одоо жинхэнэ хэрэглээ рүү орно.
python
def mendchilekh(ner: str) -> str:
return f"Сайн байна уу, {ner}!"
def nas_shalgakh(nas: int) -> bool:
return nas >= 18
def talbai(urt: float, urgun: float) -> float:
return urt * urgun
print(mendchilekh("Болд"))
print(nas_shalgakh(25))
print(talbai(3.5, 2.0))Үр дүн:
Сайн байна уу, Болд!
True
7.0Функц бүрийн гарчгийг уншаарай. Тэдгээр нь өөрсдөө тайлбарлаж байна:
mendchilekh(ner: str) -> str — "string ав, string буцаа."
nas_shalgakh(nas: int) -> bool — "бүхэл тоо ав, үнэн/худал буцаа."
talbai(urt: float, urgun: float) -> float — "хоёр бутархай тоо ав, бутархай тоо буцаа."
Функцийн ДОТОР орох шаардлагагүй. Гарчиг нь гэрээ юм.
Хэрэв параметр нь float гэж зарлагдсан бол int дамжуулж болох уу?
python
def talbai(urt: float, urgun: float) -> float:
return urt * urgun
print(talbai(3, 2))6Ажиллана, ямар ч анхааруулга байхгүй, mypy ч гомдохгүй. Учир нь Python-ы type систем нь int -ийг float -ын хүлээн зөвшөөрөгдөх хувилбар гэж үздэг — бүхэл тоо бол бутархай тооны тусгай тохиолдол юм.
Гэхдээ ЭСРЭГ ЧИГЛЭЛД болохгүй:
python
def nas_shalgakh(nas: int) -> bool:
return nas >= 18
print(nas_shalgakh(25.5))Python нь ажиллуулна (True гарна), гэхдээ editor нь улаанаар зурж, mypy нь гомдоно:
main.py:5: error: Argument 1 to "nas_shalgakh" has incompatible type "float"; expected "int"has incompatible type "float"; expected "int" гэдэг нь "float ирлээ, int хүлээж байсан" гэсэн үг. Логиктой: бүхэл тоо шаардаж байгаа газарт бутархай тоо өгөх нь мэдээлэл алдагдахад хүргэж болно.
Санах дүрэм: int нь float болж чадна, float нь int болж чадахгүй.
Одоо list, dictionary руу орно. Энд шинэ бичлэг гарч ирнэ: дөрвөлжин хаалт.
Эхлээд буруу аргаас эхэлье:
python
def niilber(tootsuud: list) -> int:
return sum(tootsuud)Энэ ажиллана. Гэхдээ шошго нь ХАНГАЛТГҮЙ. list гэдэг нь зөвхөн "жагсаалт" гэж хэлж байна — тэр жагсаалтад ЮУ байгааг хэлээгүй. Тоонууд уу? String-үүд үү? Холимог уу?
Одоо зөв аргаар:
python
def niilber(tootsuud: list[int]) -> int:
return sum(tootsuud)
print(niilber([1, 2, 3, 4, 5]))15list[int] гэдэг нь "бүхэл тоонуудын жагсаалт" гэсэн үг. Дөрвөлжин хаалт дотор байгаа төрөл нь "энэ жагсаалт юугаар дүүрсэн бэ" гэдгийг хэлж байна.
Хэдэн жишээ:
python
neres: list[str] = ["Болд", "Сараа", "Төмөр"]
tootsuud: list[int] = [1, 2, 3]
unes: list[float] = [15000.0, 800000.0]
tugluuruud: list[bool] = [True, False, True]Энэ бол хувьсагчид hint өгөх нь хэрэгтэй болдог эхний тохиолдол. Учир нь хоосон жагсаалт дээр editor нь юу ч таамаглаж чадахгүй:
python
neres = [] # editor: "энэ юуны жагсаалт вэ? мэдэхгүй"
neres: list[str] = [] # editor: "аан, string-үүдийн жагсаалт"Хоёр дахь тохиолдолд editor нь neres.append(123) гэж бичихэд анхааруулна — учир нь 123 нь string биш.
Dictionary нь ХОЁР төрөлтэй: key-ийн төрөл, value-гийн төрөл. Тиймээс дөрвөлжин хаалт дотор хоёр зүйл, таслалаар тусгаарлагдана.
python
nas: dict[str, int] = {"Болд": 25, "Сараа": 30}dict[str, int] гэдэг нь "key нь string, value нь бүхэл тоо байдаг dictionary" гэсэн үг. Дараалал нь ҮРГЭЛЖ dict[key, value].
Хэдэн жишээ:
python
unes: dict[str, int] = {"ном": 15000, "утас": 800000}
tokhirgoo: dict[str, bool] = {"darkmode": True, "medegdel": False}
onoo: dict[str, float] = {"Болд": 85.5, "Сараа": 92.0}Функц дээр:
python
def khamgiin_unetei(unes: dict[str, int]) -> str:
return max(unes, key=lambda baraa: unes[baraa])
unes = {"ном": 15000, "утас": 800000, "харандаа": 500}
print(khamgiin_unetei(unes))утасГарчгийг уншаарай: "key нь string, value нь бүхэл тоо байдаг dictionary ав, string буцаа." Функц юу хийхийг бүрэн ойлгож болно.
Дашрамд, max(unes, key=lambda baraa: unes[baraa]) гэсэн мөр нь Хичээл 3.5-ын мэдлэгийг ашиглаж байна. Dictionary дээр max дуудахад Python нь KEY-үүдийг харьцуулдаг тул key= функцээр "утгаар нь харьцуул" гэж заавал зааж өгөх хэрэгтэй.
Hint-үүд ҮҮРЛЭЖ болно. Энэ нь эхэндээ хачирхалтай харагдана, гэхдээ логик нь тууштай.
python
suragchid: list[dict[str, int]] = [
{"Болд": 85},
{"Сараа": 92},
]list[dict[str, int]] гэдэг нь "dictionary-уудын жагсаалт, dictionary бүрийн key нь string, value нь бүхэл тоо" гэсэн үг. Гаднаас дотогшоо уншаарай: жагсаалт → доторх нь dictionary → доторх нь string-ээс тоо руу.
Илүү бодит жишээ:
python
angi: dict[str, list[str]] = {
"10а": ["Болд", "Сараа"],
"10б": ["Төмөр", "Цэцэг"],
}dict[str, list[str]] — "key нь string (ангийн нэр), value нь string-үүдийн жагсаалт (сурагчдын нэрс)."
Мөн жагсаалт доторх жагсаалт:
python
matritz: list[list[int]] = [
[1, 2, 3],
[4, 5, 6],
]list[list[int]] — "жагсаалтуудын жагсаалт, дотоод жагсаалт бүр нь тоонуудаас бүрдэнэ."
Практик зөвлөгөө: үүрлэлт нь ХОЁР давхраас илүү болвол код унших нь хэцүү болно. Тэр үед dataclass (Бүлэг 9) ашиглах нь илүү зөв шийдэл — тэнд та list[Suragch] гэж бичих боломжтой болно, тэр нь list[dict[str, str | int | bool]] гэхээс хамаагүй тод. Одоохондоо энэ мэдээллийг зөвхөн санаж яваарай.
Товч дурдъя, хоёуланг нь Бүлэг 5-д бүрэн үзнэ.
Tuple нь өвөрмөц — түүний hint нь элемент БҮРИЙН төрлийг заана:
python
tsegleg: tuple[int, int] = (10, 20)
hun: tuple[str, int, str] = ("Болд", 25, "Улаанбаатар")Яагаад ингэж байна вэ? Учир нь tuple нь ихэвчлэн ТОГТМОЛ бүтэцтэй байдаг — эхний элемент нь нэр, хоёр дахь нь нас гэх мэт. Жагсаалт бол нэг төрлийн олон зүйл, tuple бол өөр төрлийн цөөн зүйл. Энэ ялгааг Бүлэг 5-д гүнзгий үзнэ.
Set нь жагсаалттай ижил бичлэгтэй:
python
uvurmuts_neres: set[str] = {"Болд", "Сараа"}Одоо энэ бүх ажлын шагналыг харъя. VS Code нээгээд дараах кодыг бичээрэй:
python
def neres_kheveleкh(neres: list[str]) -> None:
for ner in neres:
print(ner.)Сүүлийн мөрөнд ner. гэж бичээд түр зогсоорой. Editor нь ЖАГСААЛТ гаргаж ирнэ: upper(), lower(), split(), replace(), strip(), startswith() — string-ийн бүх method.
Editor яаж мэдэв? Та neres: list[str] гэж зарласан. Тиймээс for ner in neres дотор ner нь str байх ёстой. Editor нь тэр гинжийг дагаж, string-ийн method-уудыг санал болгосон.
Одоо hint-ийг устгаад үзээрэй:
python
def neres_kheveleкh(neres) -> None:
for ner in neres:
print(ner.)Editor нь юу ч санал болгохгүй, эсвэл маш ерөнхий жагсаалт өгнө. Тэр neres -д юу байгааг мэдэхгүй.
Энэ бол type hint-ийн хамгийн шууд, хамгийн өдөр тутмын ашиг тус. Та hint бичих гурван секунд зарцуулж, оронд нь editor тань таны бичих бүх мөрөнд туслах болно.
Курс 1-ийн харилцагчийн дэвтрийн кодыг сэргээж, hint нэмье.
Өмнө нь:
python
def kharilagch_nemekh(devter, ner, utas):
devter[ner] = utas
return devter
def kharilagch_khaikh(devter, ner):
if ner in devter:
return devter[ner]
return None
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:
if ner in devter:
return devter[ner]
return None
def buk_khevlekh(devter: dict[str, str]) -> None:
for ner, utas in devter.items():
print(f"{ner}: {utas}")Гурван функцийг харьцуулаарай. Одоо тус бүр нь өөрөө хэлж байна:
Эхнийх нь: "дэвтэр, нэр, утас ав; дэвтэр буцаа."
Хоёр дахь нь: "дэвтэр, нэр ав; утас БУЮУ юу ч биш буцаа."
Гурав дахь нь: "дэвтэр ав; юу ч буцаахгүй, зөвхөн хэвлэнэ."
Хоёр шинэ зүйл гарч ирлээ.
-> None нь "энэ функц утга буцаадаггүй" гэсэн үг. Курс 1-ээс санаж байгаа байх: return бичээгүй функц нь автоматаар None буцаадаг. print хийдэг функцууд ихэвчлэн ийм байна. Энэ бол маш түгээмэл hint.
str | None нь "string ЭСВЭЛ None" гэсэн үг. Босоо зураас (|) нь "эсвэл" гэсэн утгатай. Энэ бичлэгийг дараагийн хичээлд бүрэн үзнэ — одоохондоо зөвхөн танилцаж, "утга байж ч болно, байхгүй ч байж болно" гэсэн санааг ойлгоод өнгөрөөрэй.
Хичээл 3.5-д бид функцийг утга болгож дамжуулж сурсан. Тэдгээрт ч hint өгч болно, гэхдээ бичлэг нь арай нарийн:
python
from typing import Callable
def hoyor_udaa_duudakh(func: Callable[[], None]) -> None:
func()
func()Callable[[], None] гэдэг нь "аргументгүй, юу ч буцаадаггүй функц" гэсэн үг. Эхний дөрвөлжин хаалт нь параметрүүдийн жагсаалт (энд хоосон), дараа нь буцаах төрөл.
Энэ бичлэг нь эхэндээ будлиантай тул би түүнийг энэ курсэд БАРАГ АШИГЛАХГҮЙ. Зөвхөн та бусдын кодод харах магадлалтай тул танилцуулж байна. Хэрэв харвал: "аан, энэ параметр нь функц хүлээж байна" гэж ойлгоод өнгөрөөрэй.
Хуучин Python код (2021 оноос өмнөх) дээр та ийм бичлэг харах магадлалтай:
python
from typing import List, Dict
def niilber(tootsuud: List[int]) -> int:
return sum(tootsuud)Том үсэгтэй List, Dict нь typing модулиас import хийгддэг байсан. Python 3.9-өөс эхлэн ЖИЖИГ үсэгтэй list[int], dict[str, int] -ийг шууд ашиглах боломжтой болсон бөгөөд import шаардлагагүй.
Энэ курс нь ЗӨВХӨН шинэ, жижиг үсэгтэй бичлэгийг ашиглана. Хуучин бичлэг нь ажилладаг ч хуучирсан. Хэрэв та интернэтээс List[int] гэсэн код харвал — тэр нь хуучин заавар гэдгийг мэдэж, list[int] гэж бич.
Хэрэв сонирхвол: Түвшин 1-ийн guided build (текст статистикийн хэрэгсэл) кодоо нээгээд, функц бүрд hint нэмж үзээрэй. Жишээ нь:
python
def fail_unshikh(zam: str) -> str:
...
def ugend_salgakh(tekst: str) -> list[str]:
...
def davtamj_toolokh(ugs: list[str]) -> dict[str, int]:
...Hint нэмсний дараа editor нь илүү ухаалаг болсныг мэдрэх болно — жишээ нь ugs. гэж бичихэд жагсаалтын method-ууд гарч ирнэ.
Мөн хүсв: хоосон жагсаалт үүсгээд hint-тэй, hint-гүй хоёр хувилбарыг editor дээр харьцуулж үзээрэй. neres = [] ба neres: list[str] = [] — дараа нь neres.append(...) гэж бичихэд ялгаа мэдрэгдэнэ.
1. Дугуй хаалт ашиглах
python
def niilber(tootsuud: list(int)) -> int:
return sum(tootsuud)Traceback (most recent call last):
File "main.py", line 1, in <module>
def niilber(tootsuud: list(int)) -> int:
TypeError: 'type' object is not iterable'type' object is not iterable гэдэг нь "төрлийг давтаж болохгүй" гэсэн үг. Hint-д ЗААВАЛ дөрвөлжин хаалт: list[int]. Дугуй хаалт нь list(...) гэсэн функцийн дуудалт болж хувирдаг.
2. Dictionary-д нэг л төрөл бичих
python
nas: dict[str] = {"Болд": 25}VS Code нь улаанаар зурна, mypy нь гомдоно. Dictionary нь ЗААВАЛ хоёр төрөлтэй: dict[str, int]. Key ба value хоёулаа заавал.
3. Цэгтэй таслалын оронд тэнцүү тэмдэг
python
ner = str = "Болд"Алдаа гарахгүй, гэхдээ огт өөр зүйл болно — ner ба str хоёулаа "Болд" болно, мөн та Python-ы built-in str -ийг ДАРЖ бичлээ. Энэ бол Хичээл 3.4-т үзсэн built-in дарж бичих алдаа. Зөв: ner: str = "Болд".
4. Том үсэгтэй List, Dict ашиглах
python
def niilber(tootsuud: List[int]) -> int:
return sum(tootsuud)Traceback (most recent call last):
File "main.py", line 1, in <module>
def niilber(tootsuud: List[int]) -> int:
NameError: name 'List' is not definedNameError: name 'List' is not defined гэдэг нь "List нэртэй зүйл олдсонгүй" гэсэн үг. Том үсэгтэй List нь from typing import List гэж import хийх шаардлагатай — гэхдээ түүнийг ашиглах хэрэггүй. Зөв: жижиг үсэгтэй list[int].
5. Hint нь шалгалт хийнэ гэж найдах
python
def nas_shalgakh(nas: int) -> bool:
return nas >= 18
print(nas_shalgakh("хорин тав"))Traceback (most recent call last):
File "main.py", line 5, in <module>
print(nas_shalgakh("хорин тав"))
File "main.py", line 2, in nas_shalgakh
return nas >= 18
TypeError: '>=' not supported between instances of 'str' and 'int'Анзаараарай: алдаа нь ФУНКЦ ДОТОР гарсан, дуудалт дээр биш. Python нь hint-ийг шалгаагүй — тэр string-ийг эелдэгээр хүлээж авч, дараа нь харьцуулах гэж оролдоод унасан. Editor нь энэ алдааг ажиллуулахаас өмнө анхааруулах байсан, гэхдээ Python өөрөө биш. Өмнөх хичээлийн гол сургамж дахин батлагдлаа.
Бичлэг: нэр: төрөл = утга (хувьсагч), def f(param: төрөл) -> буцаах_төрөл: (функц).
Дөрвөн үндсэн төрөл: str, int, float, bool.
int нь float шаардаж байгаа газарт болно; эсрэгээр болохгүй.
Цуглуулгын hint нь дөрвөлжин хаалт ашиглана: list[int], set[str], dict[str, int].
Dictionary нь ЗААВАЛ хоёр төрөлтэй: dict[key_төрөл, value_төрөл].
Hint-үүд үүрлэж болно: list[dict[str, int]], dict[str, list[str]]. Гэхдээ хоёр давхраас цааш явбал dataclass (Бүлэг 9) илүү зөв шийдэл.
-> None нь "юу ч буцаадаггүй" гэсэн үг — print хийдэг функцүүдийн стандарт hint.
str | None нь "string эсвэл юу ч биш" — дараагийн хичээлийн сэдэв.
Хувьсагчид hint өгөх нь ихэвчлэн шаардлагагүй (editor өөрөө таамаглана), гэхдээ ХООСОН цуглуулга дээр хэрэгтэй: neres: list[str] = [].
Хуучин List[int], Dict[str, int] (том үсэгтэй, typing-ээс import) нь ХУУЧИРСАН. Жижиг үсэгтэй list[int] ашигла.
Editor нь hint-ийн ачаар илүү ухаалаг болно — энэ бол хамгийн шууд, өдөр тутмын шагнал.
Дараагийн хичээлд бид энэ хичээлд хоёр удаа гарч ирсэн | None бичлэгийг бүрэн үзнэ. Тэр нь "утга байж ч болно, байхгүй ч байж болно" гэсэн бодит амьдралын нөхцөл байдлыг илэрхийлдэг — жишээ нь "энэ нэрийг дэвтрээс хайлаа, олдсон эсвэл олдоогүй." Мөн None дээр method дуудахад гарч ирдэг AttributeError гэсэн маш түгээмэл алдааг задлан тайлбарлана.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.