Лекция · 4.4–4.6

Күрделі шарттар

Концертке кіру үшін екі шарт орындалуы керек делік: жасың 18-ден асуы керек ЖӘНЕ қолыңда билет болуы керек. Тек біреуі жеткіліксіз — екеуі де бірге орындалуы тиіс. Дәл осы сұраққа жауап беретін тақырыппен танысамыз — күрделі (құрамды) шарттар: and, or, not логикалық операторлары арқылы бірнеше шартты бір тұтас шартқа біріктіру. Бұл тақырып ҰБТ-да аса жиі кездеседі: жас санатын анықтау, координаталық ширекті and арқылы табу, бірнеше санның арасында белгілі бір қасиет бар-жоғын тексеру — барлығы дәл осы тақырыпқа негізделген.

Күрделі шарт деген не?

Өткен сабақта координаталық ширекті анықтау үшін кірістірілген if қолдандық: алдымен x таңбасын тексеріп, содан кейін оның ішінде y таңбасын тексердік. Бұл дұрыс жұмыс істеді, бірақ ойлап көрсек — біз шын мәнінде нені тексеріп жатырмыз? «x оң ЖӘНЕ y оң» деген бір тұтас ойды!

Сұрақ туады: екі шартты («x > 0» және «y > 0») кірістірудің орнына, бір жолда, бір тұтас шарт ретінде жазуға бола ма? Жауабы — иә, болады. Python-да бірнеше қарапайым шартты логикалық операторлар (and, or, not) арқылы біріктіріп, бір тұтас шарт жасауға болады. Осындай, бірнеше қарапайым шарттан құралған шартты күрделі (құрамды) шарт дейміз.

x > 0 y > 0 and True/False
Анықтама
Күрделі (құрамды) шарт — логикалық амалдар (and, or, not) көмегімен бір тұтас шартқа біріктірілген бірнеше қарапайым шарт. Қарапайым шарт екі мән арасындағы салыстырудан тұрады (мыс. x >= 5).

Анықтаманы бөлшектеп көрейік: «Логикалық амалдар (and, or, not)» — бұл операторлар шарттарды бір-бірімен «жалғайтын» арнайы сөздер, олар математикадағы +, -, × сияқты, бірақ сандар емес, рас/жалған мәндермен жұмыс істейді. «Бір тұтас шартқа біріктірілген» — нәтижесінде бірнеше шарт болса да, Python оларды бір ғана шарт ретінде қарастырады, нәтиже жалғыз True немесе False болады. «Қарапайым шарт» — бұл бұған дейін көрген, бір ғана салыстырудан тұратын шарт (мыс. x > 0), ол күрделі шарттың «кірпіші» болып табылады.

Неге дәл осылай жасалған? Себебі көптеген нақты есептерде шешім бір ғана белгіге емес, бірнеше белгінің бірлесіп орындалуына немесе кем дегенде біреуінің орындалуына байланысты болады. Мысалы: x > 0 and y > 0 — бұл бір тұтас шарт, ол тек x та, y да оң болғанда ғана True болады. Ал x > 0 or y > 0 — бұл шарт x пен y-дың кем дегенде біреуі оң болса жеткілікті, True болады.

🔐 Сейф (and)
🔑🔑
Ашу үшін екі кілт ТЕ керек
🚪 Үй (or)
🚪 немесе 🚪
Кез келген есік ашық болса жеткілікті

Бұл — екі құлпы бар сейфке ұқсайды: сейфті ашу үшін екі кілт ТЕ керек (and логикасы). Ал кейде керісінше — үйге кіру үшін алдыңғы есік НЕМЕСЕ артқы есік ашық болса жеткілікті (or логикасы), екеуі бірге ашық болуы шарт емес.

⚠️
Жиі кеткен қате: күнделікті тілде «немесе» сөзі кейде «тек біреуі» дегенді білдіреді (мыс. «шай немесе кофе ішесің бе?»). Бірақ Python-дағы or операторы олай емес — екі шарт та ақиқат болса да, нәтиже сонда да True болады. Бұл — логикадағы or мен күнделікті тілдегі «немесе» арасындағы маңызды айырмашылық.
Логикалық операторлар: and, or, not

