Кірістірілген және каскадты шарттар
Өткен сабақта бір ғана шартты тексеруді үйрендік: «егер a > 0 болса — мынау, болмаса — анау». Бірақ өмірде шешімдер көбіне бір қадаммен бітпейді: «егер сыртта суық болса — күрте киесің, ал егер сонымен қатар жаңбыр да жауып тұрса — оның үстінен қолшатыр да аласың». Дәл осындай «шарт ішіндегі шартты» бағдарламада қалай жазатынымызды, сонымен қатар екіден көп нұсқадан таңдау керек болғанда не істейтінімізді осы сабақта үйренеміз. Бұл тақырып ҰБТ-да жиі кездеседі: координаталық жазықтықтың ширегін анықтау, бірнеше санатқа бөлу, көп нұсқалы есептер — барлығы дәл осы тақырыпқа негізделген.
Ойланып көр: киім таңдағанда сен алдымен ауа райына қарайсың — суық па, жылы ма? Егер суық болса, бұл жерде шешім бітпейді — тағы бір сұрақ туады: жаңбыр жауып тұр ма? Жаңбыр болса — күрте үстіне қолшатыр да аласың, болмаса — тек күрте жеткілікті.
Мұнда не байқадың? Бірінші шарттың («суық па?») «иә» жауабының ішінде тағы бір шарт («жаңбыр бар ма?») жасырылған. Жауабы — қарапайым: if блогының ішіне тағы бір if жазуға болады. Сыртқы шарт ақиқат болғанда ғана, оның ішінде орналасқан екінші шарт тексеріледі. Осындай, басқа тармақтың ішінде орналасқан тармақты кірістірілген тармақталу дейміз.
Кірістірілген тармақталу — басқа тармақталу бұтақтарының (if немесе else) ішінде орналасқан тармақ. Бір
if операторының ішінде тағы бір if операторы жазылады. Шегініс өлшемі әр деңгейде артады (8 бос орын, 2 деңгей).
Анықтаманы бөлшектеп көрейік: «Басқа тармақтың ішінде орналасқан» — ішкі if сыртқы if-тің (немесе else-тің) блогының бір бөлігі болып саналады, ол сыртқы шарт орындалғанда ғана іске қосылады. «Бір if операторының ішінде тағы бір if» — деңгейлердің саны шектелмеген, бірақ көбінесе 2 деңгеймен шектеледі, өйткені одан көп болса, кодты оқу қиындайды. «Шегініс әр деңгейде артады» — бірінші деңгей 4 бос орын шегінісімен жазылса, екінші деңгей (ішкі if) тағы 4 бос орын қосып, жалпы 8 бос орын шегінісімен жазылады.
Неге дәл осылай ұйымдастырылған? Себебі кейбір шешімдер бір ғана сұрақпен шешілмейді — алдымен бір жалпы сұраққа жауап табу керек, содан кейін сол жауапқа байланысты тағы нақтыланған сұрақ қою керек. Мысалы: «егер ученик 5 сынса оқыса (1-шарт), және сонымен қатар үй жұмысын да тапсырса (2-шарт), оған «үздік» белгісі қойылады». Бұл — екі деңгейлі кірістірілген тармақталудың типтік мысалы.
Кірістірілген тармақталуды бір-бірінің ішінде тұрған қорапшаларға (матрёшкаға) ұқсатуға болады. Сыртқы қорапты ашсаң — оның ішінде тағы кішірек қорап тұр. Дәл осылай, сыртқы шартты «ашқанда», оның ішінен тағы бір шарт шығады.
Мұғалім тақтада қалай шешер еді, дәл солай қадаммен жүрейік.
x = int(input()) y = int(input())
if x > 0: ... else: ...
if x > 0: if y > 0: print("Birinshi toksan") else: print("Tortinshi toksan") else: if y > 0: print("Ekinshi toksan") else: print("Ushinshi toksan")
Енді басқа жағдайды қарастырайық: оқушының бағасын анықтау керек делік — «5» болса «Үздік», «4» болса «Жақсы», «3» болса «Қанағаттанарлық», қалғаны «Қанағаттанарлықсыз». Мұнда екі емес, төрт түрлі нұсқа бар. Бұл есепті кірістірілген if арқылы шешуге болады, бірақ әр жаңа нұсқа қосылған сайын кірістіру тереңдей береді, шегініс саны өсе береді, кодты оқу қиындай түседі.
Python мұндай жағдай үшін ыңғайлырақ тәсіл ұсынады — бірнеше шартты бір деңгейде, тізбектей тексеретін құрылым. Осындай, екіден көп нұсқадан таңдау үшін қолданылатын, шарттарды жоғарыдан төмен қарай тізбектей тексеретін тармақталуды каскадты тармақталу дейміз.
Каскадты тармақталу (if-elif-else) — екіден көп нұсқадан таңдау қажет болғанда қолданылады. Шарттар жоғарыдан төмен қарай тізбектей тексеріледі; біреуі орындалған сәтте сәйкес блок іске қосылады және қалған шарттар тексерілмейді.
Анықтаманы бөлшектеп көрейік: «Екіден көп нұсқа» — каскадты тармақталу дәл осы жағдайда тиімді: екі ғана нұсқа болса, қарапайым if-else жеткілікті. «Жоғарыдан төмен қарай тізбектей тексеріледі» — Python алдымен бірінші шартты тексереді, ол жалған болса — екіншісін, ол да жалған болса — үшіншісін, осылай жалғасады. «Біреуі орындалған сәтте... қалғаны тексерілмейді» — бұл өте маңызды қасиет: бір шарт ақиқат болып, сәйкес блок орындалғаннан кейін, Python қалған шарттарды мүлдем тексермейді, тіпті олар да ақиқат болатын болса да.
Неге дәл осылай жұмыс істейді? Себебі есеп логикасы бойынша, бір нәрсе тек бір санатқа жатуы керек. Сондықтан бірінші сәйкес келген шарт табылғаннан кейін, қалғанын тексерудің қажеті жоқ — бұл, сонымен қатар, бағдарламаны жылдамырақ та етеді. Мысалы: number = 1 болғанда, Python алдымен «number == 1» дегенді тексереді — ол ақиқат, сондықтан «Bir» деп шығарады да, «number == 2» шартын мүлдем тексермейді.
Каскадты тармақталуды эскалатор баспалдақтарына ұқсатуға болады: жоғарыдан төмен қарай түсе бересің, әр баспалдақта «осында тоқтаймын ба?» деп тексересің. Қажетті жерге жеткенде тоқтайсың да, қалған баспалдақтарға назар аудармайсың.
elif орнына бірнеше тәуелсіз if жазады. Бұл — қате емес, бірақ тиімсіз әрі қауіпті: Python әр if-ті бөлек тексереді, тіпті алдыңғысы ақиқат болса да, келесі if-ті де тексере береді. Бұл кейде күтпеген нәтижеге әкелуі мүмкін.Python синтаксисі:
if <шарт 1>: <нұсқау 1> elif <шарт 2>: <нұсқау 2> else: <нұсқау 3>
elif бірнеше рет қайталануы мүмкін, ал else блогы міндетті емес.
Бөлшектеп қарайық: «elif» — «else if» дегеннің қысқарған түрі, «алдыңғы шарт жалған болса, мынаны тексер» дегенді білдіреді. «elif бірнеше рет қайталануы мүмкін» — нұсқа саны қанша болса, сонша elif жазуға болады, шектеу жоқ. «else блогы міндетті емес» — егер барлық elif шарттары жалған болғанда ешқандай арнайы әрекет керек болмаса, else-ті жазбауға болады.
Неге elif деңгейі бір ғана? Себебі бұл — каскадты тармақталудың басты артықшылығы: барлық шарттар if-тің бір деңгейінде тұрады, кірістіру жасалмайды, сондықтан код жазылым ретімен оқуға оңай. Мысалы:
number = int(input()) if number == 1: print("Bir") elif number == 2: print("Eki") else: print("Baska san")
Мұнда үш нұсқа бар: 1, 2 және «басқа сан». Барлығы бір деңгейде, кірістірусіз жазылған. Бұл — кезекте тұрған сияқты: алдымен біріншіге сұрақ қойылады, «иә» десе — сол адаммен жұмыс жасалады, «жоқ» десе — кезектегі келесіге өтеді. Бір адам «иә» дегеннен кейін, қалған кезекке қарамайсың.
elif мен else-ті шатастырып, екеуінде де шарт жазуға тырысады (else number == 5: деп жазып қояды). Бұл — синтаксистік қате. else-тің өзінің шарты болмайды — ол «барлық алдыңғы шарттар жалған болғанда» дегенді ғана білдіреді. Шарт қажет болса, ол міндетті түрде elif болуы керек.else number == 5:
print("Bes") elif number == 5:
print("Bes") Мұғалім тақтада қалай шешер еді, дәл солай қадаммен жүрейік.
number = int(input())
if number == 1: print("Bir")
elif number == 2: print("Eki")
else: print("Baska san")
Енді бір сұрақ туады: ширек анықтау есебінде неге кірістірілген if қолдандық, ал баға анықтау есебінде неге elif қолдандық? Екеуі де «бірнеше нұсқадан таңдау» емес пе?
Мәселе мынада — бұл екі есептің құрылымы мүлдем әртүрлі. Ширек есебінде екі тәуелсіз белгі бар (x таңбасы және y таңбасы), олардың комбинациясы нәтижені анықтайды. Ал баға есебінде бір ғана белгі бар (number мәні), оның әртүрлі нақты мәндерін кезекпен тексереміз. Дәл осы айырмашылық — қашан кірістіру, қашан каскад қолдану керектігін анықтайтын негізгі белгі.
if...elif...else құрылымы кірістірілген if-else-ден оқылуы оңай болғандықтан артық: кірістіруде шегініс саны артып, кодты түсіну қиындайды, ал elif барлық шартты бір деңгейде тексереді.
Бөлшектеп қарайық, қашан қайсысын қолдану керек: Кірістірілген if — екі немесе одан да көп тәуелсіз белгінің комбинациясын тексеру керек болғанда қолданылады (мыс. x пен y таңбасы бірге қарастырылады). Каскадты if-elif-else — бір ғана белгінің әртүрлі нақты мәндерін немесе диапазондарын кезекпен тексеру керек болғанда қолданылады (мыс. бір ғана number айнымалысының 1, 2 немесе басқа мәндері).
Неге elif жалпы алғанда оқуға оңайырақ деп саналады? Себебі кірістіруде әр жаңа деңгей қосымша шегініс қосады — 2 деңгей 8 бос орын, 3 деңгей 12 бос орын талап етеді. Бұл кодты экранда оңға қарай «жылжытып» жібереді, оны оқу қиындайды. Ал elif барлық нұсқаны бір тік сызықта, бір деңгейде ұстайды.
Кірістіру — бір үлкен жолдың ішінен тармақталатын кішкене сыңарлар сияқты (алдымен үлкен жолды таңда, содан кейін сол жолдың ішіндегі кіші жолды таңда). Ал каскад — бір үлкен жолда қатар тұрған бірнеше есік сияқты, әр есікке кезекпен барасың, біреуі ашылса — кіресің де, қалғанына бармайсың.
elif қолдан, тәуелсіз белгілердің комбинациясы болса — кірістір.Бұл тақырып ҰБТ-да жиі үш түрлі формада кездеседі: (1) екі немесе үш белгінің комбинациясы бойынша нәтиже анықтау (мыс. координаталық ширек); (2) бір айнымалының бірнеше мәні бойынша санатқа бөлу (мыс. баға, дәреже); (3) кірістірілген немесе каскадты кодтың нәтижесін «қолмен» орындап шығу (трассировка).
Есте сақтау керек негізгі ережелер: кірістіру — тәуелсіз белгілердің комбинациясы үшін; elif — бір белгінің бірнеше мәні үшін; ішкі if әрқашан сыртқыдан 4 бос орынға артық шегінеді; каскадта бірінші ақиқат шарт табылғаннан кейін, қалғаны тексерілмейді.
elif орнына бөлек, тәуелсіз if жазып, артық тексерулерге жол беруelse-ке шарт жазуға тырысу (else-тің меншікті шарты болмайды)- Кірістірілген тармақталу — бір шарттың ішіне тағы бір шарт орналастыру; тәуелсіз белгілердің комбинациясын тексеру керек болғанда қолданылады, әр деңгей шегіністі 4 бос орынға арттырады.
- Каскадты тармақталу (if-elif-else) — бір белгінің бірнеше нақты мәнін бір деңгейде, тізбектей тексереді, біреуі табылған соң қалғаны тексерілмейді.
elifбірнеше рет қайталануы мүмкін,elseблогы міндетті емес.- Екі тәсілдің де өз орны бар: есептің құрылымына қарай дұрысын таңдау маңызды.