Shanraq.org Shanraq.org
Циклдер: for, range және zip үнсіз істейтін нәрсе
IT

Python: деректен өз есебіңізге дейін 8-сабақ (барлығы 56)

Циклдер: for, range және zip үнсіз істейтін нәрсе

Python курсының сегізінші сабағы. Отыздың орнына бір салыстыру: цикл қатарды өзі аралайды, `continue` дерегі жоқ жылды аттайды, жинақтауыш орташаны санайды — бес жылда 11,52%. Қоса екі тұзақ: `zip` қатарды қысқасы бойынша үнсіз қияды, ал шығуы жоқ `while` шеттен өтіп құлайды.

Не үшін керек

Өткен сабақта бір салыстыру үш рет жазылған еді. Бес жыл — он бес жол, отыз жыл — оқуға да, түзетуге де келмейтін бағдарлама.

Цикл қайталауды түбегейлі жояды: ереже бір рет жазылады, ал қатардағы жол қанша болса да болады. Нағыз деректегі жұмыс осыдан басталады — онда үш сан емес, мыңдаған сан бар.

Бүгін циклдің үнсіз қателесетін екі орны да шығады. Екеуі де біздің қатарда өлшенді, екеуін де бірден есте сақтаған жөн.

Бірден тұтас

cikl.py файлы. Іске қосу: ортадан python cikl.py.

Бағдарлама бұрынғылардан ұзын — қырық төрт жол. Міндеттісі — бірінші блок: қатарды аралау, continue және жинақтауыш. Қалған үшеуі zip, enumerate, break пен while-ды көрсетеді; оларды бет-жүзінен танып қойса жеткілікті, керек болғанда оралуға болады.

"""8-сабақ: цикл — қатарды сіз емес, бағдарлама аралайды.

Өткен сабақта бір салыстыру үш рет жазылған еді. Мұнда ол бір рет жазылады,
ал жыл отыз болса да жарайды.
"""

# Жылдық инфляция, %: Қазақстан және әлем. Сандар бірінші сабақтан, Дүниежүзілік банк.
kz = {2021: 8.0, 2022: 15.0, 2023: 14.5, 2024: 8.7, 2025: 11.4, 2026: None}
world = {2021: 3.5, 2022: 8.1, 2023: 5.8, 2024: 3.0, 2025: 3.0}

print("== бүкіл қатар, олқылық есепке кірмейді")
total = 0.0
count = 0
for year, value in kz.items():
    if value is None:
        print(f"{year}: дерек жоқ")
        continue
    total += value
    count += 1
    print(f"{year}: {value:5.1f}%")
print(f"саны бар жыл: {count}, орташа: {total / count:.2f}%")

print()
print("== екі қатар қатар тұр")
for number, (here, there) in enumerate(zip(kz.values(), world.values()), start=1):
    print(f"{number}. Қазақстан {here:5.1f} | әлем {there:4.1f}")

print()
print("== он пайыздан жоғары алғашқы жыл")
for year in range(2021, 2026):
    if kz[year] > 10:
        print(f"{year}: {kz[year]}%")
        break

print()
print("== соңынан бастап қанша жыл қатарынан әлемдікінен жоғары")
year = 2025
streak = 0
# Шарт жылдың қатарда бар-жоғын да тексереді: онсыз цикл 2020 жылға өтіп,
# KeyError-мен құлайды. for өзі бітеді, while — тек айтқанда ғана.
while year in world and kz[year] > world[year]:
    streak += 1
    year -= 1
print(f"қатарынан: {streak}, соңғы осындай жыл: {year + 1}")

Шығатыны:

== бүкіл қатар, олқылық есепке кірмейді
2021:   8.0%
2022:  15.0%
2023:  14.5%
2024:   8.7%
2025:  11.4%
2026: дерек жоқ
саны бар жыл: 5, орташа: 11.52%

