Ачааллж байна...
Энэ хичээлээр Бүлэг 13 дуусна. Мөн энэ бол богино, ойлголтын хичээл — шинэ бичлэг бараг байхгүй.
Гэвч тэр нь Python-ы хамгийн ҮНДСЭН механизмуудын нэгийг тайлна.
Асуулт нь энгийн: for loop нь ЯГ ЮУ хийдэг вэ?
Та түүнийг Курс 1-ээс эхлэн хэдэн мянган удаа бичсэн:
python
for useg in "Монгол": # STRING
for too in [1, 2, 3]: # LIST
for ner in {"Болд", "Сараа"}: # SET
for tulkhuur in {"a": 1}: # DICTIONARY
for x, y in [(1, 2), (3, 4)]: # TUPLE-үүд
for mur in fail: # ФАЙЛ
for i in range(10): # RANGE
for a, b in zip(x, y): # ZIP
for kvadrat in generator: # GENERATORЕс өөр төрөл. Нэг л for.
Тэдгээр нь дотоод бүтцээрээ ТЭС ӨӨР. String нь тэмдэгтийн дараалал, dictionary нь hash хүснэгт, файл нь дискэн дээрх байт, generator нь зогссон функц.
Тэгвэл for яаж бүгд дээр ажиллаж байна вэ?
Хариулт нь Бүлэг 8.3-ын ПРОТОКОЛ бөгөөд тэр нь Бүлэг 13.1-ийн generator -ыг бүрэн тайлна.
Бүлэг 8.3-ын дүрмийг санаж байна уу?
Протокол гэдэг нь: "хэрэв та ЭДГЭЭР method-уудтай бол, та ЭНЭ ЗҮЙЛИЙГ хийж чадна."
Python нь чиний ХЭН болохыг асуухгүй. Тэр зөвхөн ЮУ ХИЙЖ ЧАДАХЫГ асууна.
Тэнд бид __len__ (→ len()), __str__ (→ print()), __eq__ (→ ==) -ыг үзсэн.
Одоо ДАВТАГДАХ протоколыг үзнэ.
Тэр нь ХОЁР method шаарддаг:
Method | Юу хийдэг |
|---|---|
| "Надад ITERATOR өг" |
| "Дараагийн утгыг өг" |
Тэр л болоо.
for loop нь тэр хоёрыг л дууддаг. Объектын төрөл, нэр, эцэг class — юу ч хамаагүй.
Эхлээд нэр томьёогоо тодруулъя, учир нь тэдгээр нь төстэй бөгөөд эхэндээ будлиантай.
ITERABLE (давтагдах боломжтой) — __iter__ -тэй объект.
"Би давтагдаж чадна." Жишээ: list, string, dictionary, set, tuple, файл.
ITERATOR (давтагч) — __next__ -тэй объект.
"Би дараагийн утгыг өгч чадна." Жишээ: generator, zip, enumerate.
Хамаарал:
Iterable нь __iter__() дуудахад ITERATOR буцаана
Iterator нь __next__() дуудахад УТГА буцаана
Зүйрлэл:
Iterable бол НОМ. Тэр нь агуулгатай, гэхдээ өөрөө "дараагийн хуудас" гэсэн ойлголтгүй.
Iterator бол ЗАКЛАДКА. Тэр нь "би хаана байна" гэдгийг мэднэ, "дараагийнх нь юу вэ" гэдгийг хэлж чадна.
Нэг номд ОЛОН закладка байж болно — тус бүр өөр хуудсанд. Тиймээс нэг list дээр олон iterator байж болно, тус бүр өөр байрлалд.
for loop нь ЯГ ЮУ хийдэг вэОдоо гол хариулт.
python
for x in jagsaalt:
print(x)Python нь дотроо ЯГ дараах зүйлийг хийж байна:
python
it = jagsaalt.__iter__() # 1. ITERATOR ав
while True:
try:
x = it.__next__() # 2. Дараагийн утгыг ав
except StopIteration: # 3. Утга дуусав уу?
break # → зогс
print(x) # 4. Биеийг ажиллуулТэр л болоо. for бол зөвхөн ЭНЭ.
Дөрвөн алхам:
__iter__() дуудаж iterator ав
__next__() дуудаж утга ав
StopIteration гарвал — ЗОГС
Үгүй бол — биеийг ажиллуулж, 2 руу буц
Илбэ БАЙХГҮЙ.
Бүлэг 13.1-ээс StopIteration -ыг санаж байна уу?
python
gen = toolokh()
print(next(gen))
print(next(gen))
print(next(gen)) # утга дууссан!StopIterationТэр үед би ингэж хэлсэн:
"
forloop нь тэр дохиог сонсож, эвлэгээр зогсдог. Энэ нь Бүлэг 13.4-т бүрэн тайлагдана."
Одоо та мэднэ: for нь StopIteration -ыг try/except -ээр барьж, break хийдэг.
Ойлголтыг бататгахын тулд for -ыг ГАРААР бичье.
python
jagsaalt = [10, 20, 30]
# Ердийн for
print("--- for loop ---")
for x in jagsaalt:
print(x)
# ГАРААР ижил зүйл
print("\n--- гараар ---")
it = iter(jagsaalt) # __iter__() дуудаж байна
while True:
try:
x = next(it) # __next__() дуудаж байна
except StopIteration:
break
print(x)--- for loop ---
10
20
30
--- гараар ---
10
20
30ЯГ ИЖИЛ.
iter(x) нь x.__iter__() -ийн богино бичлэг (яг л len(x) нь x.__len__() шиг).
next(it) нь it.__next__() -ийн богино бичлэг.
Бүлэг 8-ын зарчим дахин: special method-ыг ШУУД дуудахгүй. Built-in функцээр дамжуулна.
python
jagsaalt = [10, 20, 30]
it = iter(jagsaalt)
print(f"jagsaalt: {type(jagsaalt)}")
print(f"it: {type(it)}")
print()
print(next(it))
print(next(it))
print(next(it))
print(next(it)) # утга дууссанjagsaalt: <class 'list'>
it: <class 'list_iterator'>
10
20
30
Traceback (most recent call last):
...
StopIterationlist ба list_iterator нь ХОЁР ӨӨР төрөл.
list — iterable (__iter__ -тэй)
list_iterator — iterator (__next__ -тэй)
Ном ба закладка.
Одоо Бүлэг 13.1-ийн нэг зүйлийг тайлбарлая.
python
jagsaalt = [10, 20, 30]
it = iter(jagsaalt)
print(list(it)) # бүх утгыг ав
print(list(it)) # ДАХИН[10, 20, 30]
[]Хоёр дахь удаа ХООСОН.
Iterator нь НЭГ УДААГИЙН. Закладка нь номын төгсгөлд хүрсэн — тэр нь буцаж эхлэхгүй.
Гэвч LIST нь дахин давтагдана:
python
jagsaalt = [10, 20, 30]
print(list(jagsaalt))
print(list(jagsaalt))[10, 20, 30]
[10, 20, 30]Яагаад? Учир нь list(jagsaalt) дуудах бүрд Python нь ШИНЭ iterator үүсгэдэг (jagsaalt.__iter__()).
Ном хэвээрээ. Зөвхөн ШИНЭ закладка.
Одоо Бүлэг 2.3-ын сургамж бүрэн тодорхой боллоо:
python
hosud = zip([1, 2], ["а", "б"])
print(list(hosud))
print(list(hosud))[(1, 'а'), (2, 'б')]
[]zip нь ITERATOR буцаадаг, iterable БИШ. Тиймээс тэр нь НЭГ УДААГИЙН.
Ижил зүйл enumerate, map, filter, generator дээр.
Харин range нь ITERABLE:
python
r = range(3)
print(list(r))
print(list(r))[0, 1, 2]
[0, 1, 2]range нь дахин давтагдана! Тэр нь zip -ээс ялгаатай.
Тиймээс range -ыг олон удаа ашиглаж болно, zip -ыг болохгүй. Одоо та яагаад гэдгийг мэдэж байна.
Нэг нарийн зүйл: бүх iterator нь мөн iterable юм.
python
gen = (i * i for i in range(3))
it = iter(gen)
print(gen is it) # ЯГ ТЭР объект уу?TrueGenerator -ын __iter__ нь ӨӨРИЙГӨӨ буцаадаг.
Яагаад? Учир нь for loop нь ЭХЛЭЭД __iter__() дууддаг. Хэрэв generator нь түүнийг дэмждэггүй бол — for ажиллахгүй.
Тиймээс generator нь "би аль хэдийн iterator байна, өөрийгөө буцаая" гэж хэлдэг.
Тэр л шалтгаанаар та generator дээр шууд for хийж чадна:
python
gen = (i * i for i in range(3))
for x in gen:
print(x)0
1
4Одоо буцаж хараарай. Курсийн олон нууц одоо тодорхой боллоо.
Яагаад for нь ес өөр төрөл дээр ажилладаг вэ?
→ Тэд бүгд __iter__ -тэй. Өөр ямар ч холбоо байхгүй.
Яагаад zip -ыг хоёр удаа ашиглаж болохгүй вэ? (Бүлэг 2.3)
→ Тэр нь ITERATOR, НЭГ УДААГИЙН.
Яагаад generator нь санах ой хэмнэдэг вэ? (Бүлэг 13.1)
→ Тэр нь утгыг __next__() дуудахад л үүсгэдэг. Бүгдийг хадгалдаггүй.
Яагаад StopIteration нь алдаа биш вэ? (Бүлэг 13.1)
→ Тэр нь ДОХИО. for нь түүнийг барьж, зогсдог.
Яагаад __getitem__ -ээр for ажилладаг вэ? (Бүлэг 8.3)
→ Хэрэв __iter__ байхгүй бол, Python нь __getitem__ -ыг 0, 1, 2... гэж дуудна, IndexError гарах хүртэл.
Тэр нь ХУУЧИН арга. Одоо та жинхэнэ шийдэл нь __iter__ гэдгийг мэдэж байна.
Яагаад sum, max, sorted, list, comprehension бүгд ижил зүйл дээр ажилладаг вэ?
→ Тэд бүгд for loop дээр баригдсан. for нь iterable шаарддаг. Ижил протокол.
Python бол протоколуудын систем. Бүлэг 8.3-ын өгүүлбэр дахин батлагдлаа.
Энэ курс нь өөрийн __iter__/__next__ бичихийг ЗААВАЛ шаардахгүй. Тэр нь ховор хэрэгцээ.
Гэхдээ жишээ харах нь ойлголтыг бататгана.
Бүлэг 8.3-ын ZarlagiinBurtgel -ыг санаж байна уу?
Тэнд бид __getitem__ ашиглан for -ыг ажиллуулсан. Тэр нь ХУУЧИН арга.
Одоо ЗӨВ арга:
python
class ZarlagiinBurtgel:
def __init__(self) -> None:
self.zarlaguud: list[str] = []
def nemekh(self, zarlaga: str) -> None:
self.zarlaguud.append(zarlaga)
def __iter__(self):
return iter(self.zarlaguud) # дотоод жагсаалтын iterator!
def __len__(self) -> int:
return len(self.zarlaguud)
burtgel = ZarlagiinBurtgel()
burtgel.nemekh("Ном")
burtgel.nemekh("Автобус")
burtgel.nemekh("Хоол")
for z in burtgel:
print(z)
print(f"\nНийт: {len(burtgel)}")
print(f"Эрэмбэлсэн: {sorted(burtgel)}")
print(f"Comprehension: {[z.upper() for z in burtgel]}")Ном
Автобус
Хоол
Нийт: 3
Эрэмбэлсэн: ['Автобус', 'Ном', 'Хоол']
Comprehension: ['НОМ', 'АВТОБУС', 'ХООЛ']__iter__ нь дотоод жагсаалтын iterator -ыг ДАМЖУУЛЖ байна.
return iter(self.zarlaguud) — "миний дотоод жагсаалтаас закладка ав."
Тэр л болоо. Нэг мөр.
Одоо for, sorted, comprehension, sum, max — БҮГД ажиллана.
__getitem__ -ээс ДЭЭР:
Илүү тод (жинхэнэ протокол)
Дараалал БИШ объектод ч ажиллана (dictionary шиг)
for нь мөнхөд гүйх эрсдэлгүй
Мөн yield -ээр ч бичиж болно:
python
def __iter__(self):
for z in self.zarlaguud:
yield z # generator!Бүлэг 13.1-ийн yield нь __iter__ -д ажиллаж байна.
Учир нь yield -тэй функц нь generator буцаадаг, generator нь iterator юм. Гинж бүрэн.
Хэрэв сонирхвол: for loop -ыг ГАРААР бичээд (iter, next, try/except StopIteration), ердийн for -той ижил ажиллаж байгааг батлаарай.
Тэр туршилт нь for -ийн бүх нууцыг тайлна.
Мөн хүсвэл: zip ба range -ыг хоёр удаа list() -д хийж, ялгааг өөрийн нүдээр хараарай. Нэг нь хоосон, нөгөө нь хэвээрээ.
Мөн хүсвэл: өөрийн class-д __iter__ нэмээд, for, sorted, comprehension бүгд ажиллаж эхлэхийг мэдрээрэй.
1. Iterator -ыг хоёр удаа ашиглах
python
gen = (i for i in range(3))
print(sum(gen))
print(sum(gen))3
0Iterator нь НЭГ УДААГИЙН. Олон удаа хэрэгтэй бол list() -д хий.
2. iterable ба iterator -ыг андуурах
Iterable = __iter__ (list, string, dict) — олон удаа давтагдана
Iterator = __next__ (generator, zip, enumerate) — НЭГ УДААГИЙН
3. StopIteration -ыг алдаа гэж бодох
Тэр нь ДОХИО, алдаа биш. for нь түүнийг барьдаг.
Гэхдээ next() -ыг ГАРААР дуудвал — та өөрөө барих ёстой:
python
try:
x = next(it)
except StopIteration:
print("Дууслаа")Эсвэл default утга өг:
python
x = next(it, None) # дуусвал None4. __iter__ -д self буцаах (буруу)
python
class Burtgel:
def __iter__(self):
return self # БУРУУ — self нь __next__ -гүй!TypeError: iter() returned non-iterator of type 'Burtgel'__iter__ нь ITERATOR буцаах ёстой (__next__ -тэй объект).
Хамгийн энгийн: return iter(self.dotood_jagsaalt).
5. for -д index ашиглах гэж оролдох
python
gen = (i for i in range(5))
print(gen[2])TypeError: 'generator' object is not subscriptableIterator -д index байхгүй. Тэр нь дараалал БИШ.
for loop нь ЯГ ГУРВАН зүйл хийдэг:
iter(x) → iterator ав
next(it) → дараагийн утга ав
StopIteration гарвал → ЗОГС
Илбэ БАЙХГҮЙ.
ITERABLE = __iter__ -тэй ("би давтагдаж чадна"). Жишээ: list, string, dict, set, range.
ITERATOR = __next__ -тэй ("би дараагийн утгыг өгч чадна"). Жишээ: generator, zip, enumerate.
Зүйрлэл: НОМ (iterable) ба ЗАКЛАДКА (iterator). Нэг номд олон закладка байж болно.
iter(x) = x.__iter__(). next(it) = it.__next__(). (Бүлэг 8-ын зарчим: special method-ыг ШУУД дуудахгүй.)
ITERATOR нь НЭГ УДААГИЙН. Дуусвал — хоосон.
zip, enumerate, generator → iterator → НЭГ УДААГИЙН (Бүлэг 2.3-ын сургамж!)
range, list, string → iterable → ОЛОН УДАА (дуудалт бүрд ШИНЭ iterator)
Generator -ын __iter__ нь ӨӨРИЙГӨӨ буцаадаг — тиймээс generator дээр шууд for хийж болно.
StopIteration нь АЛДАА БИШ — ДОХИО. for нь түүнийг барьж, зогсдог.
Өөрийн class-д давтагдах чадвар нэмэх:
python
def __iter__(self):
return iter(self.dotood_jagsaalt) # нэг мөр!Дараа нь for, sorted, sum, comprehension — БҮГД ажиллана.
__getitem__ -ээр for ажиллуулах нь ХУУЧИН арга (Бүлэг 8.3). __iter__ нь ЗӨВ.
PYTHON БОЛ ПРОТОКОЛУУДЫН СИСТЕМ. Бүлэг 8.3-ын өгүүлбэр эцэст нь бүрэн батлагдлаа.
Бүлэг 13 дууслаа. Та одоо Python-ы гүнзгий хэрэгслүүдийг эзэмшлээ: generator (санах ой), raise ба өөрийн exception (алдаа), with (цэвэрлэгээ), iterator (for -ийн нууц).
Бүлэг 14-т бид async -ыг үзнэ.
Тэр нь орчин үеийн Python-ы хамгийн их яригддаг, хамгийн их айдас төрүүлдэг сэдэв юм. FastAPI-гийн documentation нь async def гэсэн бичлэгээр дүүрэн байдаг.
Гэвч би танд эхнээс нь шударгаар хэлье: FastAPI ашиглахын тулд async -ыг ЭЗЭМШИХ ШААРДЛАГАГҮЙ. Түүнийг УНШИЖ ТАНИХ л хангалттай. Мөн FastAPI нь ердийн def -тэй ч бүрэн ажилладаг.
Тиймээс Бүлэг 14 нь гурван богино хичээл — ойлголтын түвшинд. Бид async -ыг айдасгүй болгож, түүнийг уншиж таних чадвар олгоно. Тэгээд Бүлэг 15-ын capstone руу орно.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.