Логикалық операторлардың нақты қалай жұмыс істейтінін көру үшін, барлық мүмкін жағдайды бір кестеге жинап көрейік. Бұл — математикадағы көбейту кестесі сияқты, бірақ сандар емес, рас/жалғанмен жұмыс істейді. x пен y — екі бөлек шарттың нәтижесі (0 — жалған, 1 — рас); ал «x and y», «x or y», «not x» бағандары — сол екі шартты әртүрлі оператормен біріктіргендегі нәтиже.

xyx and yx or ynot x
00001
01011
10010
11110

and — логикалық көбейту (конъюнкция, «және»), or — логикалық қосу (дизъюнкция, «немесе»), not — логикалық теріске шығару (инверсия, «емес»).

Кестені қарапайым сөзбен қайталайық: and (және) — нәтиже тек екеуі де рас болғанда ғана рас болады. or (немесе) — нәтиже екеуінің кем дегенде біреуі рас болса жеткілікті рас болады. not (емес) — берілген мәнді керісінше айналдырады: рас болса — жалғанға, жалған болса — расқа.

Неге and «көбейту» деп аталады? Себебі 0 мен 1-ді көбейту ережесімен дәл сәйкес келеді: 1×1=1, ал қалғанының бәрі 0. Ал or «қосу» деп аталады, себебі логикалық тұрғыдан кем дегенде бір «бірдің» болуы жеткілікті болатын жағдайды білдіреді. Мысалы: x = (5 > 3) — бұл рас (1), y = (2 > 10) — бұл жалған (0). x and y — рас and жалған = жалған (0). x or y — рас or жалған = рас (1), себебі кем дегенде біреуі рас.

and — тізбектей екеуі де жанса жарық or — параллель біреуі жансада жарық

Екі шамды елестет: and — екі шам да жанғанда ғана бөлме жарық болады (екеуі тізбектей қосылған сияқты). or — кез келген біреуі жанса да бөлме жарық болады (екеуі параллель қосылған сияқты). not — шамды керісінше айналдыратын қосқыш, жанып тұрса өшіреді, өшіп тұрса жағады.

⚠️
Жиі кеткен қате: көп оқушылар and мен or-дың нәтижесін шатастырады, әсіресе екеуі де жалған болатын жағдайды дұрыс есептей алмайды. Есте сақта: and — ең «талапшыл» (екеуі де керек), or — ең «жеңіл» (біреуі жетеді). Сондықтан бірдей екі шартта and нәтижесі әрқашан or нәтижесінен қатаңырақ (азырақ жағдайда True) болады.
Тізбектелген салыстыру

Математика сабағында «0 < a < 10» деген жазуды көрген боларсың — бұл «a нөлден үлкен, ЖӘНЕ a онға кіші» дегенді білдіреді. Сұрақ: Python-да да дәл осылай қысқа жазуға бола ма, әлде міндетті түрде «0 < a and a < 10» деп ұзақ жазу керек пе? Қызығы — көптеген бағдарламалау тілдерінде мұндай қысқа жазу мүмкін емес. Бірақ Python — бұл жағынан ерекше тіл.

Python математикадағыдай жазуға рұқсат береді: 0 < a < b деп жазсаң, Python мұны автоматты түрде 0 < a and a < b деп түсінеді. Бұл — Python-ның ерекше, ыңғайлы мүмкіндігі, оны тізбектелген салыстыру дейміз.

Анықтама
Python тілінің ерекшелігі — салыстыру амалдарының қысқартылған жазылуы: if 0 < a < b жазуы if a > 0 and a < b-мен бірдей нәтиже береді.
0 b a

