Pobierz Wykonanie warunkowe i więcej Egzaminy w PDF z Logika tylko na Docsity!
Rozdział 3
Wykonanie warunkowe
3.1. Wyrażenia logiczne
Wyrażenie logiczne to wyrażenie, które jest prawdziwe lub fałszywe. Poniższe przykłady używają operatora ==,
który porównuje dwa operandy i zwraca True, jeśli są one równe, lub False w przeciwnym wypadku:
True
5 == 6 False
True i False są specjalnymi wartościami, które należą do klasy bool; nie są one napisami:
type ( True ) < class ' bool ' > type ( False ) < class ' bool ' >
Operator == jest jednym z operatorów porównania ; pozostałe to:
x != y # x nie jest r ó wne y x > y # x jest wi ę ksze od y x < y # x jest mniejsze od y x >= y # x jest wi ę ksze lub r ó wne y x <= y # x jest mniejsze lub r ó wne y x is y # x jest tym samym co y x is not y # x nie jest tym samym co y
Choć powyższe operacje pewnie już znasz, symbole używane przez Pythona różnią się od symboli matematycz-
nych. Częstym błędem jest użycie pojedynczego znaku równości (=) zamiast znaku podwójnej równości (==).
Pamiętaj, że = jest operatorem przypisania, a == jest operatorem porównania. Nie ma znaków takich jak =<
lub =>.
3.2. Operatory logiczne
Istnieją trzy operatory logiczne : and, or i not. Semantyka (znaczenie) tych operatorów jest podobna do ich
znaczenia w języku angielskim. Na przykład wyrażenie
x > 0 and x < 10
28 Rozdział 3. Wykonanie warunkowe
x > 0
print(‘x jest dodatnia’)
Tak
Nie
Rysunek 3.1. Logika instrukcji if
jest prawdziwe tylko wtedy, gdy wartość zmiennej x jest większa niż 0 i mniejsza niż 10.
Wyrażenie n%2 == 0 or n%3 == 0 jest prawdziwe, jeśli którykolwiek z tych warunków jest prawdziwy, tzn. jeśli
liczba jest podzielna przez 2 lub 3.
Operator not neguje wyrażenie logiczne, więc not (x > y) jest prawdziwe, jeśli x > y jest fałszywe, tzn. jeśli
wartość x jest mniejsza lub równa y.
Ściślej mówiąc, operandy operatorów logicznych powinny być wyrażeniami logicznymi, ale Python nie jest tutaj
bardzo restrykcyjny. Każda dodatnia liczba całkowita jest interpretowana jako „prawdziwa”.
17 and True True
Taka elastyczność może być użyteczna, ale istnieją pewne niuanse, które mogą być mylące. Lepiej ich unikać,
dopóki nie będziesz pewien, że wiesz, co robisz.
3.3. Instrukcja warunkowa
Aby napisać użyteczny program, prawie zawsze potrzebujemy możliwości sprawdzenia pewnych warunków i
dostosowania do nich zachowania programu. Instrukcje warunkowe dają nam tę możliwość. Najprostszą formą
jest instrukcja if:
if x > 0 : print ( 'x jest dodatnia ')
Wyrażenie logiczne po instrukcji if jest nazywane warunkiem. Kończymy wyrażenie if znakiem dwukropka
(:), a linia lub linie po wyrażeniu if są wcięte.
Jeśli warunek logiczny jest prawdziwy, to wykonywane jest wyrażenie we wcięciu. Jeśli warunek logiczny jest
fałszywy, to wyrażenie we wcięciu jest pomijane.
Instrukcje if mają taką samą strukturę jak definicje funkcji lub pętle for^1. Instrukcja składa się z linii nagłówka,
która kończy się znakiem dwukropka (:), po którym następuje wcięty blok (tzw. ciało instrukcji if). Takie
instrukcje nazywane są instrukcjami złożonymi , ponieważ rozciągają się na więcej niż jedną linię.
Nie ma górnego ograniczenia co do liczby instrukcji, które mogą pojawić się w ciele instrukcji if, ale musi być
co najmniej jedna instrukcja. Czasami warto przygotować ciało if bez instrukcji (zazwyczaj jako miejsce na
kod, którego jeszcze nie napisałeś). W takim przypadku możesz użyć pass, który nie robi nic.
if x < 0 : pass # trzeba obs ł u ż y ć warto ś ci ujemne!
(^1) Dowiemy się o funkcjach w rozdziale 4, a o pętlach w rozdziale 5.
30 Rozdział 3. Wykonanie warunkowe
x < y print(‘x jest mniejsza niż y’)
Tak
x > y print(‘x jest większa niż y’)
Tak
print(‘x i y są równe’)
Nie
Nie
Rysunek 3.3. Logika if-elif
3.5. Warunki powiązane
Czasami mamy więcej niż dwie możliwości i potrzebujemy więcej niż dwóch gałęzi. Jednym ze sposobów na
wyrażenie takiej sytuacji jest warunek powiązany :
if x < y : print ( 'x jest mniejsza ni ż y ') elif x > y : print ( 'x jest wi ę ksza ni ż y ') else : print ( 'x i y s ą r ó wne ')
elif jest skrótem od else if. Tutaj również wykonana zostanie dokładnie jedna gałąź.
Nie ma ograniczenia co do liczby instrukcji elif. Jeśli istnieje klauzula else, to musi ona być na końcu (ale
samo jej pojawienie się nie jest wymagane).
if choice == 'a ': print ( 'Z ł a odpowied ź ') elif choice == 'b ': print ( ' Dobra odpowied ź ') elif choice == 'c ': print ( ' Blisko , ale ź le ')
Każdy warunek jest kolejno sprawdzany. Jeśli pierwszy jest fałszywy, sprawdzany jest następny itd. Jeśli jeden
z nich jest prawdziwy, to wykonywana jest odpowiadająca mu gałąź, a instrukcja jest kończona. Nawet jeśli
więcej niż jeden warunek jest prawdziwy, to tylko pierwszy z tych prawdziwych wykonuje swoją gałąź kodu.
3.6. Warunki zagnieżdżone
Jeden warunek może być również zagnieżdżony w innym. Mogliśmy zapisać przykład z trzema gałęziami w ten
sposób:
if x == y : print ( 'x i y s ą r ó wne ') else : if x < y : print ( 'x jest mniejsza ni ż y ') else : print ( 'x jest wi ę ksza ni ż y ')
3.7. Łapanie wyjątków przy użyciu try i except 31
x == y
Nie
print(‘x i y są równe’)
Tak
x < y
print(‘x jest większa niż y’)
Nie
print(‘x jest mniejsza niż y’)
Tak
Rysunek 3.4. Zagnieżdżone instrukcje if
Warunek zewnętrzny zawiera dwie gałęzie. Pierwsza gałąź zawiera prostą instrukcję. Druga gałąź zawiera
kolejną instrukcję if, która ma dwie własne gałęzie. Te dwie gałęzie to proste instrukcje, chociaż mogłyby być
również instrukcjami warunkowymi.
Chociaż wcięcie tych instrukcji sprawia, że ich struktura jest widoczna, to jednak zagnieżdżone instrukcje
warunkowe bardzo szybko stają się trudne do odczytania. Ogólnie rzecz biorąc, jeśli możesz, to ich unikaj.
Operatory logiczne często są sposobem na uproszczenie zagnieżdżonych instrukcji warunkowych. Na przykład
możemy przepisać następujący kod za pomocą jednego warunku:
if 0 < x : if x < 10: print ( 'x jest jednocyfrow ą dodatni ą liczb ą. ')
Funkcja print() jest wywoływana tylko wtedy, gdy spełnimy oba warunki, więc możemy uzyskać ten sam
efekt z operatorem and:
if 0 < x and x < 10: print ( 'x jest jednocyfrow ą dodatni ą liczb ą. ')
3.7. Łapanie wyjątków przy użyciu try i except
Wcześniej widzieliśmy fragment kodu, w którym używaliśmy funkcji input() i int() do odczytania i prze-
tworzenia liczby całkowitej wprowadzonej przez użytkownika. Widzieliśmy też, jak takie podejście może być
zdradzieckie:
prompt = " Jaka jest pr ę dko ś ć lotu jask ó ł ki bez obci ą ż enia ?\ n " speed = input ( prompt ) Jaka jest pr ę dko ś ć lotu jask ó ł ki bez obci ą ż enia? Jakiej jask ó ł ki? Afryka ń skiej czy europejskiej? int ( speed ) ValueError : invalid literal for int () with base 10:
Gdy wykonamy te polecenia w interpreterze Pythona, otrzymujemy od niego prośbę o wprowadzenie danych,
interpreter pomyśli „ups!” i przejdzie do naszej następnej instrukcji.
Jeżeli jednak umieścisz ten kod w skrypcie Pythona i wystąpi błąd, to Twój skrypt natychmiast się zatrzyma
w miejscu pojawienia się błędu, wyświetlając przy tym informacje z mechanizmu traceback , pozwalającego
zobaczyć kolejne wywołania funkcji, które ostatecznie doprowadziły do wystąpienia błędu. Po wystąpieniu
błędu skrypt nie wykona kolejnych instrukcji.
3.8. Minimalna ewaluacja wyrażeń logicznych 33
3.8. Minimalna ewaluacja wyrażeń logicznych
Gdy Python przetwarza wyrażenie logiczne takie jak x >= 2 and (x/y)> 2, ewaluuje je od lewej do prawej
strony. Ze względu na definicję and, jeśli x jest mniejsze niż 2, wyrażenie x >= 2 zostanie ewaluowane do False,
a więc całe wyrażenie zostanie ewaluowane do False, niezależnie od tego czy (x/y) > 2 zostanie ewaluowane
do True czy False.
Gdy Python wykryje, że nic już nie zyska dzięki ewaluacji pozostałej część wyrażenia logicznego, przerywa
jego ewaluację i nie wykonuje dalszych obliczeń. Zatrzymanie oceny wyrażenia logicznego, ponieważ ogólna
wartość jest już znana, nazywa się minimalną ewaluacją.
Konsekwencją specyfiki działania minimalnej ewaluacji jest sprytna technika zwana wzorcem strażnika. Prze-
analizujmy następującą sekwencję kodu w interpreterze Pythona:
x = 6 y = 2 x >= 2 and ( x / y ) > 2 True x = 1 y = 0 x >= 2 and ( x / y ) > 2 False x = 6 y = 0 x >= 2 and ( x / y ) > 2 Traceback ( most recent call last ) : File " < stdin > " , line 1 , in < module > ZeroDivisionError : division by zero
Trzecie obliczenie nie powiodło się, ponieważ Python ewaluował (x/y) i y było zerem, co spowodowało błąd
wykonania. Ale pierwszy i drugi przykład nie zakończyły się błędami, ponieważ pierwsza część tych wyrażeń
x >= 2 została ewaluowana do False, więc warunek (x/y) nigdy nie został sprawdzony właśnie z powodu
reguły minimalnej ewaluacji, przez co nie było tutaj żadnego błędu.
Możemy w następujący sposób skonstruować takie wyrażenie logiczne, aby strategicznie umieścić strażnika tuż
przed ewaluacją potencjalnie powodującą błąd:
x = 1 y = 0 x >= 2 and y != 0 and ( x / y ) > 2 False x = 6 y = 0 x >= 2 and y != 0 and ( x / y ) > 2 False x >= 2 and ( x / y ) > 2 and y != 0 Traceback ( most recent call last ) : File " < stdin > " , line 1 , in < module > ZeroDivisionError : division by zero
W pierwszym wyrażeniu logicznym, x >= 2 wynosi False, więc ewaluacja kończy się na and. W drugim
wyrażeniu logicznym, x >= 2 wynosi True, ale y != 0 wynosi False, więc nigdy nie dochodzimy do próby
ewaluacji (x/y).
W trzecim wyrażeniu logicznym, y != 0 jest po obliczeniu (x/y), więc wyrażenie kończy się błędem.
W drugim wyrażeniu mówimy, że y != 0 działa jak strażnik , tak by zapewnić, że wykonamy (x/y) tylko wtedy,
gdy y nie jest zerem.
34 Rozdział 3. Wykonanie warunkowe
3.9. Debugowanie
Mechanizm traceback w Pythonie pojawia się w przypadku wystąpienia błędu; zawiera on wiele informacji, ale
czasem może być przytłaczający. Najbardziej użyteczne są zazwyczaj informacje o tym:
- jaki to był błąd,
- gdzie ten błąd wystąpił.
Błędy składniowe są zazwyczaj łatwe do znalezienia, ale jest kilka podstępnych przypadków. Błędy związane z
tzw. białymi znakami^2 mogą być dla nas trudne do wychwycenia, ponieważ np. spacje i tabulacje są mało
widoczne i jesteśmy przyzwyczajeni do ich ignorowania.
x = 5 y = 6 File " < stdin > " , line 1 y = 6 x >= 2 and y != 0 and ( x / y ) > 2 False >>> x >= 2 and ( x / y ) > 2 and y != 0 Traceback ( most recent call last ) : File " < stdin > " , line 1 , in < module > ZeroDivisionError : division by zero >>> ## W pierwszym wyrażeniu logicznym, x >= 2 wynosi False, więc ewaluacja kończy się na and. W drugim ## wyrażeniu logicznym, x >= 2 wynosi True, ale y != 0 wynosi False, więc nigdy nie dochodzimy do próby ## ewaluacji (x/y). ## W trzecim wyrażeniu logicznym, y != 0 jest po obliczeniu (x/y), więc wyrażenie kończy się błędem. ## W drugim wyrażeniu mówimy, że y != 0 działa jak strażnik , tak by zapewnić, że wykonamy (x/y) tylko wtedy, ## gdy y nie jest zerem. ## 34 Rozdział 3. Wykonanie warunkowe 3.9. Debugowanie ## Mechanizm traceback w Pythonie pojawia się w przypadku wystąpienia błędu; zawiera on wiele informacji, ale ## czasem może być przytłaczający. Najbardziej użyteczne są zazwyczaj informacje o tym: - jaki to był błąd, - gdzie ten błąd wystąpił. ## Błędy składniowe są zazwyczaj łatwe do znalezienia, ale jest kilka podstępnych przypadków. Błędy związane z ## tzw. białymi znakami^2 mogą być dla nas trudne do wychwycenia, ponieważ np. spacje i tabulacje są mało ## widoczne i jesteśmy przyzwyczajeni do ich ignorowania. >>> x = 5 >>> y = 6 File " < stdin > " , line 1 y = 6 ^ IndentationError : unexpected indent
W powyższym przykładzie problem polega na tym, że druga linia jest wcięta przez jedną spację. Ale komunikat
o błędzie wskazuje na y, co jest mylące. Ogólnie rzecz biorąc, komunikaty o błędach wskazują, gdzie problem
został wykryty, ale rzeczywisty błąd może być w kodzie gdzieś wcześniej, czasami w poprzedniej linii.
Ogólnie komunikaty o błędach informują o tym, gdzie wykryto problem, ale często nie tam, gdzie został on
popełniony.
3.10. Słowniczek
ciało instrukcji Sekwencja instrukcji zawarta w złożonej instrukcji.
gałąź Jedna z alternatywnych sekwencji instrukcji występujących w instrukcji warunkowej.
instrukcja warunkowa Instrukcja, która kontroluje przepływ wykonywania programu w zależności od pewnego
warunku.
instrukcja złożona Instrukcja składająca się z nagłówka i ciała. Nagłówek kończy się dwukropkiem (:). Ciało
jest wcięte w stosunku do nagłówka.
minimalna ewaluacja Kiedy Python jest w trakcie ewaluacji złożonego wyrażenia logicznego i przerywa dalszą
ewaluację, ponieważ Python zna końcową wartość wyrażenia bez potrzeby ewaluacji reszty wyrażenia.
operator logiczny Jeden z operatorów, który łączy wyrażenia logiczne: and, or lub not.
operator porównania Jeden z następujących operatorów, który porównuje swoje operandy: ==, !=, >, <, >= i
traceback Lista funkcji, które są wykonywane; pojawia się, gdy wystąpi wyjątek.
warunek Wyrażenie logiczne w instrukcji warunkowej określające która gałąź jest wykonywana.
warunki powiązane Wyrażenie warunkowe z serią alternatywnych gałęzi.
warunki zagnieżdżone Instrukcja warunkowa, która pojawia się w jednej z gałęzi innej instrukcji warunkowej.
wyrażenie logiczne Wyrażenie o wartości True lub False.
wzorzec strażnika Miejsce, w którym konstruujemy wyrażenie logiczne z dodatkowymi porównaniami, tak
aby skorzystać z działania minimalnej ewaluacji.
3.11. Ćwiczenia
Ćwiczenie 1. Przepisz ponownie swój program obliczający wynagrodzenie, tak aby dać pracownikowi 1,5 raza
większą stawkę godzinową za czas przepracowany powyżej 40 godzin.
(^2) Należą do nich spacje, znaki tabulacji, znaki końca linii oraz dowolne inne znaki niemające kształtu na ekranie.