== екі қатар қатар тұр
1. Қазақстан   8.0 | әлем  3.5
2. Қазақстан  15.0 | әлем  8.1
3. Қазақстан  14.5 | әлем  5.8
4. Қазақстан   8.7 | әлем  3.0
5. Қазақстан  11.4 | әлем  3.0

== он пайыздан жоғары алғашқы жыл
2022: 15.0%

== соңынан бастап қанша жыл қатарынан әлемдікінен жоғары
қатарынан: 5, соңғы осындай жыл: 2021

Талдау

for нөмір санамайды, элементті алады

for year, value in kz.items():

Көп тілде цикл санауыш жасап, нөмір бойынша жүреді. Python-да for элементтердің өзін алады: тізімнен — мәндерді, сөздіктен — кілттерді, ал .items()-тен — сол жерде екі айнымалыға жайылатын жұптарды. Бұл — кортеж сабағындағы сол тарқату.

Осыдан қателердің жартысын үнемдейтін ереже шығады: элемент керек болса, нөмірді емес, элементтің өзін алыңыз.

Елестетіп көріңіз. Қолдағы чектер бумасы. Сіз «маған төртінші чекті бер» демейсіз — бума бітпейінше келесісін ала бересіз.

continue аттап өтеді, break тоқтатады

if value is None:
    print(f"{year}: дерек жоқ")
    continue

continue осы айналымды тастап, келесі элементке өтеді. Өткен сабақтағы жетіспейтін мәнмен дәл осы керек: саны жоқ жыл бөлек жолмен басылады да, орташаға кірмейді.

break — басқа нәрсе: ол циклден мүлде шығады. Үшінші блокта ол он пайыздан жоғары алғашқы жылда іріктеуді тоқтатады, сондықтан 2023–2025 жылдар мүлде тексерілмейді.

Жинақтауышты циклге дейін жасайды

total = 0.0
count = 0
for ...:
    total += value
    count += 1

Сырттағы екі айнымалы, ішіндегі += — қатар бойынша есеп деген осы. Оларды циклге дейін жасау міндетті: ішінде олар әр айналымда нөлденіп отырар еді.

Бір емес, екі санды санаймыз: соманы да, санын да. Өйткені бөлу қатардың ұзындығына емес, дерегі бар жылдардың санына жүреді — жетіспейтін мән есепке кірмейді, әрі орташа сондықтан 9,6 емес, 11,52 болып шықты.

zip қысқасы бойынша үнсіз қияды

Шығудың екінші блогына қараңыз: kz ішінде алты жыл болса да, бес жол тұр.

for number, (here, there) in enumerate(zip(kz.values(), world.values()), start=1):

zip қатарларды жұптап қосады да, алдымен бітетінінде тоқтайды. Бізде kz ішінде алты мән, world ішінде бесеу, сондықтан 2026 жыл шығудан жоғалды. Қате де, ескерту де жоқ.

Мұнда бұл орынды: 2026 жылдың саны бәрібір жоқ. Бірақ әдет қауіпті: екі қатар әр дереккөзден келіп, біреуі қысқа болса, zip құйрығын үнсіз қиып тастайды, ал есеп толық емес деректе шығады. Ұзындық маңызды болғанда, оны анық тексереді — len(a) == len(b) — немесе үнсіз қалмай, әртүрлі ұзындықта құлайтын zip(a, b, strict=True) алады.

Ал қиюдан да маңыздысы: zip жылдар бойынша емес, орындар бойынша қосады. Мұнда екі қатардың кілттері де рет-ретімен тұр, сондықтан жұптар дұрыс шықты. Қатарлар әр дереккөзден келсе, кілттердің реті басқа болуы мүмкін, әрі zip 2021 жылды 2022-мен үнсіз жұптайды. Бірдей ұзындық та, strict=True де бұдан құтқармайды: олар элементтерді санайды, кілттерді салыстырмайды.

