Vadovėlis/Loginiai reiškiniai
Šiame skyriuje padėsiu tau išsiaiškinti, kas yra loginiai reiškiniai. Sugalvojau nedidelį programos pavyzdį, kurio tau įvedinėti nebūtina:
a = 6 b = 7 c = 42 print(1, a == 6) print(2, a == 7) print(3, a == 6 and b == 7) print(4, a == 7 and b == 7) print(5, not a == 7 and b == 7) print(6, a == 7 or b == 7) print(7, a == 7 or b == 6) print(8, not (a == 7 and b == 6)) print(9, not a == 7 and b == 6)
Šios programos išvestis yra:
1 True 2 False 3 True 4 False 5 True 6 True 7 False 8 True 9 False
Galvoje, turbūt, jau sukasi mintis: kas čia ką tik įvyko? Paaiškinsiu, kaip veikia kiekviena eilutė, kad mintys susidėliotų į savas vietas. Mano programoje gausu print
sakinių, iš kurių kiekvienas išspausdina skaičių ir loginę reikšmę. Skaičius man padeda suprasti, kurio print
sakinio rezultatas tai yra. Atkreipk dėmesį, kad kiekvienoje išvesties eilutėje yra žodis False
(Klaidinga) arba True
(Teisinga), o Python'e kiekviena loginė reikšmė False
gali būti užrašoma skaičiumi 0, o True
1.
Eilučių:
print(1, a == 6) print(2, a == 7)
rezultatas atitinkamai yra True
ir False
, kadangi pirmasis reiškinys yra teisingas, o antrasis yra klaidingas. Trečioji eilutė: print(3, a == 6 and b == 7)
- šiek tiek skiriasi nuo prieš tai buvusių - joje yra naudojamas operatorius and
. Loginis operatorius and
grąžina rezultatą True
tik tada, kai reiškiniai iš abiejų and
pusių yra teisingi, kitu atveju visas reiškinys bus klaidingas ir grąžins False
. Ketvirtoje eilutėje: print(4, a == 7 and b == 7) tik vienas iš reiškinių yra teisingas, dėl to eilutės rezultatas yra False
. Operatoriaus and
galimi rezultatai gali būti apibrėžti tokia lentele:
Reiškinys | Rezultatas |
---|---|
True and True
|
True |
True and False
|
False |
False and True
|
False |
False and False
|
False |
Atkreipk dėmesį, jei pirmas reiškinys yra klaidingas, tai Python’as nebetikrins antrojo, kadangi jis žino, jog visas reiškinys yra klaidingas. Parašyk šias eilutes ir paleisk programą: False and print("Labas")
ir palygink rezultatą su šios eilutės True and print("Labas")
rezultatu. Techniškai tai yra vadinama sutrumpintos grandies įvertinimas (short-circuit evaluation).
Penktoje eilutėje, print(5, not a == 7 and b == 7)
, yra naudojamas not
operatorius. not
suteikia priešingą reikšmę reiškiniui (reiškinys taip pat galėtų būti užrašomas taip: print(5, a != 7 and b == 7)
). Štai lentelė apibrėžianti operatoriaus not
rezultatus:
Reiškinys | Rezultatas |
---|---|
not True
|
False |
not False
|
True |
Dvi toliau pateiktos eilutės: print(6, a == 7 or b == 7)
ir print(7, a == 7 or b == 6)
naudoja operatorių or
. Pastarasis operatorius grąžina True
jei pirmasis reiškinys yra teisingas arba, jei antrasis reiškinys yra teisingas, arba, jei abu reiškiniai yra teisingi. Jei nei vienas iš reiškinių nėra teisingas, tuomet yra grąžinamas False. Štai lentelė apibrėžianti operatoriaus or
rezultatus:
Reiškinys | Rezultatas |
---|---|
True or True
|
True |
True or False
|
True |
False or True
|
True |
False or False
|
False |
Turėk omeny, jei pirmasis reiškinys yra teisingas Python’as nebetikrins antrojo, kadangi jis žino, jog visas reiškinys bus teisingas. Kaip jau minėjau anksčiau, naudojant operatorių or
, jei bent vienas iš reiškinių yra teisingas, tuomet viso reiškinio galutinis rezultatas bus teisingas. Pirmoji dalis yra teisinga, todėl antroji dalis gali būti klaidinga arba teisinga, tačiau visa išraiška vis dar teisinga.
Aštuntoje: print(8, not (a == 7 and b == 6))
ir devintoje: print(9, not a == 7 and b == 6)
eilutėse yra atvaizduojamas reiškinių grupavimo pavyzdys. Reiškinius Python’e galima sugrupuoti naudojant skliaustelius. Sugrupavę reiškinius, mes priverčiame Python’ą iš pradžių įvertinti reiškinius skliaustuose ir tik tada likusias reiškinio dalis. Atkreipk dėmesį, kad skliausteliai pakeitė reiškinį iš neteisingo į teisingą. Taip nutiko dėl to, kad operatorius not
buvo pritaikytas reiškiniui skliausteliuose, vietoj to, kad būtų pritaikytas tik a == 7
daliai.
Parodysiu pavyzdį, kaip rašant kodą galima pritaikyti loginius operatorius:
sąrašas = ["Gyvenimas", "Visata", "Viskas", "Benas", "Liepa", "Gyvenimas", "Liepa"] # kuriama sąrašo kopija. Peržiūrėk skyrių Daugiau apie sąrašus, kuriame sužinosi ką reiškia [:]. kopija = sąrašas[:] # surūšiuoti sąrašą kopija.sort() ankstesnis = kopija[0] del kopija[0] kiekis = 0 # sąraše surask vienodus elementus while kiekis < len(kopija) and kopija[kiekis] != ankstesnis: ankstesnis = kopija[kiekis] kiekis = kiekis + 1 # Jei nėra atitikmens tuomet kiekis negali būti < len # kadangi ciklas kol bus vykdomas tol, kol kiekis < len # ir nėra rastas atitikmuo if kiekis < len(kopija): print("Pirmasis atitikmuo:", ankstesnis)
Šios programos rezultatas: Pirmasis atitikmuo: Gyvenimas
Programa ieško vienodų elementų, tikrindama šią sąlygą: while kiekis < len(kopija) and kopija[kiekis] nėra lygus ankstesnis
. Kai kiekis
yra didesnis už paskutinio kopija
sąrašo elemento indeksą arba, kai atsiranda sutampantis elementas, operatorius and
nebėra tiesa, todėl ciklas pasibaigia. if
sakinys patikrina ar ciklas while
pasibaigė dėl to, kad buvo rastas sutampantis elementas.
Šioje programoje yra panaudotas dar vienas and
operatoriaus „triukas“. Jei dar kartą pažiūrėsi į operatoriaus and
lentelę pamatysi, jog trečioje eilutėje yra netiesa ir netiesa. Jei kiekis >= len(kopija)
(kitais žodžiais, jei kiekis < len(kopija)
yra False
), tada kodo dalis kopija[kiekis]
nebus tikrinama. Taip yra todėl, kad Python’as žino, jei pirmasis teiginys yra klaidingas, tai abu jie nebegali būti teisingi. Šis „short circuit“ triukas yra naudingas tuomet, kai antrasis and
operatoriaus reiškinys gali sukelti klaidą. Aš panaudojau pirmąjį reiškinį (kiekis < len(kopija)
), kad patikrinčiau ar kintamasis kiekis
yra validus sąrašo kopija
indeksas. Jei manimi netiki, tuomet ištrink iš sąrašo elementus „Liepa“ ir „Gyvenimas“, sukeisk vietomis sąlygas kiekis < len(kopija) and kopija[kiekis] != ankstesnis
(rašyk: kopija[kiekis] != ankstesnis and kiekis < len(kopija)
) ir patikrink ar programa vis dar veikia, kaip turėtų.
Loginiai operatoriai gali būti naudojami, kai mes norime patikrinti dvi arba daugiau skirtingų sąlygų vienu metu.
Pastaba apie loginius operatorius
Dažna pradedančiųjų programuotojų klaida yra neteisingas supratimas, kaip veikia loginiai operatoriai ir kaip juos „skaito“ Python'o interpretatorius. Pavyzdžiui: vos tik sužinojus apie operatorius and
ir or
, galima pagalvoti, kad išraiška x == ('a' or 'b')
patikrins, ar kintamasis x
yra lygus a
arba kintamasis x
lygus b
, tačiau taip nėra. Norint suprasti, apie ką kalbu, pradėk interaktyvią sesiją su interpretatoriumi ir įvesk šias išraiškas:
>>> 'a' == ('a' or 'b') >>> 'b' == ('a' or 'b') >>> 'a' == ('a' and 'b') >>> 'b' == ('a' and 'b')
Štai yra rezultatai, kurie nėra intuityvūs:
>>> 'a' == ('a' or 'b') True >>> 'b' == ('a' or 'b') False >>> 'a' == ('a' and 'b') False >>> 'b' == ('a' and 'b') True
Šiuo momentu gali pasirodyti, jog operatoriai and
ir or
veikia klaidingai. Neatrodo logiška, jog pirmuose reiškiniuose 'a'
yra lygu 'a'
arba 'b'
, tačiau 'b'
nėra lygu 'a'
arba 'b'
. Taip pat yra ir su paskutiniu reiškiniu - jis neatrodo teisingas, nes 'b'
yra lygus 'a'
ir 'b'
. Išsiaiškinus, kaip veikia Python’o interpretatorius pasidaro aišku, kodėl gavome būtent tokius rezultatus.
Kai Python’o interpretatorius „pamato“ reiškinį, kuriame yra naudojamas or
, jis paima pirmąjį teiginį ir patikrina ar jo rezultatas yra True
. Jei pirmasis teiginys yra True
, tuomet Python’as grąžina to teiginio rezultatą, netikrindamas antrojo. Kaip jau minėjau anksčiau, naudojant operatorių or
užtenka patikrinti ar pirmasis teiginys yra teisingas, nes tada mes jau žinome, kad visas reiškinys yra teisingas ir programai nebereikia papildomai tikrinti antrojo. Iš kitos pusės, jei pirmasis teiginys grąžina False
, tada Python’as turi patikrinti ir antrojo teiginio rezultatą bei grąžinti jo reikšmę. Antrasis teiginys nusako visos išraiškos rezultatą, kadangi pirmoji pusė buvo klaidinga. Šis interpretatoriaus „tingus“ įvertinimas vadinamas "short circuiting" ir yra įprastas būdas įvertinti logines išraiškas daugelyje programavimo kalbų.
Panašiai veikia ir operatorius and
: Python’as naudoja, "short circuit" techniką, kad pagreitintų išraiškos įvertinimą. Jei pirmasis teiginys yra klaidingas, tada visas reiškinys yra klaidingas. Kitu atveju, jei pirmasis teiginys yra teisingas, tada Python’as patikrina antrąjį ir grąžina galutinę reikšmę.
Reiktų atkreiptį dėmesį į vieną niuansą: ne tik loginių išraiškų rezultatai gali būti apibrėžiami True
arba False
reikšmėmis. Norėdami patikrinti bet kurio objekto x
loginę reikšmę, galite naudoti funkciją bool(x)
. Žemiau yra pateikiama lentelė, kurioje yra pavyzdžiai, kokiems objektams Python’as priskiria True
arba False
:
True | False |
---|---|
True | False |
1 | 0 |
Skaičiai kitokie nei nulis | Tekstinė eilutė 'None' |
Ne tuščios tekstinės eilutės | Tuščios tekstinės eilutės |
Sąrašai (lists) turintys elementų | Sąrašai (lists) neturintys elementų |
Žodynai (dictionaries) turintys elementų | Žodynai (dictionaries) neturintys elementų |
Dabar galime suprasti gluminančius rezultatus, kuriuos gavome, kai anksčiau išbandėme logines išraiškas. Pažiūrėkime, ką Python'o interpretatorius „mato“, eidamas per šį kodą:
Pirmasis atvejis:
>>> 'a' == ('a' or 'b') # Iš pradžių žiūrėk į reiškinį skliaustuose: "('a' or 'b')" # 'a' yra netuščia teksto eilutė, todėl reiškinio rezultatas yra True # Grąžink tą pirmą reikšmę: 'a' >>> 'a' == 'a' # teksto eilutė 'a' yra lygi teksto eilutei 'a', todėl reiškinio rezultatas yra True True
Antrasis atvejis:
>>> 'b' == ('a' or 'b') # Iš pradžių žiūrėk į reiškinį skliaustuose: "('a' or 'b')" # 'a' yra netuščia teksto eilutė, todėl reiškinio rezultatas yra True # Grąžink tą pirmą reikšmę: 'a' >>> 'b' == 'a' # teksto eilutė 'b' nėra lygi teksto eilutei 'a', todėl reiškinio rezultatas yra False False
Trečiasis atvejis:
>>> 'a' == ('a' and 'b') # Iš pradžių žiūrėk į reiškinį skliaustuose: "('a' and 'b')" # 'a' yra netuščia teksto eilutė, todėl reiškinio rezultatas yra True, patikrinkime antrąją reikšmę # 'b' yra netuščia teksto eilutė, todėl antrojo reiškinio rezultatas yra True # Grąžink antrąją reikšmę kaip viso reiškinio rezultatą: 'b' >>> 'a' == 'b' # teksto eilutė 'a' nėra lygi teksto eilutei 'b', todėl reiškinio rezultatas yra False False
Ketvirtasis atvejis:
>>> 'b' == ('a' and 'b') # Iš pradžių žiūrėk į reiškinį skliaustuose: # 'a' yra netuščia teksto eilutė, todėl reiškinio rezultatas yra True, patikrinkime antrąją reikšmę # 'b' yra netuščia teksto eilutė, todėl antrojo reiškinio rezultatas yra True # Grąžink antrąją reikšmę kaip viso reiškinio rezultatą: 'b' >>> 'b' == 'b' # teksto eilutė 'b' yra lygi teksto eilutei 'b', todėl reiškinio rezultatas yra True True
Taigi, Python’as tikrai teisingai įvertino duotuosius reiškinius, kurių rezultatai iš pradžių neatrodė akivaizdūs. Kaip minėjau anksčiau, svarbu atpažinti, kokį rezultatą tavo loginė išraiška grąžins ir kodėl.
Grįžtant prie pradinių reiškinių, štai kaip juos turėtum aprašyti, kad jie grąžintų reikšmes, kurių tikiesi:
>>> 'a' == 'a' or 'a' == 'b' True >>> 'b' == 'a' or 'b' == 'b' True >>> 'a' == 'a' and 'a' == 'b' False >>> 'b' == 'a' and 'b' == 'b' False
Įvertinus šiuos reiškinius yra gaunamos logines reikšmes True
arba False
, o ne teksto eilutės, kad galėtume gauti teisingus palyginimo rezultatus.
Pavyzdžiai
slaptazodis1.py
## Ši programa prašo vartotojo prisijungimo vardo ir slaptažodžio. # Kai vartotojas juos įveda, programa įvertina ar jis gali prisijungti. vardas = input("Koks tavo vardas? ") slaptažodis = input("Koks tavo slaptažodis? ") if vardas == "Benas" and slaptažodis == "Penktadienis": print("Sveikas, Benai!") elif vardas == "Jonas" and slaptažodis == "Kietas": print("Sveikas, Jonai!") else: print("Aš tavęs nepažįstu.")
Pavyzdiniai rezultatai:
Koks tavo vardas? Benas
Koks tavo slaptažodis? Penktadienis
Sveikas, Benai!
Koks tavo vardas? Andrius
Koks tavo slaptažodis? Pinigai
Aš tavęs nepažįstu.
Pratimai
1. Parašyk programą, kurioje vartotojas turi atspėti tavo vardą, tačiau jie turės tik 3 spėjimus tai padaryti iki kol programa bus uždaryta.
Sprendimas | |
---|---|
print("Pabandyk atspėti mano vardą!") kiekis = 1 VARDAS = "gilbertas" spėjimas = input("Koks mano vardas? ") while kiekis < 3 and spėjimas.lower() != VARDAS: # .lower visas didžiąsias raides teksto eilutėje pakeičia į mažąsias, todėl net jei vartotojas įves Gilbertas, tai vis tiek bus teisingas atsakymas print("Tu neteisus!") spėjimas = input("Koks mano vardas? ") kiekis = kiekis + 1 if spėjimas.lower() != VARDAS: print("Tu neteisus!") # ši žinutė nėra atspausdinama trečiąjį bandymą, todėl mes tai padarome dabar print("Tu nebegali spėti.") else: print("Taip! Mano vardas yra", VARDAS + "!") |
2. Parašyk programą, kuri paprašytų įvesti du skaičius. Programa turėtų išvesti, ar abu skaičiai didesni už 10, ar abu skaičiai mažesni už 10, ar vienas didesnis, kitas mažesnis.
Sprendimas | |
---|---|
pirmas_skaičius = int(input("Įvesk pirmą skaičių: ")) antras_skaičius = int(input("Įvesk antrą skaičių: ")) if pirmas_skaičius > 10 and antras_skaičius > 10: print ("Abu skaičiai didesni nei 10") elif pirmas_skaičius < 10 and antras_skaičius < 10: print ("Abu skaičiai mažesni nei 10") else: print ("Vienas iš skaičių mažesnis nei 10") |
3. Parašyk programą, kuri paprašytų sukurti stiprų slaptažodį. Reikalavimai stipriam slaptažodžiui:
- Jis turėtų būti sudarytas iš daugiau nei 6 simbolių
- Jis turėtų turėti bent vieną skaitmenį
- Jis turėtų turėti bent vieną specialų simbolį iš šio sąrašo: !#$?
Programa turėtų išvesti, ar slaptažodis pakankamai stiprus, ar ne.
Sprendimas | |
---|---|
def ar_turi_skaičių(slaptažodis): skaičiai = "0123456789" rezultatas = False for raidė in slaptažodis: if raidė in skaičiai: rezultatas = True break return rezultatas def ar_turi_simbolį(slaptažodis): simboliai = "!#$?" rezultatas = False for raidė in slaptažodis: if raidė in simboliai: rezultatas = True break return rezultatas def ar_slaptažodis_stiprus(slaptažodis): ar_užtenka_simbolių = len(slaptažodis) > 6 ar_yra_skaitmuo = ar_turi_skaičių(slaptažodis) ar_yra_simbolis = ar_turi_simbolį(slaptažodis) return ar_užtenka_simbolių and ar_yra_skaitmuo and ar_yra_simbolis įvestas_slaptažodis = input("Įvesk slaptažodį: ") ar_stiprus = ar_slaptažodis_stiprus(įvestas_slaptažodis) if ar_stiprus: print ("Slaptažodis pakankamai stiprus") else: print ("Slaptažodis nepakankamai stiprus") |