Бөлшектеп қарайық: «Қысқартылған жазылуы» — бір айнымалыны екі жақтан салыстыру бір жолда, екі рет жазбай-ақ көрсетіледі. «0 < a < b» — бұл жазу «a саны 0-ден де үлкен, b-дан да кіші» дегенді білдіреді, яғни a екі шектің арасында жатыр. «a > 0 and a < b» — бұл толық, ұзақ жазылу түрі, нәтижесі қысқа жазумен дәл бірдей.

Неге бұл мүмкін? Себебі Python ішінде осындай тізбектелген салыстыруды автоматты түрде екі бөлек салыстыруға бөліп, оларды and арқылы біріктіреді. Мысалы: 3 <= old < 6 деген жазу — old санының 3-тен кем еместігін ЖӘНЕ 6-дан кем екенін бір мезетте тексереді. Бұл, мысалы, жас санатын анықтауда («балабақша жасы») өте ыңғайлы қолданылады.

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

⚠️
Жиі кеткен қате: кейбір оқушылар бұл қысқа жазуды басқа бағдарламалау тілдерінде де (мыс. C++ немесе Java) жұмыс істейді деп ойлайды. Бұл — қате. Тізбектелген салыстыру — Python-ға ғана тән ерекшелік, басқа көптеген тілдерде 0 < a < b деген жазу мүлдем басқа (қате) нәтиже беруі мүмкін.
Күрделі шарттарды есепте қолдану

Мұғалім тақтада қалай шешер еді, дәл солай қадаммен жүрейік.

Деңгей: орта
Не белгілі: Адамның жасы (old).
Не табу керек: Жасына сай білім алу сатысын анықтау (3-6: балабақша, 6-10: бастауыш, 10-15: негізгі, 15+: жоғары мектеп).
Неге дәл осы әдісті қолданамыз: әр санат екі шетпен шектелген диапазон. Мұны жазудың ең қысқа жолы — тізбектелген салыстыру (3 <= old < 6), ал санат саны төртеу болғандықтан, оларды кезекпен elif арқылы тексереміз.
1
Жасты енгіземіз.
old = int(input("Jasynyzdy engiziniz: "))
2
Бірінші диапазонды тізбектелген салыстырумен тексереміз — «old 3-тен кем емес, ЖӘНЕ 6-дан кем» дегенді бір жолда тексереді.
if 3 <= old < 6:
    print("Balabaksha")
3
Қалған диапазондарды elif арқылы тізбектей тексереміз. Соңғы санатта тек төменгі шек жеткілікті, өйткені жоғарғы шек жоқ.
elif 6 <= old < 10:
    print("Bastayysh mektep")
elif 10 <= old < 15:
    print("Orta mektep")
elif 15 <= old:
    print("Jogary mektep")
Тексеру: old=3 болса, «3 ≤ 3 < 6» — ақиқат, демек «Balabaksha» шығады, қалған elif шарттары тексерілмейді. Жауабы: old=3 → "Balabaksha". Қорытынды идея: диапазон шегі бар санаттарды анықтағанда, тізбектелген салыстыру кодты қысқа әрі оқуға оңай етеді, ал бірнеше диапазон болғанда оларды elif арқылы тізбектей тексереміз.
3–6 6–10 10–15 15+ old=3
Деңгей: орта
Не белгілі: (x, y) нүктесінің координаттары.
Не табу керек: Нүктенің координаталық ширегін and операторымен анықтау.
Неге дәл осы әдісті қолданамыз: бұл — өткен сабақта кірістірілген if арқылы шешілген есептің дәл өзі, бірақ енді and операторы арқылы әр ширектің шартын бір жолда жазамыз — кірістірудің қажеті жоқ.
1
Координаттарды енгіземіз.
x = int(input())
y = int(input())
2
Әр ширектің шартын and арқылы бір жолда жазамыз — әр ширек x пен y таңбасының белгілі бір комбинациясы.
if x > 0 and y > 0:
    print("Birinshi toksan")
elif x < 0 and y > 0:
    print("Ekinshi toksan")
elif x < 0 and y < 0:
    print("Ushinshi toksan")
else:
    print("Tortinshi toksan")
