🧩 Wyrażenia logiczne

Do tej pory widzieliśmy zaledwie bardzo proste warunki, sprawdzające wartość tylko jednej zmiennej na raz. Czasem to za mało!

Jak zachować się w sytuacji, gdy chcielibyśmy wykonać akcję tylko jeśli jednocześnie DWA warunki są spełnione? Na przykład, gdy piszemy zasady działania platformy społecznościowej:

Aby uzyskiwać odpowiedzi na takie złożone pytania, potrzebujemy operatorów logicznych (and, or, not). Wykonują one operacje na wartościach logicznych (True/False) – podobnie jak plus i minus działają na liczbach!

🤝 Operator 'and' (Koniunkcja)

Aby dobrze zrozumieć operatory logiczne, przytoczę historię małego Jasia. Chciał on pograć na komputerze, więc poszedł do mamy prosić o pozwolenie. Ta jednak powiedziała:

"Będziesz mógł pograć, gdy odrobisz lekcje i posprzątasz pokój".
👩‍🏫
# Jak wyglądałby ten warunek w Pythonie?
can_play_games = finished_homework and cleaned_room

Widzimy tu zmienne finished_homework i cleaned_room, reprezentujące kolejno ukończenie zadań domowych i posprzątanie pokoju (są to wartości True lub False). Pomiędzy nimi znajduje się potężny operator and.

📊 Tabela prawdy: AND

Operator and ("i") sprawia, że CAŁE wyrażenie jest równe True TYLKO WTEDY, gdy OBYDWIE jego strony są równe True. Spójrzmy na tabelę:

Warunek AWarunek BWynik A and B
TrueTrueTrue
TrueFalseFalse
FalseTrueFalse
FalseFalseFalse
print(True and True)    # Wydrukuje: True
print(True and False)   # Wydrukuje: False

🎯 Czy Jasio może mieć szczeniaka?

+100 XP

Zadanie - Użycie AND

Spójrz na poniższy kod określający, czy Jasiowi uda się namówić rodziców na szczeniaka. W tym celu musi mieć czas wolny ORAZ być odpowiedzialnym. Jaki będzie wynik (True/False)?

have_time = True
is_responsible = False

can_have_puppy = is_responsible and have_time
print(can_have_puppy)

Wynik to oczywiście False. Mimo posiadania czasu, brak odpowiedzialności (False z lewej strony and) psuje cały plan!

📏 Częste użycie AND: Sprawdzanie zakresów

Częstym, praktycznym wykorzystaniem tego operatora w programowaniu jest sprawdzenie, czy liczba znajduje się w jakimś konkretnym przedziale: czyli czy jest większa od minimum I zarazem mniejsza niż maksimum.

# Załóżmy, że pytamy program czy wynik testu jest poprawny.
percent = 85

# Sprawdzamy czy % to conajmniej 0 I JEDNOCZEŚNIE maksymalnie 100:
if percent >= 0 and percent <= 100:
    print("Poprawna wartość")
Jeśli percent będzie miał wartość z zakresu od 0 do 100, to zostanie wyświetlona "Poprawna wartość". W przeciwnym wypadku (np. ktoś wpisał -5 albo 105), warunek ten w ogóle się nie spełni.

👐 Operator 'or' (Alternatywa)

Niestety, we wcześniejszej historyjce Jasio nie odrobił lekcji, zatem nie mógł pograć na komputerze. Wtedy jednak zadzwonili do niego znajomi i zaprosili go do kina. Jasio poszedł do mamy i poprosił o pieniądze na wyjście.

"Dostaniesz pieniądze, jeśli posprzątasz garaż lub umyjesz samochód."
👩‍🏫
# Ten nowy warunek dla kina można zapisać tak:
can_go_to_cinema = cleaned_garage or washed_car

📊 Tabela prawdy: OR

Operator or (po polsku "lub") reprezentuje alternatywę. Całe wyrażenie zwraca True, gdy spełnione jest albo jedno, albo drugie, albo nawet oba warunki jednocześnie! Wystarczy mu choć odrobina prawdy.

Warunek AWarunek BWynik A or B
TrueTrueTrue
TrueFalseTrue
FalseTrueTrue
FalseFalseFalse
print(False or True)   # Wydrukuje: True
print(False or False)  # Wydrukuje: False

⚠️ Pułapka słowa "lub"

Wracając do naszej historii: Jasio tak się zapalił do pracy, że zarówno posprzątał garaż, jak i umył samochód! Zdziwiona mama powiedziała: "Chciałam, byś zrobił JEDNO albo DRUGIE, a nie obydwa".

