Ачааллж байна...
Өмнөх хоёр хичээлд бид generator-ийг ганцаар нь ажиллуулсан. Generator функц нэг машин үүсгэж, generator expression нэг мөрөнд ижил машин бүтээж байлаа. Тэр машинууд ихэвчлэн list, range, файл зэрэг энгийн эх сурвалжаас утга авч, sum(), any(), for loop зэрэг хэрэглэгчид өгч байсан. Энэ хичээлд бид нэг энгийн боловч хүчирхэг санааг нэмнэ: generator-ийн эх сурвалж нь өөр generator байж болно. Бүлэг 1-ээс бид generator бол iterator, iterator бол for loop-д өгч болох зүйл гэдгийг мэднэ. Тэгэхээр нэг generator-ийг нөгөө generator-ийн for loop-д шууд өгч болох нь гарцаагүй.
Ийм байдлаар хэд хэдэн generator-ийг гинжин холбоход pipeline үүснэ. Pipeline гэдэг англи үг анх "хоолой" гэсэн утгатай бөгөөд програмчлалд "өгөгдөл нэг шатнаас нөгөө шат руу урсдаг дараалсан боловсруулалт"-ыг хэлдэг. Шат бүр ганцхан энгийн ажил хийдэг: нэг нь файлаас мөр уншина, нөгөө нь хоосон мөрийг хаяна, гурав дахь нь мөрийг задална, дөрөв дэх нь зөвхөн алдааны мөрүүдийг үлдээнэ. Шат тус бүр нь хэдэн мөр л код, тусад нь ойлгоход хялбар, тусад нь шалгахад хялбар. Гэвч тэдгээр хамтдаа нарийн төвөгтэй боловсруулалт хийж, санах ойд нэг удаад нэг л мөр байлгадаг.
Энэ хичээлийн гол сорилт нь pipeline-ий "үл харагдах" ажиллагааг ойлгох явдал. Дөрвөн шат зэрэг хөлдсөн машин байх бөгөөд нэг мөр конвейерийн эхнээс төгсгөл хүртэл хэрхэн дамждаг нь кодыг харахад огт тодорхойгүй. Тиймээс бид pipeline-ийг шат шатаар нь бүтээж, шат бүрийг нэмэх болгондоо ажиллуулж шалгана. Дараа нь нэг мөрийг бүх шатаар дамжуулж, алхам бүрт дөрвөн машин тус бүр хаана зогсож байгааг trace-ээр дагана.
Талх нарийн боовны үйлдвэрийн конвейерийг төсөөлөөд үзээрэй. Туузан замын дагуу дөрвөн ажилчин зогсож байна. Эхнийх нь агуулахаас зуурсан гурил авчирдаг. Хоёр дахь нь гэмтэлтэй, хэлбэр алдсан хэсгийг хаядаг. Гурав дахь нь гурилыг хэлбэржүүлж, талх болгодог. Дөрөв дэх нь зөвхөн нэг төрлийн, жишээлбэл хар талхыг хайрцаглахаар сонгодог. Ажилчин бүр өөрийн ганцхан ажлаа сайн мэддэг, бусдынхыг мэдэх шаардлагагүй.
Энэ үйлдвэрийн онцлог нь конвейер төгсгөлөөс хөдөлдөг явдал. Хайрцаглагч "надад дараагийн талх хэрэгтэй" гэж хэлэхэд л гурав дахь ажилчин талх хийж эхэлнэ. Талх хийхийн тулд түүнд гурил хэрэгтэй тул хоёр дахь ажилчнаас асууна. Хоёр дахь нь эхнийхээс асууна. Эхнийх агуулахаас нэг хэсэг гурил авчирч, хүсэлт конвейерийн дагуу буцаж урсана. Хайрцаглагч юу ч хүсэхгүй бол бүхэл конвейер зогсож, хэн ч ажиллахгүй. Агуулахад хэдэн тонн гурил байсан ч туузан дээр нэг удаад цөөхөн хэсэг л байна.
Энэ бол яг generator pipeline. Шат бүр нь generator, туузан зам нь тэдгээрийг холбосон for loop-ууд, хайрцаглагч нь бидний эцсийн for loop эсвэл sum(). Энэ "төгсгөлөөс татах" зарчмыг англиар pull-based гэж нэрлэдэг бөгөөд бүх хичээлийн туршид түүнийг санаж яваарай.
Бидний ажиллах log файл app.log нэртэй, дотор нь иймэрхүү мөрүүд байна гэж бодъё. Хүсвэл өөрийн хавтаст ийм файл үүсгэж болно. Дөрөв дэх мөр санаатайгаар хоосон.
2026-10-09 08:15:02 INFO user=bat action=login
2026-10-09 08:15:40 ERROR user=saraa action=payment
2026-10-09 08:16:05 INFO user=bat action=view
2026-10-09 08:17:11 WARNING user=temuulen action=upload
2026-10-09 08:18:30 ERROR user=bat action=paymentМөр бүр огноо, цаг, түвшин (INFO, WARNING, ERROR), мессеж гэсэн дөрвөн хэсэгтэй. Бидний зорилго: зөвхөн ERROR мөрүүдийн цаг ба мессежийг хэвлэх.
Шат 1: мөр унших
python
def read_lines(path):
with open(path, encoding="utf-8") as f:
for line in f:
yield line.rstrip("\n")Энэ generator файлыг нээж, мөр бүрийг төгсгөлийн шинэ мөрийн тэмдэггүйгээр нэг нэгээр гаргана. with блок generator-ийн дотор байгааг анзаараарай. Машин yield дээр хөлдөх бүрт файл нээлттэй хэвээр байна, учир нь with блок хараахан дуусаагүй. Машин бүх мөрийг гаргаж дуусахад with блок дуусч, файл хаагдана. Эхний шалгалт:
python
for line in read_lines("app.log"):
print(repr(line))'2026-10-09 08:15:02 INFO user=bat action=login'
'2026-10-09 08:15:40 ERROR user=saraa action=payment'
'2026-10-09 08:16:05 INFO user=bat action=view'
''
'2026-10-09 08:17:11 WARNING user=temuulen action=upload'
'2026-10-09 08:18:30 ERROR user=bat action=payment'repr() string-ийг хашилттай хэвлэдэг тул хоосон мөр ‘’ гэж тод харагдаж байна. Энгийн print() хоосон мөрийг харагдахгүй орхих байсан. Шат 1 ажиллаж байна.
Шат 2: хоосон мөрийг хаях
python
def non_empty(lines):
for line in lines:
if line.strip():
yield lineЭнэ generator-ийн оролт lines нь ямар нэг iterable: list, файл, эсвэл өөр generator байж болно. Шат 2 эх сурвалж нь юу болохыг огт мэдэхгүй, мэдэх ч шаардлагагүй. Энэ нь pipeline-ий шатуудыг хооронд нь чөлөөтэй холбох боломж олгодог чухал чанар юм. line.strip() хоосон зай арилгасан string буцаадаг бөгөөд хоосон string False гэж тооцогддог тул if нөхцөл хоосон мөрийг алгасна. Хоёр шатыг холбож шалгая:
python
lines = read_lines("app.log")
clean = non_empty(lines)
for line in clean:
print(repr(line))'2026-10-09 08:15:02 INFO user=bat action=login'
'2026-10-09 08:15:40 ERROR user=saraa action=payment'
'2026-10-09 08:16:05 INFO user=bat action=view'
'2026-10-09 08:17:11 WARNING user=temuulen action=upload'
'2026-10-09 08:18:30 ERROR user=bat action=payment'Хоосон мөр алга болов. Холболт нь non_empty(lines) гэсэн ганц дуудлага: эхний машиныг хоёр дахь машины оролт болгон өгсөн.
Шат 3: мөрийг задлах
python
def parse(lines):
for line in lines:
date, time, level, message = line.split(" ", 3)
yield {"time": time, "level": level, "message": message}line.split(“ “, 3) нь мөрийг зайгаар хуваах боловч дээд тал нь гурван удаа хуваана, тиймээс дөрвөн хэсэг гарна. Дөрөв дэх хэсэг “user=bat action=login” дотроо зай агуулдаг ч дахин хуваагдахгүй. Энэ гурав дахь argument-гүйгээр мессеж хэд хэдэн хэсэгт хуваагдаж, задлалт эвдрэх байсан. Дөрвөн хэсгийг дөрвөн хувьсагчид задалж, хэрэгтэй гурвыг нь dict болгон гаргана. Огноо бидэнд хэрэггүй ч задлахын тулд хувьсагч шаардлагатай тул date гэж нэрлэсэн.
python
records = parse(non_empty(read_lines("app.log")))
for r in records:
print(r){'time': '08:15:02', 'level': 'INFO', 'message': 'user=bat action=login'}
{'time': '08:15:40', 'level': 'ERROR', 'message': 'user=saraa action=payment'}
{'time': '08:16:05', 'level': 'INFO', 'message': 'user=bat action=view'}
{'time': '08:17:11', 'level': 'WARNING', 'message': 'user=temuulen action=upload'}
{'time': '08:18:30', 'level': 'ERROR', 'message': 'user=bat action=payment'}Энэ удаа гурван шатыг нэг мөрөнд үүрлэн холбосон: дотроос гадагш уншвал эхлээд мөр уншина, дараа нь цэвэрлэнэ, дараа нь задална. Энэ бичлэг богино ч дотроос гадагш уншихыг шаарддаг тул шат олширвол ойлгоход хэцүү болно. Удахгүй бид илүү уншигдахуйц хэлбэрийг сонгоно.
Шат 4: түвшнээр шүүх
python
def only_level(records, level):
for r in records:
if r["level"] == level:
yield rЭнэ шат хоёр argument авна: өмнөх шатны машин ба шүүх түвшин. Ингэснээр нэг функцийг ERROR, WARNING, INFO-д дахин ашиглаж болно. Одоо бүх pipeline-ийг шат бүрийг тусдаа мөрөнд, нэртэй хувьсагчид хадгалан угсаръя:
python
lines = read_lines("app.log")
clean = non_empty(lines)
records = parse(clean)
errors = only_level(records, "ERROR")
for r in errors:
print(r["time"], r["message"])08:15:40 user=saraa action=payment
08:18:30 user=bat action=paymentPipeline бүрэн ажиллаж байна. Энэ хэлбэр дээрээс доош, конвейерийн дарааллаар уншигддаг: мөр, цэвэрлэгээ, задлалт, шүүлт. Шат бүр өөрийн нэртэй тул pipeline юу хийж байгааг кодыг дагаж уншихад тодорхой. Нэг чухал баримт бий: эхний дөрвөн мөр ажиллах үед файлаас нэг ч мөр уншигдаагүй, бүр файл ч нээгдээгүй. Дөрвөн мөр зөвхөн дөрвөн хөлдсөн машин үүсгэж, тэдгээрийг хооронд нь холбосон. Конвейер эцсийн for loop асуух үед л хөдөлнө.
Одоо энэ хичээлийн хамгийн чухал хэсэг: эцсийн for loop эхний ERROR мөрийг авах хүртэл юу болдгийг алхам алхмаар дагая. Алхам бүрт дөрвөн машины төлөвийг тэмдэглэнэ: тус бүр хаана зогсож байна, гарт нь юу байна.
Алхам 0 (дөрвөн хувьсагч оноогдсоны дараа). Дөрвөн машин үүссэн, бүгд эхэндээ зогссон. lines: файл нээгдээгүй. clean, records, errors: функцийн биеийн нэг ч мөр ажиллаагүй. Санах ойд нэг ч log мөр алга.
Алхам 1 (for loop errors-оос анх асуух). errors машин сэрж, for r in records: мөрөнд хүрэнд records-оос асууна. records сэрж, for line in lines: мөрөнд хүрээд clean-ээс асууна. clean сэрж, lines-аас асууна. lines сэрж, файлыг нээж, эхний мөр “...08:15:02 INFO user=bat action=login”-ийг уншина. Энэ мөчид дөрвөн машин бүгд хөдөлгөөнд орсон боловч дээрх гурав нь доод шатныхаа хариуг хүлээж байна. Хүсэлт конвейерийн төгсгөлөөс эхлэл рүү урссан.
Алхам 2 (INFO мөр дээш урсах). lines мөрийг yield хийж хөлдөнө, файлын унших байрлал хоёр дахь мөрний эхэнд. clean мөрийг хүлээн авч, хоосон биш тул yield хийж хөлдөнө. records мөрийг хүлээн авч, dict болгон задалж, {‘level’: ‘INFO’, ...}-г yield хийж хөлдөнө. errors тэр dict-ийг хүлээн авч, түвшнийг шалгана: INFO нь ERROR биш. Тиймээс errors yield хийхгүй, харин өөрийн for loop-ийн дараагийн давталт руу шилжиж, records-оос дахин асууна. Энэ INFO мөр хаягдлаа: эцсийн for loop түүнийг хэзээ ч харсангүй.
Алхам 3 (хоёр дахь мөрийг татах). records сэрж, clean-ээс асууна. clean сэрж, lines-аас асууна. lines сэрж, файлаас “...08:15:40 ERROR user=saraa action=payment”-ийг уншина.
Алхам 4 (ERROR мөр бүх шатыг давах). lines yield хийж хөлдөнө, файлын байрлал гурав дахь мөрний эхэнд. clean шалгаад yield хийж хөлдөнө. records задлаад {‘time’: ‘08:15:40’, ‘level’: ‘ERROR’, ‘message’: ‘user=saraa action=payment’}-г yield хийж хөлдөнө. errors шалгана: ERROR. Энэ удаа errors yield хийж хөлдөнө. Эцсийн for loop dict-ийг r-д онооно.
Алхам 5 (хэвлэх мөчийн бүрэн зураг). print() “08:15:40 user=saraa action=payment” гэж хэвлэх тэр мөчид санах ойн байдал:
lines: yield мөрөнд хөлдсөн, файл нээлттэй, унших байрлал гурав дахь мөрний эхэнд.
clean: yield мөрөнд хөлдсөн, гарт нь сүүлд дамжуулсан ERROR мөрийн string.
records: yield мөрөнд хөлдсөн, гарт нь сүүлд дамжуулсан мөр ба dict.
errors: yield мөрөнд хөлдсөн, гарт нь мөн тэр dict.
Файлын үлдсэн дөрвөн мөр: огт уншигдаагүй, санах ойд байхгүй.
Энэ зураг pipeline-ий бүх үнэ цэнийг харуулж байна. Файл таван мөртэй ч, таван сая мөртэй ч энэ мөчид санах ойд байгаа зүйл ижил: дөрвөн хөлдсөн машин, тэдгээрийн гарт байгаа нэг мөрийн өгөгдөл. Өмнөх хичээлд бид нэг generator expression санах ойг хэрхэн хэмнэдгийг хэмжилтээр харсан. Энд дөрвөн generator холбогдсон ч энэ шинж чанар хадгалагдаж байна, учир нь шат бүр зөвхөн нэг мөрийг дамжуулж, өмнөхийг хадгалдаггүй.
Мөн алхам 2-ын INFO мөрийн хувь заяаг анхаараарай. Тэр мөр гурван шатыг давж, задлагдсан ч дөрөв дэх шатанд шүүгдэж, хаягдсан. Шүүлтүүрийн шат нь өөрөө yield хийхгүйгээр доод шатнаасаа дахин асуух замаар ажилладаг. Эцсийн хэрэглэгч хаягдсан мөрийн тухай огт мэдэхгүй. Тэр зөвхөн "дараагийнх" гэж асууж, бэлэн ERROR мөр хүлээн авдаг.
Жишээ 1: ижил pipeline generator expression-оор
Шат бүр нэг давталт, нэг нөхцөл эсвэл нэг хувиргалт хийдэг энгийн тохиолдолд өмнөх хичээлийн generator expression илүү товч бичлэг өгнө. Задлалтын логикийг тусдаа энгийн функц болгоод, шатуудыг generator expression-оор холбоё:
python
def parse_line(line):
date, time, level, message = line.split(" ", 3)
return {"time": time, "level": level, "message": message}
lines = read_lines("app.log")
clean = (line for line in lines if line.strip())
records = (parse_line(line) for line in clean)
errors = (r for r in records if r["level"] == "ERROR")
for r in errors:
print(r["time"], r["message"])08:15:40 user=saraa action=payment
08:18:30 user=bat action=paymentГаралт ижил, ажиллагаа ч ижил. Дээрх trace энэ хувилбарт ч үгчлэн хүчинтэй, зөвхөн машинууд функцийн нэргүй, <genexpr> машинууд болсон. parse_line() бол энгийн функц, generator биш: нэг мөр аваад нэг dict буцаадаг. Түүнийг generator expression дотор дуудаж байгаа нь "задлах" шатыг үүсгэж байна. read_lines-ийг generator функцээр үлдээсэн шалтгаан нь with блок шаардлагатай, тэр нь нэг мөрт бичлэгт багтахгүй.
Аль хэлбэрийг сонгох вэ? Шат нь нэг мөрт энгийн шүүлт эсвэл хувиргалт бол generator expression уншихад хурдан. Шат нь хэд хэдэн мөр логик, with блок, try/except, дотоод төлөв шаардвал generator функц илүү тодорхой. Бодит кодонд хоёр хэлбэрийг холих нь хэвийн, дээрх жишээ ч яг ингэж холисон.
Жишээ 2: эрт зогсох ба хэдэн мөр уншигдсан бэ
Өмнөх хичээлд эрт зогсолт generator-ийн хамгийн том хурдны давуу тал гэдгийг хэмжилтээр харсан. Pipeline-д энэ давуу тал бүх шатанд нэгэн зэрэг ажилладаг. Үүнийг харахын тулд read_lines-д чагнуур нэмээд, зөвхөн эхний ERROR мөрийг авъя.
python
def read_lines(path):
with open(path, encoding="utf-8") as f:
for number, line in enumerate(f, start=1):
print(f" [файлаас {number}-р мөрийг уншлаа]")
yield line.rstrip("\n")
lines = read_lines("app.log")
clean = (line for line in lines if line.strip())
records = (parse_line(line) for line in clean)
errors = (r for r in records if r["level"] == "ERROR")
first = next(errors)
print("Эхний алдаа:", first["time"], first["message"]) [файлаас 1-р мөрийг уншлаа]
[файлаас 2-р мөрийг уншлаа]
Эхний алдаа: 08:15:40 user=saraa action=paymentХичээл 1.3-ын next() энд бүхэл pipeline-ийн эцсийн хэрэглэгч болов. Чагнуур нийт хоёр мөр уншсаныг харуулж байна. Эхний мөр INFO байсан тул шүүгдэж, хоёр дахь мөр ERROR байсан тул next() хариугаа авч, бүх конвейер зогсов. Файлын үлдсэн дөрвөн мөрийг хэн ч асуугаагүй тул тэд уншигдсангүй, задлагдсангүй, шүүгдсэнгүй. Хэрэв энэ хэдэн гигабайт log байж, эхний алдаа эхний мянган мөрөнд байсан бол pipeline файлын маш бага хэсгийг л уншаад зогсох байсан. enumerate()-ийн start=1 argument нь тоолол 0-ээс биш 1-ээс эхлэхийг заасан.
Энэ кодонд нэг шударга тэмдэглэл бий. Бид pipeline-ийг дундуур нь орхисон тул read_lines машин with блокийн дотор хөлдсөн хэвээр, файл нээлттэй үлдсэн. Python ийм орхигдсон generator-ийг хэн ч барихаа больсны дараа цэвэрлэж, тэр үед with блок дуусч файл хаагдана. Энгийн скриптэд энэ хангалттай. Олон файлтай урт хугацааны програмд ийм нарийн цэвэрлэгээг илүү хянах арга бий бөгөөд бид Бүлэг 6-д context manager-ийг гүнзгий судлахдаа энэ сэдэв рүү эргэж ирнэ.
Жишээ 3: ижил шатууд, өөр pipeline
Pipeline-ий шатууд жижиг, бие даасан тул шинэ асуултад шинэ код бичихгүйгээр тэдгээрийг өөрөөр угсарч болдог. Жишээлбэл, хэрэглэгч бүр хэдэн алдаа гаргасныг тоолъё. Шинэ шат ганцхан: мессежээс хэрэглэгчийн нэрийг гаргах.
python
def user_of(record):
first_part = record["message"].split(" ")[0]
return first_part.removeprefix("user=")
lines = read_lines("app.log")
clean = (line for line in lines if line.strip())
records = (parse_line(line) for line in clean)
errors = (r for r in records if r["level"] == "ERROR")
users = (user_of(r) for r in errors)
counts = {}
for user in users:
counts[user] = counts.get(user, 0) + 1
print(counts){'saraa': 1, 'bat': 1}Эхний дөрвөн шат өмнөхтэй үгчлэн ижил. Бид зөвхөн нэг шинэ шат users-ийг нэмж, эцсийн хэрэглэгчийг хэвлэлтийн оронд тоолуур болгосон. user_of() мессежийг зайгаар хувааж, эхний хэсэг “user=saraa”-г аваад, removeprefix() ашиглан “user=” угтварыг арилгана. counts.get(user, 0) нь dict-д тэр хэрэглэгч байхгүй бол 0 буцаадаг, Course 1-2-оос танил загвар.
Эсвэл WARNING мөрүүд хэрэгтэй бол errors шатны нөхцлийг солиход л хангалттай. Мөр уншдаг, цэвэрлэдэг, задалдаг шатууд хэзээ ч өөрчлөгдөхгүй. Конвейерийн ажилчин бүр өөрийн ажлыг мэддэг тул шугамын төгсгөлд шинэ ажилчин нэмэх нь бусдыг дахин сургах шаардлагагүй. Энэ модульчлагдсан чанар нь Түвшин 1-ийн хамтарсан бүтээлд том log файлыг боловсруулахдаа бидний гол хэрэгсэл болох юм.
Хүсвэл app.log-д хэдэн шинэ мөр нэмж, тэдгээрийн нэгийг “2026-10-09 08:20:00 ERROR” гэх мэт мессежгүй, ердөө гурван хэсэгтэй болгоод pipeline-ийг ажиллуулж үзээрэй. Аль шатанд, ямар алдаа гарах вэ гэдгийг эхлээд таамаглаад, дараа нь шалгаж болно. Сонирхвол Жишээ 2-ын чагнууртай хувилбарт next(errors)-ийг хоёр удаа дуудаж, нийт хэдэн мөр уншигдахыг урьдчилан бодоод харьцуулж болно. Мөн шат бүрт өөрийн чагнуурыг нэмж, trace-ийн хүсэлт урсгалыг дэлгэц дээр бүрэн харах нь энэ хичээлийн хамгийн тод баталгаа болно. Эдгээр бүгд санал бөгөөд дараагийн хичээлүүд үүнийг хийсэн гэж үзэхгүй.
ValueError: not enough values to unpack (expected 4, got 1). "Задлах утга хүрэлцэхгүй байна: 4 хүлээсэн, 1 ирсэн" гэсэн утгатай. Энэ нь pipeline-д шатуудын дараалал чухал гэдгийг харуулдаг алдаа. Хэрэв parse шатыг non_empty-ээс өмнө байрлуулбал хоосон мөр задлагдах гэж оролдоно: “”.split(“ “, 3) нь [‘’] буюу ганц хэсэгтэй list буцаах тул дөрвөн хувьсагчид задалж чадахгүй. Traceback parse функцийн задлах мөрийг заана. Шийдэл нь цэвэрлэх шатыг задлах шатнаас өмнө тавих. Ерөнхий дүрэм: шүүх, цэвэрлэх шатууд аль болох эрт, хувиргах шатууд дараа нь.
ValueError: I/O operation on closed file. "Хаагдсан файл дээр оролт гаралтын үйлдэл хийлээ" гэсэн утгатай. Эхний шатыг yield-гүйгээр бичихэд гардаг: def read_lines(path): with open(path) as f: return f. Функц файл объектыг буцаах мөчид with блок дуусч, файл хаагдана, дараагийн шат хаагдсан файлаас унших гэж оролдоно. Яг энэ шалтгаанаар read_lines-д yield ашигласан: yield хүрэх бүрт машин with блок дотор хөлдөж, файлыг нээлттэй байлгадаг. Шийдэл нь эхний шатыг generator функц болгох.
TypeError: string indices must be integers, not ‘str’. “String-ийн индекс бүхэл тоо байх ёстой, ‘str’ биш” гэсэн утгатай. Хачирхалтай санагдах энэ алдаа ихэвчлэн нэг шатанд yield-ийн оронд return бичихэд гардаг. Хэрэв parse функц yield {...} биш return {...} гэж бичигдсэн бол тэр generator биш энгийн функц болж, эхний мөрийн dict-ийг л буцаана. Дараагийн шат for r in records гэж тэр dict дээр давтахад dict-ийн түлхүүрүүд болох “time”, “level”, “message” string-үүд r-д оноогдоно. Дараа нь r[“level”] гэж string-д string индексээр хандах гэж оролдож энэ алдаа гарна. Шийдэл нь бүх шат yield ашиглаж байгааг шалгах. Хэрэв pipeline гэнэт ердөө нэг үр дүн гаргаад зогсвол ч мөн энэ шалтгааныг сэжиглээрэй.
Pipeline юу ч хэвлэхгүй байх. Мессежгүй алдаа, хоёр түгээмэл шалтгаантай. Эхнийх нь эцсийн хэрэглэгч алга: дөрвөн шатыг угсарсан ч for loop эсвэл next() бичээгүй бол машинууд хэзээ ч хөдлөхгүй. Хоёр дахь нь хоосорсон pipeline-ийг дахин ашиглах: for r in errors хоёр удаа бичвэл хоёр дахь удаа юу ч гарахгүй, учир нь бүх дөрвөн машин аль хэдийн дууссан. Pipeline-ийг дахин ажиллуулахын тулд бүх шатыг эхнээс нь дахин угсрах хэрэгтэй, эсвэл угсралтыг нэг функц дотор хийж, тэр функцийг дахин дуудах.
Generator pipeline бол нэг generator-ийн гаралт нөгөөгийн оролт болдог гинжин холбоо юм. Шат бүр нэг энгийн ажил хийж, эх сурвалж нь юу болохыг мэдэхгүйгээр ямар ч iterable-аас уншдаг. Бүх шатыг угсрах үед юу ч ажиллахгүй. Эцсийн хэрэглэгч асуух үед хүсэлт конвейерийн төгсгөлөөс эхлэл рүү урсаж, нэг мөр эхлэлээс төгсгөл рүү дамждаг. Шүүлтүүр шат мөрийг хаяхдаа доод шатнаасаа дахин асуудаг. Trace-ээс бид аль ч мөчид санах ойд зөвхөн хөлдсөн машинууд ба нэг мөрийн өгөгдөл байдгийг харсан. Эрт зогсох үед бүх шат нэг дор зогсож, файлын уншаагүй хэсэг огт хүрэгдэхгүй. Шатуудыг generator функц эсвэл generator expression-оор бичиж, чөлөөтэй хольж болох бөгөөд шатуудын дараалал, ялангуяа цэвэрлэгээ задлалтаас өмнө байх нь чухал.
Энэ хичээлд бид бүх шатыг өөрсдөө бичсэн. Гэвч зарим ажил маш түгээмэл байдаг: эхний N элементийг авах, хэд хэдэн эх сурвалжийг нэг урсгал болгон залгах, хязгааргүй тоолох. Python ийм “lazy” хэрэгслүүдийг бэлэн цуглуулга болгон стандарт сандаа агуулдаг. Дараагийн хичээлд бид тэр хэрэгслийн хайрцаг болох itertools-ийг нээж, count, islice, chain гэсэн гурван хамгийн хэрэгтэй хэрэгсэлтэй танилцана. Өмнөх хичээлийн хязгааргүй numbered generator-ийг аюулгүй таслахын тулд islice яг хэрэгтэй хэрэгсэл болох юм.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.