Осыдан ереже шығады: екі қатарды кілт бойынша салыстырады, орын бойынша емес. Жылдар сол үшін бар: for year in kz: ... world[year]. zip-ті орынның өзі мағына болатын жерде алады — біздің шығудағыдай, онда бір жылдың екі саны қатар басылады, өйткені екі қатар да бір жерден, бір ретпен алынған.

enumerate айналымдарды сіздің орныңызға санайды

enumerate(..., start=1)

Жол нөмірі керек болса, санауышты қолмен жасамаңыз. enumerate «нөмір, элемент» жұбын береді, ал start=1 адамға нөмірлеуді нөлден емес, бірден оқу ыңғайлы екенін айтады.

range — тізім емес, рецепт

for year in range(2021, 2026):

range(2021, 2026) 2021, 2022, 2023, 2024, 2025 жылдарды береді — оң шеті кірмейді, тізім сабағындағы тілімдердегідей. Ереже сол, екінші рет жаттаудың қажеті жоқ.

Маңыздысы: range жадта тізім жасамайды. range(1_000_000) range(5) қанша орын алса, сонша алады — ол сандарды бір-бірлеп береді. Бұл — жалқаулықпен алғашқы кездесу; толығырақ генераторлар сабағында болады.

while тек сіз айтқанда ғана бітеді

while year in world and kz[year] > world[year]:

for өзі бітеді: элементтер таусылды — цикл шықты. while шарт ақиқат болғанша айнала береді, ал шығуды қадағалау сізге қалады.

Бұл бағдарламаның алғашқы нұсқасы year in world-сыз жазылған еді — әрі құлады:

KeyError: 2020

Бес жылдың бәрі әлемдік инфляциядан жоғары болып шықты, цикл 2021 жылға жетті де, қатарда жоқ 2020 жылға аттады, сөйтіп жоқ кілтті сұрады. year in world тексеруі — циклдің тоқтауға тиіс шеті сол.

Сабақ картасы

Сабақ картасы: аралау, аттап өту және шет

Өз сөзіңізбен айтыңыз

Қарамай, дауыстап немесе қағазға жауап беріңіз. Жауаптары — сабақтың соңында.

  1. continue мен break-тің айырмасы неде?
  2. Орташа неге қатардың ұзындығына емес, count-қа бөлумен саналады?
  3. Бір қатар екіншісінен қысқа болса, zip не істейді, әрі мұның қаупі неде?

Жаттығу

Тапсырмаға дейінгі үш қысқа қадам: болжау, толықтыру, жөндеу. Жауаптары — сабақтың соңында, бірақ алдымен өзіңіз жауап беріңіз.

1. Болжаңыз. Бұл бағдарлама не басып шығарады?

total = 0
for value in [8.0, None, 15.0]:
    if value is None:
        continue
    total += value
print(total)

2. Бос орынды толтырыңыз. ... орнына 2021-ден 2025-ке дейінгі жылдарды (соңғысын қоса) басып шығаратын нәрсені қойыңыз.

for year in ...:
    print(year, end=" ")

3. Жөндеңіз. Бағдарлама үш жылдың екеуін ғана басып шығарады. Біріншісі қай жерде жоғалғанын табыңыз.

years = [2021, 2022, 2023]
for i in range(1, len(years)):
    print(years[i])

Тапсырма

Міндетті. Берілгені:

prices = [520.0, 546.0, None, 498.0, 515.0]

Тізімді циклмен аралап, айдың нөмірі (санақ бірден) мен бағасын басып шығарыңыз; саны жоқ айды бөлек жолмен басып, есепке алмаңыз. Соңында саны бар ай нешеу екенін және солар бойынша орташаны басып шығарыңыз. Содан кейін 530-дан қымбат алғашқы айды тауып, нөмірін басыңыз — әрі қарай іздемеңіз.

Күтілетін шығу:

1: 520.0
2: 546.0
3: дерек жоқ
4: 498.0
5: 515.0
саны бар ай: 4, орташа: 519.75
530-дан қымбат алғашқы ай: 2