Jasio jednak znał się na programowaniu i odpowiedział:

"Użyłaś łącznika 'lub', który akceptuje zrobienie zarówno jednego, jak i drugiego! To działa w języku polskim podobnie jak operator or w programowaniu".
Dlatego spójrz raz jeszcze na pierwszą linijkę tabelki z poprzedniego slajdu: True or True rzuca na koniec radosne True! Jasio był cwany, a mama zaakceptowała wyjaśnienie programistyczne. Jasio poszedł z kolegami do kina.

🔄 Operator 'not' (Negacja)

Ostatnim operatorem logicznym, który powinniśmy poznać, jest zaprzeczenie, czyli not stawiane PRZED wartością logiczną.

Słowo "not" oznacza "nie". Podobnie jak minus (-) przed liczbą zamienia ją na odwrotną, tak not przed wartością logiczną zamienia ją na przeciwną. Z True robi False, a z False robi True.
Warunek (cond)not cond
TrueFalse
FalseTrue
is_boring = False
# Czy ten kurs NIE jest nudny?
print(not is_boring)      # Wypisze: True!

🛡️ Tarcza ochronna - NOT w nawiasach

Zazwyczaj nie dajemy `not` przed pojedynczą zmienną. Znacznie częściej kładziemy to słowo przed wielkim, skomplikowanym warunkiem, zamkniętym w nawiasach, żeby odwrócić JEGO CAŁKOWITY WYNIK.

Kolejna rozmowa mamy z Jasiem:

"Będziesz mógł grać na komputerze, jeśli nie zawalisz sprawdzianu z matematyki i posprzątasz pokój".
# Wynik negatywny to False (nie zawalił)
failed_math_test = False
cleaned_room = True

# Chcemy by oblał sprawdzian LUB nie posprzątał: to zła ścieżka.
# Oplatamy wszystko NAWIASAMI i dopiero to odwracamy słowem NOT:
can_play = not (failed_math_test and not cleaned_room)
Zwróć uwagę, jak nawiasy zmieniają działanie! Podobnie jak w matematyce -(10 + 5) daje -15. Cały fragment obłożony nawiasami rozwiązuje się najpierw (np. dając False), a potem przylepia się do niego not zamieniając wynik na True.

🎭 Podwójne zaprzeczenie

Czy zastanawiałeś się, co się stanie, gdy napiszesz "nie, nie zjadłem tego ciastka"? Programowanie w 100% akceptuje podwójne zaprzeczenie!

print(True)                             # True
print(not True)                         # False
print(not not True)                     # True! (znowu prawda)
print(not not not True)                 # False
print(not not not not True)             # True
Bawiąc się językiem, możemy powiedzieć: nie jest tak, że programowanie nie akceptuje podwójnego zaprzeczenia. A nawet (nie nie nie nie) akceptuje wielokrotne zaprzeczenie. Każdy kolejny znak "not" po prostu odwraca wartość, zupełnie jak znak minus z matematyki przed zmienną (np. print(-negative) dające cyfrę 1).

🗣️ Jak czytać to na głos?

Aby nie pogubić się w zawiłych warunkach, warto wyrobić w sobie nawyk czytania wyrażeń logicznych na głos. Spróbuj stosować te tłumaczenia:

  • and czytaj jako i.
  • or czytaj jako lub.
  • not przed zmienną czytaj jako nie.
  • not (...) przed całym NAWIASEM czytaj jako: nie jest tak, że...

Poćwiczmy to! Załóżmy takie znaczenie naszych pudełek:

🗣️ Trening z czytania!

Przeczytaj w głowie poniższe zdania w języku Python, a następnie sprawdź tłumaczenie obok:

cleaned_room and passed_test
# posprzątał pokój i zaliczył sprawdzian

not is_grounded or passed_test
# nie ma szlabanu lub zaliczył sprawdzian

cleaned_room and not passed_test
# posprzątał pokój i nie zaliczył sprawdzianu

not (is_grounded or not passed_test)
# NIE JEST TAK, ŻE (ma szlaban lub nie zaliczył sprawdzianu)

Jeśli masz ogromne problemy z rozszyfrowaniem wielokrotnych zaprzeczeń jak z ostatniego przykładu... możesz użyć sztuczek znanych jako prawa De Morgana, ale często łatwiej przepisać warunek od nowa w czytelniejszy sposób!

🎯 Ćwiczenie: Puzzle z kodem

+250 XP

Kto jest w stanie przewidzieć wynik?

