Python: деректен өз есебіңізге дейін 9-сабақ (барлығы 56)
Функциялар: есепке ат және қате санды ұстайтын assert
Python курсының тоғызыншы сабағы. Қатарды аралау ат алады да, кез келген қатарды санайды: Қазақстан — 11,52%, әлем — 4,68%. Қоса бос қатарда есепті тоқтататын `assert`, `sorted(key=)` ішіндегі `lambda` және өлшенген тұзақ: тақырыптағы `into=[]` мәндерді жинап қояды.
Не үшін керек
Өткен сабақта қатарды аралау бағдарламаның ішінде жазылған еді. Сол есепті екінші қатар бойынша жүргізу үшін оны көшіру керек — сол сәттен бастап сізде екі көшірме болады, әрі олар алғашқы түзетуде-ақ айырылады.
Функция есептің бір кесегіне ат береді. Содан кейін ол қанша керек болса, сонша шақырылады, бір жерде тұрады, бір рет түзетіледі.
Бүгін шығатын екінші нәрсе дерек туралы курста синтаксистен маңыздырақ: есептің ішіндегі тексеру. Қате сан айқайламайды — ол есепке дейін тыныш жетеді де, нағызындай көрінеді. assert — оның жолына бөгет қоюдың алғашқы тәсілі.
Бірден тұтас
func.py файлы. Іске қосу: ортадан python func.py.
Міндеттісі — екі функция мен олардың шақырылуы: def, return, әдепкі мәні бар аргумент және assert. Одан кейінгінің бәрі — lambda, *args, көріну аймағы — төменде бөлек талданады, тапсырмада керегі жоқ.
"""9-сабақ: функция — есептің бір кесегіне берілген ат.
Өткен сабақта қатарды аралау бағдарламаның ішінде жазылған еді. Сол есепті
екінші қатармен жүргізу үшін оны көшіруге тура келер еді. Мұны ат шешеді.
"""
# Жылдық инфляция, %: Қазақстан және әлем. Сандар бірінші сабақтан, Дүниежүзілік банк.
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}
def average(series):
"""Қатардың орташасы; саны жоқ жылдар есепке кірмейді."""
total = 0.0
count = 0
for value in series.values():
if value is None:
continue
total += value
count += 1
assert count > 0, "қатарда бірде-бір сан жоқ"
return total / count
def above(series, other, since=2021):
"""Since жылынан бастап бірінші қатар екіншісінен жоғары болған жылдар.
Екі қатардың бірінде саны жоқ жыл есепке кірмейді.
"""
years = []
for year, value in series.items():
if year < since or value is None or other.get(year) is None:
continue
if value > other[year]:
years.append(year)
return years
print("== бес жылдың орташасы")
print(f"Қазақстан: {average(kz):.2f}%")
print(f"әлем: {average(world):.2f}%")
print()
print("== әлемдікінен жоғары жылдар")
print("бәрі: ", above(kz, world))
print("2023-тен:", above(kz, world, since=2023))
print()
print("== ең жоғары үш жыл")
pairs = []
for year, value in kz.items():
if value is not None:
pairs.append((year, value))
top = sorted(pairs, key=lambda pair: pair[1], reverse=True)
print(top[:3])
Шығатыны:
== бес жылдың орташасы
Қазақстан: 11.52%
әлем: 4.68%
== әлемдікінен жоғары жылдар
бәрі: [2021, 2022, 2023, 2024, 2025]
2023-тен: [2023, 2024, 2025]
== ең жоғары үш жыл
[(2022, 15.0), (2023, 14.5), (2025, 11.4)]
Талдау
def, шегініс және return
def average(series):
...
return total / count
def ат жасайды, жақшалар аргументтерді тізеді, қос нүкте мен шегініс денені береді — if пен for-дағыдай. return мәнді сыртқа шығарады да, функцияның жұмысын сол жерде бітіреді: одан кейінгі жолдар орындалмайды.
return-сіз функция да жұмыс істейді, бірақ None қайтарады — жетінші сабақтағы сол «сан жоқ». Ұмытылған return қате бермейді, есепте бос орын береді, ал оны кейін ұзақ іздейді.
def-тен кейінгі үш тырнақшадағы жол — docstring, функцияның сипаттамасы. Оны файл басында көрдік; мұнда ол бағдарламаны емес, бір кесекті түсіндіреді, әрі функцияның жетіспейтін мәндермен не істейтінін жазатын жер де осы.
Айту аз, істеу керек. above ішінде жетіспейтін мән екі жағынан да тексеріледі: other.get(year) is None «бөтен қатарда жыл жоқ» дегенді де, «жыл бар, саны жоқ» дегенді де жабады. Тек өз қатарымызды тексерсек, value > other[year] бір күні None-ға тап болып, жауаптың орнына TypeError-мен құлар еді. Жетіспейтін мәнтармен жұмыс істеймін деп уәде берген функция өзіне жететін жетіспейтін мәндің бәрін білуге міндетті.
Елестетіп көріңіз. Аты бар рецепт. Ол басыңызда тұрғанда, оны әр жолы қайта айтып бересіз; жазылып, ат алғаннан кейін бір сөзбен беріледі.
Әдепкі мәні бар аргумент және атымен шақыру
def above(series, other, since=2021):
since=2021 — әдепкі мән: онсыз шақырдыңыз, сонымен алдыңыз. above(kz, world, since=2023) аргументті атымен береді, әрі шақыруда 2023 дегеннің не екені көрініп тұр.
Бұл әдетке тұрарлық: above(kz, world, 2023) дәл солай жұмыс істейді, бірақ оқитын адам үшінші аргументтің не болғанын есінде ұстауға тиіс. Шақырудағы ат сол күшті үнемдейді.
Тұзақ: функция тақырыбындағы into=[]
Әдепкі мән Python def-ті оқығанда бір рет есептеледі, әр шақыруда емес. Сан үшін бұл байқалмайды, тізім үшін — апат:
def bad(value, into=[]):
into.append(value)
return into
bad(1) → [1]
bad(2) → [1, 2] ← өткен жолғы сол тізім
Екінші шақыру ішінде бөтен мәні бар тізім алды. Дұрысы былай:
def good(value, into=None):
if into is None:
into = []
into.append(value)
return into
good(1) → [1]
good(2) → [2]
Ереже қарапайым: функция тақырыбында әдепкі мән ретінде тек өзгермейтін нәрсе тұрады — сан, жол, None. Тізім, сөздік және жиынды ішінде жасайды.
assert: қате пайда болған жерде тоқтау
assert count > 0, "қатарда бірде-бір сан жоқ"
assert сіз сенген нәрсені тексереді, ал ол шындық болмаса — бағдарламаны сіздің мәтініңізбен тоқтатады:
AssertionError: бос қатар
Онсыз average бос қатарда бір қабат төменде нөлге бөлумен құлар еді — дерек туралы емес, бөлу туралы хабармен. assert қатені пайда болған жерінде ұстайды да, адамның тілімен айтады.
Әрі маңызды ескерту. assert — есеп туралы өз болжамыңызды тексеру, пайдаланушы жібергенді тексеру емес: python -O арқылы іске қосу оларды түгел өшіреді. Бөтен файлдан келген деректі кәдімгі if-пен әрі түсінікті қатемен тексереді; assert «мұндай болуы мүмкін емес, ал мүмкін болса, мен бірден білгім келеді» деген жерде тұрады.
lambda мен key=: тізім сабағындағы уәде
top = sorted(pairs, key=lambda pair: pair[1], reverse=True)
Тізім сабағында кортеждерді itemgetter арқылы сұрыптап, өз функциямызды жазуға уәде еткен едік. Міне ол: lambda pair: pair[1] — жұпты алып, одан екінші элементті беретін атсыз функция. sorted оны әр элемент үшін шақырады да, қайтарғаны бойынша сұрыптайды.
Дәл сол нәрсені def арқылы да жазуға болады, әрі бір жолдан ұзын нәрсе үшін солай істейді. lambda функция өз атынан қысқа болған жерде ғана орынды.
Қанша керек, сонша аргумент: *args пен **kwargs
Кейде қанша мән келетіні алдын ала белгісіз:
def report(title, *values, **options):
digits = options.get("digits", 1)
out = []
for value in values:
out.append(f"{value:.{digits}f}")
return f"{title}: " + ", ".join(out)
report("инфляция", 8.0, 15.0, 14.5) → инфляция: 8.0, 15.0, 14.5
report("инфляция", 8.0, 15.0, digits=2) → инфляция: 8.00, 15.00
Бір жұлдызша артық позициялық аргументтерді кортежге жинайды, екеуі — аталғандарын сөздікке. args пен kwargs деген аттар — тек дәстүр; жұмыс істейтіні — жұлдызшалар.
Мұны өз кодыңызда сирек қолданасыз, ал оқитыныңыз жиі: бөтен кітапханалардағы функциялардың жартысы солай құрылған.
Функция ішіндегі ат — өзінікі
count = 0
def bump():
count = count + 1
bump()
→ UnboundLocalError: cannot access local variable 'count' where it is not associated with a value
Функция ішіндегі меншіктеу жаңа, жергілікті ат жасайды. Python денедегі count = ... дегенді көреді де, count-ты бүкіл функцияда жергілікті деп санайды — оны меншіктеуге дейін оқығысы келген жолды қоса.
global сөзі мұны өшіреді, бірақ дұрыс жауап дерлік әрқашан басқа: мәнді аргументпен қабылдап, нәтижені қайтару. Сырттағы ештеңеге тимейтін функция бір шақырумен тексеріледі — бүгінгі сабақтың мәнінің жартысы да сол.
Сабақ картасы
Өз сөзіңізбен айтыңыз
Қарамай, дауыстап немесе қағазға жауап беріңіз. Жауаптары — сабақтың соңында.
- Ішінде
returnжоқ функция не қайтарады? - Функция тақырыбындағы
into=[]неге қате, алinto=Noneнеге дұрыс? assert-тің деректіif-пен тексеруден айырмасы неде?
Жаттығу
Тапсырмаға дейінгі үш қысқа қадам: болжау, толықтыру, жөндеу. Жауаптары — сабақтың соңында, бірақ алдымен өзіңіз жауап беріңіз.
1. Болжаңыз. Бұл бағдарлама не басып шығарады?
def average(series):
total = 0.0
count = 0
for value in series:
if value is None:
continue
total += value
count += 1
return total / count
print(average([8.0, None, 15.0]))
2. Бос орынды толтырыңыз. ... орнына шартты қойыңыз: саны бар және ол шектен үлкен болса, жыл алынады.
def above(series, limit):
years = []
for year, value in series.items():
if ...:
years.append(year)
return years
print(above({2024: 8.7, 2025: 11.4, 2026: None}, 10))
3. Жөндеңіз. Бағдарлама алдымен санды, содан кейін None басып шығарады. Себебін түсіндіріп, екінші жол орташаны көрсететіндей етіңіз.
def average(series):
print(sum(series) / len(series))
result = average([8.0, 15.0])
print("орташа:", result)
Тапсырма
Міндетті. Берілгені:
kz = {2023: 14.5, 2024: 8.7, 2025: 11.4, 2026: None}
world = {2023: 5.8, 2024: 3.0, 2026: 2.9}
average(series) жасаңыз — қатар бойынша орташа, жетіспейтін мәндер есепке кірмейді, бос қатарды түсінікті мәтіні бар assert тоқтатады. above(series, other) жасаңыз — бірінші қатар екіншісінен жоғары болған жылдар; екі қатардың бірінде саны жоқ жыл есепке кірмейді. Әр қатардың орташасын екі таңбамен және жылдар тізімін басып шығарыңыз.
Күтілетін шығу:
Қазақстан бойынша орташа: 11.53
әлем бойынша орташа: 3.90
әлемдіктен жоғары: [2023, 2024]
Дайын болғаны: шығу жол-жолмен сәйкес келеді; average екі рет жазылмай, екі рет шақырылған; above екі жағында да None тұрған 2026 жылда құламайды, әрі екінші қатарда жоқ 2025-ті алмайды.
Өз деректеріңізде. Өткен сабақтағы өз қатарыңызға average(series) функциясын жасаңыз: жетіспейтін мәндер есепке кірмейді, бос қатарды түсінікті мәтіні бар assert тоқтатады. Екіншісін — above(series, limit) — жасаңыз: ол мәні limit-тен үлкен кілттердің тізімін қайтарсын, әрі оны әртүрлі шекпен екі рет шақырыңыз.
Мұның бәрі step-3 ішінде жиналған — өзіңіз жазып болғаннан кейін салыстырыңыз.
Қалауыңызша.
average-геdigits=2аргументін қосып, нәтижені дөңгелектеңіз.- Өз жұптарыңызды
sorted(key=lambda ...)арқылы мәні бойынша да, кілті бойынша да сұрыптаңыз. into=[]бар функция жазып, оны үш рет шақырыңыз да, не жиналғанын қараңыз.
Жобада бұл қайда тұрады
Шолу алғашқы аттарын алады: «қатардың орташасы», «нормадан жоғары жылдар». Әрі қарай олар бөлек файлға көшіп, модуль болады, ал басты бағдарламадағы есеп үш жол болып қалады.
Қарыздар. Тексеруіміз әзірге біреу әрі есептің ішінде тұр. Нағыз тексерулер өздері тексеретін кодтан бөлек тұрады; pytest-ке курстың соңында жетеміз, бірақ керекті жердегі assert бүгіннің өзінде жұмыс істейді.
Жауаптар
Жауаптарды көрсету
Сұрақтарға
None.return-сіз функция аяғына дейін орындалады да, бос мән қайтарады — қате емес, сондықтан ұмытылғанreturnбірден көрінбейді.- Өйткені әдепкі мән бір рет,
defоқылғанда есептеледі. Сонда жасалған тізім шақырулар арасында өмір сүреді де, ішіне бөтен мәндерді жинайды;Noneөзгермейді, ал жаңа тізім әр шақыруда ішінде жасалады. assertавторлың есеп туралы болжамын тексереді әріpython -Oарқылы іске қосқанда өшеді. Сырттан келген деректі түсінікті қатесі бар кәдімгіif-пен тексереді — олардаassert-ке сүйенуге болмайды.
Жаттығуға
11.5. Жетіспейтін мән сомаға да, санауышқа да кірмеді, сондықтан23.0үшке емес, екіге бөлінеді.
11.5
value is not None and value > limit. Рет маңызды: салыстыруды бірінші қойсаңыз, жетіспейтін мәнде бағдарлама құлайды —None > 10дегенді салыстыруға болмайды.
def above(series, limit):
years = []
for year, value in series.items():
if value is not None and value > limit:
years.append(year)
return years
print(above({2024: 8.7, 2025: 11.4, 2026: None}, 10))
[2025]
- Функция басып шығарады, бірақ ештеңе қайтармайды, ал
return-сіз функцияNoneқайтарады — оныresultалды. Басып шығару мен қайтару — екі бөлек нәрсе: басып шығару адамға көрсетеді,returnбағдарламаға береді.
def average(series):
return sum(series) / len(series)
result = average([8.0, 15.0])
print("орташа:", result)
орташа: 11.5
Пікірлер (0)
Пікір қалдыру үшін кіріңіз →
Әзірге пікір жоқ. Бірінші болыңыз.