3
Соңғы жағдайды else арқылы жабамыз. Төртінші ширекті (x > 0, y < 0) бөлек жазудың қажеті жоқ — ол алдыңғы үш шарттың бәрі жалған болғандағы жалғыз қалған нұсқа, сондықтан else жеткілікті.
Тексеру: x=4, y=5 — «x > 0 and y > 0» ақиқат (екеуі де рас) → «Birinshi toksan». x=-4, y=3 — бірінші шарт жалған, екінші шарт «x < 0 and y > 0» ақиқат → «Ekinshi toksan». Жауабы: x=4,y=5 → "Birinshi toksan"; x=-4,y=3 → "Ekinshi toksan". Қорытынды идея: екі тәуелсіз белгінің комбинациясын тексеру керек болғанда, кірістірілген if-тің орнына and операторы арқылы бір жолда жазу — кодты қысқартады әрі оқуға жеңілдетеді.
Бірнеше мәнді бір жолдан оқу

Үш санды енгізу керек делік — a, b, c. Бұған дейін біз әр санды бөлек жолмен сұрап едік: a = int(input()), содан кейін b = int(input()), содан кейін c = int(input()). Бұл жұмыс істейді, бірақ үш рет Enter басу керек.

Сұрақ: үш санды бір ғана жолда, бос орынмен бөліп, бір рет Enter басып енгізуге бола ма? Жауабы — иә, болады. Бұл үшін бұған дейін файлдан сан оқығанда көрген split() әдісін, енді input()-пен бірге қолданамыз. input().split() пернетақтадан енгізілген бір жолды бос орын бойынша бөлек бөліктерге бөледі, ал map(int, ...) сол бөліктердің әрқайсысын санға айналдырады.

"4 10 -4" split() ["4","10","-4"] map(int) a,b,c
Анықтама
Бір жолдан бірнеше мән оқу үшін map() функциясы split()-пен бірге қолданылады: a, b, c = map(int, input().split()). Бұл әдіс пернетақтадан 3 санды бір рет бос орынмен бөліп енгізуге мүмкіндік береді.

Бөлшектеп қарайық: «input().split()» — input() пернетақтадан бір тұтас жолды оқиды (мыс. «4 10 -4»), ал split() оны бос орын бойынша бөлек бөліктерге бөліп, тізім қайтарады (["4", "10", "-4"]). «map(int, ...)» — тізімдегі әр элементті (олар әлі де жол түрінде) int() функциясы арқылы санға айналдырады. «a, b, c = ...» — нәтижесінде шыққан үш санды бірден үш айнымалыға бөліп тарату.

Неге дәл осылай жасалады? Себебі input() әрқашан тек бір тұтас жол қайтарады, ал бізге сол жолдың ішінен бөлек сандар керек. Мысалы: пайдаланушы «4 10 -4» деп енгізсе, input().split() нәтижесі — ["4", "10", "-4"]. map(int, ...) нәтижесі — әр элемент санға айналады. a, b, c = ... жолынан кейін a=4, b=10, c=-4 болады.

Бұл — бір қапшықты үш бөлек себетке бөліп төгуге ұқсас: алдымен қапшықтың ішіндегісін бос орындар бойынша бөлек бөліктерге бөлесің (split), содан кейін әр бөлікті дұрыс «формаға» (санға) келтіресің (map int), соңында әрбірін өз себетіне (a, b, c айнымалыларына) саласың.

⚠️
Жиі кеткен қате: көп оқушылар айнымалылар саны мен енгізілген сандар санын сәйкестендірмейді — мыс. a, b, c = map(int, input().split()) деп жазып, тек екі сан енгізеді. Бұл — ValueError қатесіне әкеледі, өйткені Python үш мән күтіп тұр, ал тек екеуі келді. Енгізілетін сандар саны мен айнымалылар саны әрқашан дәл сәйкес келуі керек.
Бірнеше мәнді есепте қолдану

Мұғалім тақтада қалай шешер еді, дәл солай қадаммен жүрейік.