Spójrz na poniższe zmienne i odpowiedz, co wypiszą na ekranie wszystkie 3 printy? Bądź dokładny jak interpreter Pythona!

has_computer = True
passed_test = False
is_grounded = False

# Wypisz wyniki tych 3 komend:
print(has_computer and passed_test)
print(passed_test or is_grounded)
print(has_computer and not passed_test)

Zapisz odpowiedzi w głowie, na następnym slajdzie znajdziesz rozwiązanie.

✅ Rozwiązanie Puzzli

  1. print(has_computer and passed_test)
    Czyli (True AND False). Funkcja 'and' wymaga dwóch prawd. Niestety, test został oblany.
    Wynik: False

  2. print(passed_test or is_grounded)
    Czyli (False OR False). Funkcja 'or' wybacza wiele, ale potrzebuje chociaż jednego sukcesu. Tutaj go brakuje.
    Wynik: False

  3. print(has_computer and not passed_test)
    Mamy komputer (True) oraz not passed_test (czyli not False, co daje True). Razem mamy True AND True!
    Wynik: True

🛡️ Warunek do akcji! (Instrukcja 'if')

Wszystko, o czym się do tej pory uczyliśmy w tym rozdziale (obliczanie, kiedy pojawia się Prawda, a kiedy Fałsz) dążyło do jednego celu. Przekazania tego wyniku do instrukcji decyzyjnej!

Aby w kodzie zrobić coś pod określonym warunkiem, używamy instrukcji warunkowej if ("jeśli"). Zaczynamy od tego słowa kluczowego, po nim umieszczamy nasz "warunek" (który zamieni się w True lub False), a na końcu obowiązkowo stawiamy dwukropek :.
if tweet_type == "promotional":
    print("Promowany")

Linia z tekstem "Promowany" wcięta niżej, jest nazywana Ciałem Warunku (Body). Ten kod wykona się TYLKO jeśli odpowiedź z zapytania po słowie if wyniosła True.

📏 Wcięcia (Indentation) to klucz!

Wcięcia, czyli dodatkowe spacje lub tabulatory przed instrukcjami, są BARDZO ważne w języku Python. Popatrz na poniższy kod:

if False:
    print("A")
print("B")

Co powinno zostać wypisane? Odpowiedź to tylko B, ponieważ print("A") znajduje się w ciele instrukcji if, której warunek to False (czyli się nie wykona). Skąd jednak wiemy, że literka B nie jest w tym ciele?

Oczywiście – jest dociśnięta do lewej krawędzi (nie posiada wcięcia). Dzięki wcięciom Python jest w stanie odróżnić odcięte fragmenty "zawartości if" od reszty zwykłego, głównego kodu.

⚔️ Wielka Wojna (Spacje czy Taby?)

Skoro wcięcia w Pythonie oznaczają dosłownie, czy kod należy do bloku warunkowego czy nie, to jak najlepiej je robić klawiaturą?

Przez długi czas toczyła się ostra dyskusja nad tym, czy tworzyć wcięcia poprzez stawianie zwykłych Spacji, czy przez pojedynczy znak Tabulacji (klawisz TAB). Nigdy nie należy ich w każdym razie mieszać w jednym pliku, bo Python zwariuje!

Zestaw reguł określających formatowanie kodu w Pythonie (np. znany dokument PEP 8) zaleca twardo: Większość projektów stosuje wcięcia na dokładnie CZTERY SPACJE. Profesjonalne edytory, jak PyCharm, potrafią sprytnie zamieniać jedno wciśnięcie klawisza Tab od razu w 4 spacje!

🤷‍♂️ Co, jeśli nic nie robię? (Słowo 'pass')

Czasem projektujemy architekturę i wiemy, że potrzebujemy w tym miejscu warunku, ale nie mamy jeszcze czasu napisać do niego kodu. Jeśli zostawisz wcięte miejsce całkiem puste, Python wyrzuci "IndentationError".

if is_logged:
    pass
Słowo kluczowe pass nie wykonuje żadnej operacji (to dosłownie wypełniacz). Jest jednak absolutnie konieczne by "oszukać" wymagania Pythona. Ratuje nas od błędu i pozwala kodowi zadziałać bez zawartości if'a, informując programistów czytających kod, że to puste ciało zostawiono tu umyślnie.

🎭 'Else' (W przeciwnym wypadku)

Ciało w instrukcji if wykona się tylko w przypadku spełnienia warunku. Ale co zrobimy, jeśli chcielibyśmy odpalić też akcję awaryjną na wypadek fałszu?