Дайын болғаны: шығу жол-жолмен сәйкес келеді; жетіспейтін мән сомаға да, санауышқа да кірмеген; алғашқы айды іздеу тізімді соңына дейін аралап шықпай, өзі тоқтайды.

Өз деректеріңізде. Бес-жеті саннан тұратын өз қатарыңызды алыңыз — бір тауардың айлар бойынша бағасын, өз шығындарыңызды, өлшеуге келетін кез келген нәрсені — әрі бір орнына None қойыңыз. Оны циклмен аралаңыз: жетіспейтін мәнді бөлек жолмен басып, есепке қоспаңыз, қалғанының мәнін шығарып, соманы, санын және орташаны санаңыз.

Қалауыңызша.

  • Саны орташадан асқан алғашқы айды break арқылы табыңыз.
  • Екі қатарыңызды zip арқылы қосып, оларды әдейі әртүрлі ұзындықта жасаңыз — қанша жол басылатынын қараңыз.
  • zip(a, b)-ны zip(a, b, strict=True)-мен алмастырып, Python не айтатынын оқыңыз.
  • Екінші қатардағы жұптардың орнын ауыстырып, ұзындығын сол күйінде қалдырыңыз да, шығуға қараңыз: сандар сол, жұптар басқа, қате жоқ.

Жобада бұл қайда тұрады

Шолу қатарда неше жыл барына тәуелді болуын қояды. Бір аралаудың өзі орташаны санайды, ең үлкенін табады, жетіспейтін мәндерды бөлек қояды — бес жыл болса да, отыз жыл болса да.

Қарыздар. Аралау әзірге бағдарламаның ішінде бір кесек болып жазылған: сол есепті екінші қатар бойынша жүргізу үшін оны көшіруге тура келеді. Бұл кесекке ат келесі сабақта беріледі — функция.

Жауаптар

Жауаптарды көрсету

Сұрақтарға

  1. continue осы айналымды тастап, келесі элементке өтеді, цикл жалғаса береді. break циклден мүлде шығады, қалған элементтер тексерілмейді.
  2. Өйткені қатарда саны жоқ жыл бар. Қатардың ұзындығына бөлу жетіспейтін мәнді нөл деп санау болар еді — өткен сабақ дәл сол туралы.
  3. zip қысқа қатарда тоқтайды да, ұзынының құйрығын үнсіз тастайды — қате де, ескерту де жоқ. Қатарлар әр дереккөзден келсе, есеп толық емес деректе шығады; сондықтан ұзындықты не тексереді, не strict=True алады.

Жаттығуға

  1. 23.0. continue ағымдағы айналымды тастап, келесі мәнге өтеді, сондықтан None сомаға кірмейді, ал 8.0 + 15.0 кіреді.
23.0
  1. range(2021, 2026). Оң шекара кірмейді, сондықтан соңғы жылды керегінен бірге артық жазады — жаңадан бастаған адам жылды жоғалтатын алғашқы жер осы.
for year in range(2021, 2026):
    print(year, end=" ")
2021 2022 2023 2024 2025
  1. range(1, len(years)) екінші элементтен басталады: тізімнің санағы нөлден. Нөмірі емес, элементтің өзі керек болса, тізімді тікелей аралайды:
years = [2021, 2022, 2023]
for year in years:
    print(year)
2021
2022
2023

Дереккөздер

Мәтінде қате не теру қатесі кездессе, бізге айтыңыз

Тапсырманы тексеру

Алдымен VS Code-та шешіп, іске қосыңыз — редактор қатені сол жерде көрсетеді. Дайын шешімді осында қойыңыз. Тексеретін — модель: ол қатені атап көрсетеді, бірақ дайын жауапты бермейді.

Тексеру үшін кіру керек. Кіру

Пікірлер (0)

Әзірге пікір жоқ. Бірінші болыңыз.