Ачааллж байна...
Курс 1-д та loop бичихдээ хоёр удаа дараа нэг эвгүй байдалтай тулгарсан байх. Эхнийх нь: жагсаалтын элементүүдийг дугаарлан хэвлэхийг хүсэхэд for loop нь танд элементийг өгдөг ч түүний ДУГААРЫГ өгдөггүй. Тиймээс та dugaar = 0 гэсэн хувьсагч loop-оос гадуур үүсгээд, loop дотор нь dugaar = dugaar + 1 гэж гараар нэмэгдүүлдэг байсан. Хоёр дахь нь: танд хоёр зэрэгцээ жагсаалт байхад (нэрс болон оноо гэх мэт) тэдгээрийг хамт явуулах цэвэрхэн арга олдохгүй, тиймээс та range(len(...)) ашиглаж index-ээр нь хоёуланд нь хандах болдог байсан.
Эдгээр хоёр асуудал нь эхлэгчийн бичдэг кодын хамгийн танигдсан шинж тэмдэг юм. Аль аль нь ажилладаг, гэхдээ аль аль нь Python-ы хувьд шаардлагагүй. Python-д яг эдгээр хоёр асуудлыг цэвэрхэн шийддэг хоёр built-in функц байдаг: enumerate ба zip. Тэдгээр нь Python-той хамт ирдэг тул суулгах шаардлагагүй, import хийх ч хэрэггүй — шууд ашиглаж болно.
Энэ хичээлийн зорилго бол таны loop бичих зуршлыг бүрмөсөн шинэчлэх явдал. Хичээл дуусахад та гараар тоолуур нэмэгдүүлэх, range(len(...)) бичих шаардлагагүй болно — тэдгээрийг харах бүрдээ "аан, энд enumerate байх ёстой байсан" гэж бодох болно.
enumerate-ийг ингэж төсөөлье. Танд ном байна, та түүнийг уншиж эхэллээ. Ердийн for loop бол хуудсуудыг эргүүлж, агуулгыг нь уншиж өгдөг туслах юм — тэр танд текстийг өгнө, гэхдээ хуудасны дугаарыг хэлэхгүй. Enumerate бол яг ижил туслах, гэхдээ хуудас бүрийг өгөхдөө "энэ гурав дахь хуудас" гэж хамт хэлж өгдөг. Танд нэмэлт зүйл хийх шаардлагагүй, тоолох ажлыг тэр өөрөө хийж байна.
zip-ийг ингэж төсөөлье. Танд хоёр цуваа хүн байна — нэг эгнээнд сурагчид, нөгөө эгнээнд тэдний дэвтэрүүд. Та тус тусад нь эргэж явахын оронд, тэдгээрийг хос хос болгож нийлүүлмээр байна: эхний сурагч эхний дэвтэртэйгээ, хоёр дахь сурагч хоёр дахь дэвтэртэйгээ. Zip бол яг тэр нийлүүлэгч. Нэр нь ч санамсаргүй биш — англиар zip гэдэг нь цамцны цахилгаан товч, тэр нь хоёр талын шүдийг ээлжлэн нийлүүлдэг.
Эхлээд Курс 1-ийн аргаар. Дэлгүүрийн барааны жагсаалтыг дугаартай нь хэвлэе.
python
baraanuud = ["ном", "утас", "харандаа"]
dugaar = 1
for baraa in baraanuud:
print(dugaar, baraa)
dugaar = dugaar + 1Хэвлэгдэх үр дүн:
1 ном
2 утас
3 харандааЭнэ код зөв ажиллаж байна. Гэхдээ хоёр мөр нь бүхэлдээ "тоолох" гэсэн туслах ажилд зориулагдсан: dugaar = 1 ба dugaar = dugaar + 1. Тэдгээр нь программын жинхэнэ санааг илэрхийлэхгүй, зөвхөн механик ажил. Хэрэв та dugaar = dugaar + 1 мөрийг мартвал бүх мөр 1 гэсэн дугаартай хэвлэгдэнэ — маш түгээмэл, маш ядаргаатай алдаа.
Одоо enumerate-ээр:
python
baraanuud = ["ном", "утас", "харандаа"]
for dugaar, baraa in enumerate(baraanuud, start=1):
print(dugaar, baraa)Яг ижил үр дүн:
1 ном
2 утас
3 харандааГурав дахь мөрийг нарийвчлан задалъя, учир нь энэ бол хичээлийн гол мөр.
enumerate(baraanuud) гэдэг нь "энэ жагсаалтыг ав, элемент бүрийг өгөхдөө түүний дугаартай нь ХАМТ өг" гэсэн үг. Тэгэхээр loop эргэх бүрд НЭГ биш ХОЁР зүйл ирж байна: эхлээд дугаар, дараа нь элемент. Тиймээс for мөрөнд бид хоёр нэр бичиж байна: for dugaar, baraa in .... Эхний нэр (dugaar) нь дугаарыг, хоёр дахь нэр (baraa) нь элементийг хүлээж авна. Энэ дараалал ТОГТМОЛ — enumerate үргэлж дугаарыг эхэлж өгдөг.
start=1 гэдэг нь "тоолохоо 1-ээс эхэл" гэсэн заавар. Хэрэв та үүнийг бичихгүй бол enumerate нь анхдагчаар тэгээс эхэлдэг, учир нь Python-д index бол үргэлж тэгээс эхэлдэг. Хүнд харуулах дугаар ихэвчлэн нэгээс эхлэх ёстой тул start=1 гэж бичих нь маш түгээмэл.
Одоо хоёр туслах мөр бүхэлдээ алга болсныг анзаараарай. Гурван мөр байсан код хоёр мөр болж, түүнээс ч чухал нь, "тоолуур мартах" гэсэн бүхэл ангиллын алдаа боломжгүй болсон.
Заримдаа танд жинхэнэ index хэрэгтэй болдог — өөрөөр хэлбэл жагсаалтад дахин хандахад ашиглаж болох дугаар. Тэр тохиолдолд start= бичихгүй, тэгээс эхлүүлнэ.
python
neres = ["болд", "сараа", "төмөр"]
for i, ner in enumerate(neres):
print(f"index {i} дээр {ner} байна")Үр дүн:
index 0 дээр болд байна
index 1 дээр сараа байна
index 2 дээр төмөр байнаЭнд i гэсэн нэр ашигласныг анзаараарай. Программистууд index-ийг ихэвчлэн i гэж нэрлэдэг заншилтай — энэ нь дэлхий нийтийн зуршил тул та бусдын кодод байнга харах болно. Одоо neres[i] гэж бичээд яг тэр элементэд дахин хандаж болно, гэхдээ ихэнхдээ шаардлагагүй, учир нь элемент нь ner гэсэн нэрээр аль хэдийн гарт тань байгаа.
Энд Курс 1-ийн муу зуршлыг харьцуулъя. Өмнө нь та index хэрэгтэй үедээ ингэж бичдэг байсан байх:
python
neres = ["болд", "сараа", "төмөр"]
for i in range(len(neres)):
print(f"index {i} дээр {neres[i]} байна")Энэ ажиллана. Гэхдээ анзаараарай: та neres[i] гэж бичих бүрдээ жагсаалтад дахин хандаж байна. Мөн range(len(...)) гэсэн бичлэг нь уншигчаас нэмэлт бодол шаарддаг — "аан, len нь урт, range нь тэр урт хүртэлх тоонууд, тэгэхээр энэ бол index-үүд." Enumerate нь энэ бүх дундын алхмыг арилгаж, шууд хэрэгтэй хоёр зүйлийг өгдөг. Мэргэжлийн Python код дотор range(len(...)) харагдвал тэр нь бараг үргэлж enumerate байх ёстой байсан гэсэн шинж юм.
Өмнөх хоёр хичээлээс comprehension-ыг санаж байгаа байх. Enumerate түүн дотор ч ажиллана:
python
neres = ["болд", "сараа", "төмөр"]
dugaartai = [f"{i}. {ner}" for i, ner in enumerate(neres, start=1)]
print(dugaartai)Үр дүн:
['1. болд', '2. сараа', '3. төмөр']for хэсэгт хоёр нэр (i, ner) авч байгаа нь энгийн loop-той яг ижил бичлэг. Comprehension бол loop-ийн өөр илэрхийлэл тул тэнд ажилладаг бүхэн энд ч ажиллана — энэ бол Python-ы тууштай байдлын сайхан жишээ.
Одоо zip рүү орно. Танд хоёр зэрэгцээ жагсаалт байна: сурагчдын нэрс, тэдний оноо. Хоёуланг нь хамт хэвлэхийг хүсэж байна.
Курс 1-ийн аргаар:
python
neres = ["болд", "сараа", "төмөр"]
onoo = [85, 92, 78]
for i in range(len(neres)):
print(f"{neres[i]}: {onoo[i]} оноо")Үр дүн:
болд: 85 оноо
сараа: 92 оноо
төмөр: 78 онооЭнэ код ажиллана, гэхдээ хэдэн сул тал байна. Нэгдүгээрт, neres[i] ба onoo[i] гэж хоёр удаа index-ээр хандаж байна — уншихад чимээ шуугиантай. Хоёрдугаарт, энэ код neres ба onoo хоёр ижил урттай гэдэгт БҮРЭН найдаж байна. Хэрэв onoo нь нэг элемент дутуу байвал IndexError гарч программ унана. Гуравдугаарт, range(len(...)) дахин гарч ирлээ — бид түүнийг арилгахаар шийдсэн шүү дээ.
Одоо zip-ээр:
python
neres = ["болд", "сараа", "төмөр"]
onoo = [85, 92, 78]
for ner, o in zip(neres, onoo):
print(f"{ner}: {o} оноо")Яг ижил үр дүн:
болд: 85 оноо
сараа: 92 оноо
төмөр: 78 онооzip(neres, onoo) гэдэг нь "энэ хоёр жагсаалтыг зэрэгцүүлж, нэг нэгээр нь хос болгож өг" гэсэн үг. Loop эргэх бүрд нэг хос ирнэ: эхний жагсаалтын элемент, хоёр дахь жагсаалтын элемент. Тиймээс for ner, o in ... гэж хоёр нэр бичиж байна. ner нь neres-ээс, o нь onoo-оос ирнэ — дараалал нь zip() дотор бичсэн дараалалтай яг таарна.
Index бүрмөсөн алга болсныг анзаараарай. Та жагсаалтад дахин хандахгүй, зөвхөн ирсэн утгуудыг л ашиглаж байна. Код цэвэрхэн болоод зогсохгүй, аюулгүй ч болсон — яагаад гэдгийг одоо үзье.
Хэрэв хоёр жагсаалт ижил урттай биш бол zip юу хийх вэ? Хариулт нь чухал бөгөөд заримдаа гэнэтийн:
python
neres = ["болд", "сараа", "төмөр", "цэцэг"]
onoo = [85, 92]
for ner, o in zip(neres, onoo):
print(f"{ner}: {o} оноо")Үр дүн:
болд: 85 оноо
сараа: 92 онооZip нь хамгийн БОГИНО жагсаалт дуусахад зогсдог. төмөр ба цэцэг хоёр огт хэвлэгдээгүй, ямар ч алдаа гараагүй, ямар ч анхааруулга байхгүй. Zip зүгээр л чимээгүйхэн зогсоод өнгөрсөн.
Энэ зан төлөв нь сайн ч муу ч байж болно. Сайн тал нь: программ унахгүй, IndexError гарахгүй. Муу тал нь: та өгөгдлөө алдсанаа мэдэхгүй өнгөрч болно. Хэрэв та хоёр жагсаалт ижил урттай байх ЁСТОЙ гэж бодож байгаа бол zip таны алдааг нуух болно.
Тиймээс сайн зуршил бол: хэрэв урт нь заавал таарах ёстой бол өөрөө шалга.
python
neres = ["болд", "сараа", "төмөр", "цэцэг"]
onoo = [85, 92]
if len(neres) != len(onoo):
print("Анхаар: жагсаалтуудын урт таарахгүй байна")
for ner, o in zip(neres, onoo):
print(f"{ner}: {o} оноо")Ингэснээр програм ажиллах ч, та юу болж байгааг мэдэж байх болно.
Өмнөх хичээлд бид zip-ийг comprehension дотор ашигласан. Одоо та түүнийг бүрэн ойлгож байгаа тул тэр кодыг эргэж хараад ойлгомжтой байх ёстой:
python
neres = ["болд", "сараа", "төмөр"]
onoo = [85, 92, 78]
duen = {ner: o for ner, o in zip(neres, onoo)}
print(duen)Үр дүн:
{'болд': 85, 'сараа': 92, 'төмөр': 78}Мөн шүүлт нэмж болно — жишээ нь тэнцсэн (60-аас дээш) сурагчдын нэрсийг л авъя:
python
neres = ["болд", "сараа", "төмөр", "цэцэг"]
onoo = [85, 45, 78, 30]
tentssen = [ner for ner, o in zip(neres, onoo) if o >= 60]
print(tentssen)Үр дүн:
['болд', 'төмөр']Энэ нэг мөрийг үг үгээр нь уншъя: "neres ба onoo-г хос хосоор нь ав (zip), хос бүрийн хувьд хэрэв оноо нь 60-аас дээш бол (if o >= 60), нэрийг нь ав (ner)." Бүлэг 2-ын гурван хичээл нэг мөрөнд нийллээ.
Zip нь хоёр жагсаалтаар хязгаарлагдахгүй. Хэдийг ч зэрэгцүүлж болно:
python
neres = ["болд", "сараа"]
onoo = [85, 92]
angi = ["10а", "10б"]
for ner, o, a in zip(neres, onoo, angi):
print(f"{ner} ({a} анги): {o} оноо")Үр дүн:
болд (10а анги): 85 оноо
сараа (10б анги): 92 онооГурван жагсаалт → for мөрөнд гурван нэр. Дүрэм нь маш энгийн: zip() дотор хэдэн жагсаалт байна, төдөн нэр бичнэ. Гэхдээ практикт гурваас дээш бол код уншихад хэцүү болж эхэлдэг — тэр үед dictionary эсвэл dataclass (Бүлэг 9) ашиглах нь илүү зөв шийдэл байдаг.
Заримдаа танд хоёулаа хэрэгтэй болдог — зэрэгцүүлсэн өгөгдөл БА дугаар.
python
neres = ["болд", "сараа", "төмөр"]
onoo = [85, 92, 78]
for i, (ner, o) in enumerate(zip(neres, onoo), start=1):
print(f"{i}. {ner}: {o} оноо")Үр дүн:
1. болд: 85 оноо
2. сараа: 92 оноо
3. төмөр: 78 онооЭнэ мөр эхэндээ жаахан төвөгтэй харагдаж магадгүй тул анхааралтай задалъя. Дотор нь zip(neres, onoo) нь хос хосыг үүсгэж байна. Түүнийг enumerate(...) нь тойрч аваад, хос бүрд дугаар нэмж байна. Тэгэхээр loop эргэх бүрд ирж байгаа зүйл нь: дугаар, дараа нь ХОС. Тиймээс зүүн талд i, (ner, o) гэж бичсэн — i нь дугаар, хаалт доторх (ner, o) нь хос.
Хаалт нь заавал байх шаардлагагүй (Python i, ner, o гэж бичсэн ч ойлгоно), гэхдээ хаалттай бичих нь уншигчид бүтцийг илүү тодорхой харуулдаг тул би түүнийг зөвлөж байна.
Хэрэв сонирхвол: өөрийн Курс 1-д бичсэн программуудаа нээгээд range(len( гэсэн бичлэг хайж үзээрэй. Олдсон бүр нь enumerate эсвэл zip болж хувирах боломжтой байх магадлалтай. Нэгийг нь сонгоод хувиргаж, программ хэвээрээ ажиллаж байгаа эсэхийг шалгаад үзээрэй.
Мөн хүсвэл: list(zip([1, 2, 3], ["а", "б", "в"])) гэж бичээд хэвлэж үзээрэй. Zip нь юу үүсгэдгийг өөрийн нүдээр харах болно — тэр нь хосуудын жагсаалт байх ба хос бүр нь tuple гэдэг бүтэц юм. Tuple-ийг Бүлэг 5-д зохих ёсоор нь үзнэ, одоохондоо "өөрчлөгдөшгүй хос" гэж ойлгоод өнгөрөөрэй.
1. enumerate-ээс нэг л нэр авах
python
for baraa in enumerate(baraanuud):
print(baraa)(0, 'ном')
(1, 'утас')
(2, 'харандаа')Алдааны мессеж гарахгүй, гэхдээ үр дүн нь таны хүссэн зүйл биш. Enumerate ХОС өгдөг тул нэг л нэр авбал тэр нэр хос бүхэлдээ болно. Дараа нь print(baraa) хийхэд хаалттай хос хэвлэгдэнэ. Засвар: for dugaar, baraa in enumerate(...) гэж хоёр нэр авна.
2. zip-ийн үр дүнг хоёр удаа ашиглах
python
hosud = zip(neres, onoo)
for ner, o in hosud:
print(ner, o)
for ner, o in hosud:
print("дахин:", ner, o)Эхний loop ажиллана, хоёр дахь loop нь ЮУ Ч ХЭВЛЭХГҮЙ. Алдаа гарахгүй, зүгээр л чимээгүй хоосон.
Шалтгаан нь: zip нь жинхэнэ жагсаалт биш, харин "нэг удаа урсаж өнгөрдөг" зүйл үүсгэдэг. Эхний loop түүнийг бүрэн уншиж дуусгасан тул хоёр дахь loop-д юу ч үлдээгүй. (Энэ зан төлөвийн жинхэнэ шалтгааныг Бүлэг 13-д iterator үзэх үед бүрэн ойлгоно.) Хэрэв танд үр дүн олон удаа хэрэгтэй бол list() дотор оруулж жинхэнэ жагсаалт болгоно:
python
hosud = list(zip(neres, onoo))Одоо хоёр loop хоёулаа ажиллана.
3. zip-ийн дарааллыг андуурах
python
for o, ner in zip(neres, onoo):
print(f"{ner}: {o} оноо")85: болд оноо
92: сараа онооАлдаа гарахгүй, гэхдээ үр дүн нь толгойгоороо эргэсэн байна. Шалтгаан нь: zip(neres, onoo) гэж бичсэн тул эхний утга нь neres-ээс, хоёр дахь нь onoo-оос ирнэ. Гэтэл for o, ner in ... гэж эсрэгээр нь нэрлэсэн байна. Засвар: zip() дотор бичсэн дараалал ба for мөрөнд бичсэн нэрсийн дараалал ЯГ таарах ёстой.
4. enumerate-д start мартах
python
for dugaar, baraa in enumerate(baraanuud):
print(dugaar, baraa)0 ном
1 утас
2 харандааАлдаа биш, гэхдээ хүнд харуулах жагсаалт тэгээс эхэлж байна — ихэнхдээ тийм байхыг хүсдэггүй. Хэрэв дугаар нь хүнд зориулагдсан бол start=1 бич. Хэрэв тэр нь жинхэнэ index бол тэгээс эхлэх нь зөв.
enumerate(жагсаалт) нь элемент бүрийг дугаартай нь хамт өгдөг. Loop-д хоёр нэр авна: for i, элемент in enumerate(...).
start=1 бичвэл нэгээс эхэлж тоолно; бичихгүй бол тэгээс.
zip(жагсаалт1, жагсаалт2) нь хоёр (эсвэл хэдэн ч) жагсаалтыг зэрэгцүүлж хос хосоор өгдөг.
Zip нь хамгийн БОГИНО жагсаалт дуусахад чимээгүйхэн зогсдог — урт нь таарах ёстой бол өөрөө шалга.
Хоёулаа comprehension дотор ажиллана.
Кодод range(len(...)) харагдвал тэр нь бараг үргэлж enumerate эсвэл zip байх ёстой байсан гэсэн шинж. Гараар тоолуур нэмэгдүүлэх шаардлага бүрмөсөн алга болно.
Дараагийн хичээлд бид slicing-ийг гүнзгий үзнэ. Курс 1-д та string-ээс нэг үсэг авахдаа ner[0] гэж бичдэг байсан. Одоо та жагсаалт болон string-ээс БҮХЭЛ ХЭСГИЙГ нь огтолж авах, ард нь эхнээс нь тоолох, алгасаж авах, бүр эргүүлж хөмрөх аргуудыг сурна. Тэнд нэг гэнэтийн зүйл ч бас байгаа: slicing нь IndexError гаргадаггүй — тэр яагаад тэгдгийг тайлбарлана.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.