Sytuacja w której mówimy "Zrób to, a w przeciwnym razie zrób tamto" jest tak częsta, że wprowadzono słowo uzupełniające: else.

if tweet_type == "promotional":
    print("Promowany")    <- Wykona się tylko dla True!
else:
    print("Zwykły")       <- Wykona się zawsze, gdy warunek wyżej poległ (False).
Zauważ, że else: nie przyjmuje żadnego własnego warunku do sprawdzania! Musi on zawsze stać na tej samej linii marginesu (w lewo) co zaprzyjaźniony z nim if, do którego się odnosi.

📉 'Elif' (Alternatywne Drabinki)

Co natomiast, gdy mamy nie dwie ("tak" lub "nie"), ale więcej opcji do wyboru? Używamy dodatkowych szczebli w naszej decyzji, czyli słowa elif (skrót od "else if", czyli "w przeciwnym wypadku, jeśli...").

if tweet_type == "promotional":
    print("Promowany")
elif tweet_type == "followed":
    print("Zwykły")
elif tweet_type == "own":
    print("Własny")
else:
    print("Inny")
Złota zasada Drabinki!
Python sprawdza kolejne części od GÓRY do DOŁU. Gdy tylko znajdzie chociaż jedno `True`, wywołuje jego ciało po czym całkowicie zakańcza sprawdzanie reszty. Bloków elif reprezentujących alternatywne wybory może być pod sobą nieskończenie wiele!

⚠️ Błąd "Złej Kolejności" Drabinki

Ponieważ komputer przerywa działanie `if-elif` na pierwszym sukcesie (pierwszej znalezionej prawdzie), łatwo tu o kolosalny błąd podczas sprawdzania liczb (np. ocen za procenty testu).

# Pokaże się ocena za 50% chociaż gracz napisał test na 100%! Dlaczego?
if percent >= 50:
    print("No, powiedzmy - Dostateczny")
elif percent >= 80:
    print("Raczej tak - Dobry")
elif percent >= 95:
    print("Na 100% - Celujący")
Rozwiązanie! Drabinkę elif zawsze zaczynamy pisać od warunków najbardziej wymagających / wąskich (np. czy ma >= 95%), schodząc powoli w dół aż do tych wyłapujących największą resztę (>= 50%). W przeciwnym razie pierwszy łagodny warunek na górze (np. 100 jest przecież > 50) złapie wszystko i pożre program!

🎯 Ćwiczenie: Mieszane napoje (If vs Elif)

+350 XP

Dziwne zachowanie barmana

Napisz kod, który realizuje poniższe wymagania dla serwowania napojów w oparciu o zmienną logiczną coffee_finished (czy dopił już kawę?) i liczbową days_until_deadline (ile dni do terminu?).

  • Jeśli coffee_finished to False ➔ Wypisz "Piję kawę".
  • Jeśli dni do deadline to mniej niż 2 ➔ Wypisz "Pracuję".
  • W każdym INNYM całkowicie wypadku ➔ Wypisz "Uczę się programowania!".

Zastanów się: Czy połączyć dwa pierwsze polecenia w jeden wspólny łańcuch `if` - `elif`? Czy może rozbić to na dwa odrębne, wolnostojące ify?

✅ Rozwiązanie: Mieszane napoje

W treści zadania ukryto pułapkę słowną. Skoro użyto opcji "w przeciwnym wypadku", musimy użyć łańcucha powiązanego wspólnym planem ratunkowym (else).

if coffee_finished == False:        # (albo krócej: if not coffee_finished:)
    print("Piję kawę")
elif days_until_deadline < 2:
    print("Pracuję")
else:
    print("Uczę się programowania!")
Sprawdź, jak zachowa się Twój kod dla wartości: coffee_finished = False i zarazem days_until_deadline = 1.
Dzięki użyciu drabinki z elif, kod wypisze tylko "Piję kawę" (i wyłączy strukturę). Gdybyś użył dwóch wolnostojących `if`ów jeden pod drugim, programista robiłby dwie rzeczy na raz: "Piję kawę", oraz "Pracuję"!

🚀 Finał Decyzji

Zrozumiałeś, jak komputer nawiguje swoim własnym losem w ułamku sekundy, łącząc pętle, ify oraz logikę wykrzykników.


🎓 +10 000 XP Otrzymano

Gratulacje po przetrwaniu tej intensywnej przeprawy przez dokumentacje języka Python. Jesteś gotów zbudować swój własny, w pełni decyzyjny kod EduQuesta!