Деңгей: қиын
Не белгілі: a, b, c үш бүтін сан (бір жолда, бос орынмен бөлінген).
Не табу керек: Сандардың арасында өзара кері (қосындысы 0-ге тең) жұп бар-жоғын анықтау.
Неге дәл осы әдісті қолданамыз: үш санды бір рет енгізу үшін map() пен split() қолданамыз. «Өзара кері жұп бар ма?» деген сұрақ үш бөлек мүмкіндікті тексереді: a+b=0 МА, әлде a+c=0 МА, әлде b+c=0 МА. Бұл үшеуінің кез келгені жеткілікті болғандықтан, or операторы қолданылады.
1
Үш санды бір жолдан оқимыз.
a, b, c = map(int, input().split())
2
Үш мүмкіндікті or арқылы біріктірілген күрделі шартта тексереміз — «a мен b өзара кері МА, ЯКИ a мен c МА, ЯКИ b мен c МА» дегенді бір жолда тексереді.
if (a+b==0) or (a+c==0) or (b+c==0):
    print('ia')
else:
    print('jog')
Тексеру: a=4, b=10, c=-4 болғанда: a+b=14 (нөлге тең емес), a+c=0 (нөлге тең!), b+c=6 (нөлге тең емес). or операторы бойынша тек біреуінің ақиқат болуы жеткілікті, сондықтан барлық шарт ақиқат — «ia» шығады. Жауабы: a=4, b=10, c=-4 → "ia" (a+c=0 болғандықтан). Қорытынды идея: «кем дегенде біреуі орындалса жеткілікті» деген есептерде or операторы қолданылады, ал бірнеше мүмкін жұптың әрқайсысын жеке шарт ретінде жазып, оларды or арқылы біріктіру — есепті толық әрі қысқа жабады.
a+b = 14 a+c = 0 ✓ b+c = 6
📝 ҰБТ-мен байланысы

Бұл тақырып ҰБТ-да жиі үш түрлі формада кездеседі: (1) бірнеше шартты and/or арқылы біріктіріп, нәтижені анықтау; (2) тізбектелген салыстыруды (a < x < b) қолданып диапазонды тексеру; (3) бірнеше мәнді бір жолдан map() пен split() арқылы оқып, оларды күрделі шартпен өңдеу.

Есте сақтау керек негізгі ережелер: and — барлығы рас болғанда ғана рас; or — кем дегенде біреуі рас болса жеткілікті; not — мәнді керісінше айналдырады; 0 < a < b жазуы a > 0 and a < b-мен бірдей; map(int, input().split()) — бір жолдан бірнеше санды оқу үшін қолданылады.

Ең жиі кеткен қателер:
!
and мен or-дың логикасын шатастыру
!
күнделікті тілдегі «немесе» мағынасын Python-дағы or операторымен шатастыру
!
тізбектелген салыстыруды тек Python-да ғана жұмыс істейтінін ұмытып, басқа тілде де солай деп ойлау
!
map(int, input().split()) қолданғанда айнымалылар саны мен енгізілген сандар санын сәйкестендірмеу
Сабақ қорытындысы
  • Күрделі шарт — бірнеше қарапайым шартты логикалық операторлар (and, or, not) арқылы бір тұтас шартқа біріктіру.
  • and — барлық шарт рас болғанда ғана рас, or — кем дегенде біреуі рас болса жеткілікті, not — мәнді теріске айналдырады.
  • Тізбектелген салыстыру (0 < a < b) — екі шартты бір жолда қысқа жазуға мүмкіндік береді (тек Python-да).
  • Бірнеше мәнді бір рет енгізу үшін map() пен split() бірге қолданылады: a, b, c = map(int, input().split()).
Логикалық операторлар
«Шарттарды біріктіру тілі» — and, or, not
Тізбектелген салыстыру
«Диапазон тексерудің қысқа жолы» — 0 < a < b
Бірнеше мән оқу
«Бір жолдан бірнеше дерек алудың тәсілі» — map()+split()