Sterowanie przepływem w Pythonie — pętle

Sterowanie przepływem to złożony proces. Jeśli instrukcje warunkowe (czyli tzw. „if-y”) pomagają algorytmowi w podejmowaniu decyzji na podstawie zaistniałych warunków, pętle decydują czy i ile razy dany fragment kodu zostanie wykonany.

To tak jak z ćwiczeniami na siłowni. Wiesz, że musisz przejść przez wszystkie maszyny na nogi i na każdej wykonać dwanaście powtórzeń – to nic innego jak podwójna pętla. Po przetłumaczeniu na pythonowy, mielibyśmy for i in range(3), a wewnątrz drugą pętlę do każdej maszyny for j in range (12). Albo raczej while siła > 0. Do środka dodałabym jeszcze małego if-a: if tired: break. I bam, piękny, złożony, czysty kod mojego treningu na siłowni gotowy.

Pętla for

Pętla for w Pythonie to konstrukcja służąca do iteracji po sekwencji (np. liście, krotce, łańcuchu znaków) lub innych obiektach iterowalnych. Iteracja oznacza powtarzanie określonego bloku kodu dla każdego elementu sekwencji.

# jeśli mamy listę obiektów i chcemy wykonać działanie dla każdego elementu 
#z tej listy
for user in users:         
    send_email(user)

#jeśli chcemy wykonać fragment kodu z góry ustaloną liczbę razy
for i in range(10):        
    print(i)

#jeśli chcemy iterować po jakiejś sekwencji i znać jej indeks
fruits = ['apple', 'banana', 'cherry']
for i, fruit in enumerate(fruits):
    print(f"{i}: {fruit}")

Cechy pętli for:

  • Pętla for może iterować po każdym obiekcie, który implementuje protokół iteracyjny, czyli np. po listach, stringach, słownikach, zbiorach, zakresach (range) czy plikach (!).
  • Jest bezpieczna, tzn., że nie ma zagrożenia, że poleci o jedną pętlę za daleko i zabraknie jej przez co iterować (jest bardziej podobna do pętli for-each z Javy niż klasycznej pętli for).
  • Prosta składnia sprawia, że pętla for w Pythonie jest krótsza, bardziej czytelna i bezpieczniejsza.

Pętla while

Pętla while w Pythonie to struktura sterująca, która umożliwia wielokrotne wykonywanie bloku instrukcji, dopóki określony warunek nie zostanie spełniony. Gdy warunek stanie się fałszywy, pętla zostaje zakończona i program kontynuuje wykonanie od linii po pętli.

# ✅ poprawnie skonstruowana pętla z "wartownikiem"
balance = 100
while balance > 0:
    balance -= 10

Rada!
Używaj pętli while, kiedy nie wiesz z góry, ile iteracji potrzeba. Ale uważaj, czasem łatwo dać się wpuścić w maliny i uruchomić nieskończoną pętlę. Zawsze dodawaj zmienną “wartownika” (ang. sentinel variable)!

# ❌  przykład niepoprawnej nieskończonej pętli:
x = 5
while x > 0:
    print(x)


# ✅ poprawnie skonstruowana nieskończona pętla: 
while True:
    answer = input("Podaj hasło dostępu: ")
    
    if answer == "openAI":
        print("Dostęp przyznany.")
        break  # ← bezpieczne zakończenie pętli
    else:
        print("Niepoprawne hasło. Spróbuj ponownie.")

Pętla break / continue / else

Instrukcje break, continue, i else (fun fact: to nie to samo else co w instrukcjach warunkowych!) to właściwie nie pętla sama w sobie, ale ciekawe rozszerzenie klasycznej pętli for lub while. Dzięki nim pętle są dużo bardziej dynamiczne i nie np. nie musimy iterować do końca pętli po znalezieniu zmiennej, na której nam zależało. Albo nie musimy wykonywać instrukcji dla wszystkich elementów pętli (niektóre możemy ominąć bez przerywania całej pętli). Wreszcie możemy dodać opcję „finally, ale tylko jak nie było break’a” czyli else.

! Uwaga !
Zauważcie, że instrukcja else wewnątrz pętli wygląda jak źle wcięty element instrukcji warunkowej if-elif-else. To jedno z miejsc, w którym łatwo popełnić błąd.

# ✅ poprawne użycie instrukcji "break" i "else": 
users = ["Anna", "Bartek", "Celina"]
search = "Dorota"

for user in users:
    if user == search:
        print("Znaleziono!")
        break
else:
    print("Brak użytkownika.")


# ✅ poprawne użycie instrukcji "continue": 
for num in range(5):
    if num == 2:
        continue
    print(num)

Cechy pętli break / continue / else

Instrukcja break przerywa pętlę natychmiast, niezależnie od tego, czy warunek działania pętli został wypełniony czy nie.
Instrukcja continue przerywa bieżącą iterację i przechodzi do następnej, bez wykonywania dalszego kodu w pętli.
Instrukcja else w pętli for lub while wykonuje się tylko raz, na końcu pętli — ale tylko wtedy, gdy pętla nie została przerwana przez break.

List, dict & set comprehensions

Comprehension to zwięzły sposób tworzenia nowych list, słowników lub zbiorów na podstawie istniejących danych — w jednej linijce. Są czytelniejsze, szybsze i bardziej charakterystyczne dla Pythona niż zwykła pętla for.

# ✅ poprawne użycie "comprehension": 
squares = [x * x for x in range(10)]

# ✅ ten sam kod napisany "klasycznie": 
squares = []
for x in range(10):
    squares.append(x * x)

Podobnie jest z Dict Comprehension.

prices_usd = {
    'milk': 2.5,
    'bread': 1.2,
    'coffee': 6.0,
    'apples': 3.3
}

# ✅ poprawne użycie "Dict Comprehension": 
prices_pl = {prod: round(price * 4.4, 2) for prod, price in prices_usd.items()}


# ✅ ten sam kod napisany "klasycznie": 
prices_pl = {}

for prod, price in prices_usd.items():
    prices_pl[prod] = round(price * 4.4, 2) 

! Rada !
Nie nadużywaj comprehension – gdy logika staje się złożona, wróć do zwykłej pętli.

Generator expressions

Generator expressions to konstrukcje bardzo podobne do list comprehension, ale zamiast tworzyć całą listę w pamięci, tworzymy obiekt generatora, który produkuje wartości na bieżąco – tylko wtedy, gdy są potrzebne.

Generator nie trzyma wszystkiego w pamięci (zużywa pamięć dopiero wtedy, kiedy po nim iterujesz), działa szybciej w iteracjach i idealny do przetwarzania dużych zbiorów danych, strumieni, plików itp.

# ✅ Generator nie tworzy niczego od razu
generator_kwadratów = (x * x for x in range(1_000_000))
print(type(generator_kwadratów))  # <class 'generator'>

# ❌ Lista od razu zajmuje miejsce w pamięci
lista_kwadratów = [x * x for x in range(1_000_000)]

Zwróć uwagę, że generatory wyglądają bardzo podobnie do list, ale wykorzystują nawiasy okrągłe zamiast kwadratowych.

Funkcje wyższego rzędu

Funkcja wyższego rzędu to taka, która przyjmuje inną funkcję jako argument i/lub zwraca funkcję jako wynik.

W Pythonie to nic niezwykłego – bo funkcje są „first-class citizens”, czyli mogą być przekazywane jak zmienne. Dobrymi przykładami takich funkcji są m.in map(func, iterable), filter(pred, iterable), any() i all().

Cechy funkcji wyższego rzędu

Funkcje wyższego rzędu mają wiele zalet:

  • Zwięzłość – potrzebują mniej kodu niż w pętli for
  • Czytelność – kod opisuje co robimy, a nie jak
  • Wydajność – funkcje map() i filter() zwracają obiekty leniwe (nie tworzą listy od razu)
  • Komponowalność – łatwo łączyć je ze sobą i z generatorami.
Funkcja map(func, iterable)

Funkcja map() przyjmuje funkcję (np. str.upper, która zamienia litery na wielkie) oraz dowolny obiekt iterowalny (np. listę) i zwraca obiekt typu map. Ten obiekt jest leniwy — nie wykonuje działania od razu, tylko generuje kolejne wyniki dopiero w trakcie iteracji.
Aby zobaczyć wyniki lub je wykorzystać, należy iterować po tym obiekcie, np. otaczając go list() lub używając w pętli for.

# ✅ Poprawne użycie funkcji map(func, iterable)
names = ["ala", "bartek", "celina"]
uppercased = map(str.upper, names)

# ❌ uwaga! Nie można wywoływać map bezpośrednio.
print(uppercased)  # <map object at 0x12345678> ← zwraca lazy obiekt map

# ✅ Należy otoczyć map wrapperem z listy.
print(list(uppercased))  # ['ALA', 'BARTEK', 'CELINA']

# ✅ To samo klasycznie, z użyciem pętli for
names = ["ala", "bartek", "celina"]
uppercased = []

for name in names:
    uppercased.append(name.upper())

print(uppercased)  # ['ALA', 'BARTEK', 'CELINA']

Funkcja filter(pred, iterable)

Funkcja filter() przyjmuje funkcję-predykat (czyli funkcję, która zwraca True lub False) oraz dowolny obiekt iterowalny (np. listę) i zwraca obiekt typu filter. Ten obiekt jest leniwy – nie filtruje elementów od razu, tylko generuje je podczas iteracji.
Aby zobaczyć wyniki lub z nich skorzystać, należy iterować po obiekcie filter, np. otaczając go list() lub używając w pętli for.

# ✅ Poprawne użycie funkcji filter(pred, iterable)
liczby = [1, 2, 3, 4, 5]
parzyste = filter(lambda x: x % 2 == 0, liczby)

print(list(parzyste))  # [2, 4]

# ❌ uwaga! Nie można wywoływać obiektu filter bezpośrednio.
print(parzyste)  # <filter object at 0x12345678> ← zwraca lazy obiekt map

# ✅ Należy otoczyć obiekt filter wrapperem z listy.
print(list(parzyste))  # [2, 4]

# ✅ To samo klasycznie, z użyciem pętli for
liczby = [1, 2, 3, 4, 5]
parzyste = []

for x in liczby:
    if x % 2 == 0:
        parzyste.append(x)

print(parzyste)  # [2, 4]

Funkcja any()

Funkcja any() przyjmuje dowolny iterowalny obiekt (np. listę, generator, wynik map() lub filter()) i zwraca:

  • True – jeśli przynajmniej jeden element jest logicznie True,
  • False – jeśli wszystkie elementy są False.

Jest zwięzła, czytelne i działają leniwie — przerywają działanie natychmiast po znalezieniu pierwszego True.

# ✅ Poprawne użycie funkcji any()
liczby = [0, 0, 3, 0]
wynik = any(x > 0 for x in liczby)
print(wynik)                          # True, bo 3 > 0

# ✅ To samo klasycznie, z użyciem pętli for
liczby = [0, 0, 3, 0]
znaleziono = False  # zmienna wartownika

for x in liczby:
    if x > 0:
        znaleziono = True
        break  # przerywamy, bo już wiemy, że warunek spełniony

print(znaleziono)                    # True

Funkcja all()

Funkcja all() przyjmuje dowolny iterowalny obiekt (np. listę, generator, wynik map() lub filter()) i zwraca:

  • True – jeśli wszystkie elementy są logicznie True,
  • False – jeśli choć jeden element jest False.

Działa leniwe – przerywa działanie przy pierwszym False.

# ✅ Poprawne użycie funkcji filter(pred, iterable)
liczby = [1, 2, 3, 4]
wynik = all(x > 0 for x in liczby)
print(wynik)                  # True


# ✅ To samo klasycznie, z użyciem pętli for
liczby = [1, 2, 3, 4]
naturalne = True  # zmienna wartownika

for x in liczby:
    if x <= 0:
        naturalne = False
        break  

print(naturalne)              # True

Którą pętlę wybrać?

ScenariuszNajlepsze narzędzieDlaczego?
Proste filtrowanie/przekształcenie listyComprehensionZwięzłe, czytelne, szybkie
Operacje strumieniowe na dużych danychGenerator / map / filterBrak alokacji ogromnych list
Iteracja z wczesnym wyjściemfor + breakBlok else pozwoli obsłużyć „nie znaleziono”
Niewiadoma liczba krokówwhileWarunek kontroluje zakończenie
Weryfikacja wielu dyskretnych przypadkówmatch-case lub łańcuch elifPattern matching jest szybszy i klarowny

Sterowanie przepływem – najlepsze praktyki i dobre rady

Poniżej znajdziesz garść najlepszych praktyk, które warto stosować (choć zazwyczaj alternatywa nie jest stricte błędem), by kod był bardziej czytelny i łatwiejszy do debugowania:

Funkcja enumerate() zamiast licznika ręcznego

Funkcja enumerate() daje jednocześnie indeks i wartość, a argument 1 sprawia, że liczymy od 1 (nie od zera).

# ✅ zalecane  
for i, wiersz in enumerate(wiersze, 1):
    print(f"Wiersz {i}: {wiersz}")

# ❌ niezalecane
for i in range(len(wiersze)):    print(f"Wiersz {i}: wiersze[i]")

Iteracja po dwóch listach jednocześnie za pomocą zip()

Funkcja zip() Łączy elementy dwóch (lub więcej) list pozycyjnie. W przypadku dwóch list o różnej długości, iteracja kończy się na tej krótszej.

# ✅ zalecane  
for a, b in zip(lista_a, lista_b):
    print(f"Para: {a} i {b}")

# ❌ niezalecane
for i in range(len(lista_a)):
    print(f"Para: {lista_a[i]} i {lista_b[i]}")

Unpacking w pętli – zamiast indeksów

Jeśli elementy to krotki/listy – rozpakuj je bezpośrednio. To rozwiązanie jest dużo bardziej czytelne, zajmuje mniej miejsca i daje mniejsze pole do popełnienia błędu.

# ✅ zalecane  
for x, y, z in points:
    print(f"X: {x}, Y: {y}, Z: {z}")

# ❌ niezalecane
for i in range(len(points)):
    x = points[i][0]
    y = points[i][1]
    z = points[i][2]
    print(f"X: {x}, Y: {y}, Z: {z}")

Używaj any() i all() do szybkich warunków zbiorczych

Funkcja any() sprawdza, czy przynajmniej jeden element spełnia warunek. Funkcja all() – czy wszystkie spełniają. Warto znać i używać obu.

# ✅ zalecane  
if any(x > 100 for x in values):
    alert("Za duża wartość!")

Spłaszczanie list (flattening) – nested loop w comprehension

Spłaszczanie list to genialne narzędzie w Pythonie, dzięki któremu nie musisz pisać zagnieżdżonych pętli.

# ✅ zalecane  
nested = [[1, 2], [3, 4]]
flat = [x for sub in nested for x in sub]
print(flat)  # [1, 2, 3, 4]

# ❌ niezalecane
flat = []
for sub in nested:
    for x in sub:
        flat.append(x)

print(flat)  # [1, 2, 3, 4

Instrukcje for + else – idealne przy wyszukiwaniu

Instrukcja else jesy wykonywania wyłącznie w przypadku, jeśli pętla nie zostanie przerwana za pomocą instrukcji break. To dobre rozwiązanie np. przy wyszukiwaniu i elegancka forma na notyfikację „znaleziono/nie znaleziono”.

# ✅ zalecane  
for x in items:
    if x == "szukane":
        print("Znaleziono!")
        break
else:
    print("Nie znaleziono.")

Sterowanie przepływem – podsumowanie

Warunki sterują co się dzieje, pętle – ile razy. W połączeniu z idiomami jak enumerate, comprehension czy match-case pozwalają pisać zaawansowany kod, który jest jednocześnie czytelny i skuteczny.

Pętle (głównie for i while) pozwalają wykonywać powtarzalne czynności automatycznie i bezbłędnie. Warunki (if, elif, else, match-case) umożliwiają podejmowanie decyzji w zależności od danych wejściowych.

To narzędzia, który umożliwiają pisanie czytelnego, efektywnego i skalowalnego kodu – zarówno dla ludzi, jak i dla maszyny. Wiele z nich jest charakterystycznych tylko dla Pythona. Umiejętność ich czytania i stosowania świadczą o biegłości w języku – i dokładnie to chcemy osiągnąć.


Co dalej?

Zapisz się do naszego newslettera, żeby nigdy nie przegapić żadnego wartościowego artykułu.

Zajrzyj do sekcji Kariera w AI, gdzie znajdziesz konkretne materiały o zmianach na rynku pracy – w Polsce i na świecie – oraz ścieżkach kariery związanych ze sztuczną inteligencją (nie tylko jako programista!).

→ A jeśli chcesz pisać modele i pracować jako Architekt AI, ale nie wiesz, od czego zacząć (lub utknąłeś gdzieś na ścieżce), odwiedź dział Nauka AI – czeka tam wiedza, ciekawostki i realne wsparcie.


! Uwaga

Niniejszy ebook ma charakter informacyjny i edukacyjny. Nie stanowi porady prawnej ani oferty pracy w rozumieniu przepisów krajowych lub unijnych.
Przy tworzeniu niniejszego artykułu korzystano ze wsparcia narzędzi opartych na sztucznej inteligencji – m.in. w zakresie porządkowania treści, analizy źródeł, przyspieszenia redakcji i wyszukiwania źródeł Jednak wszelkie decyzje dotycząca treści, interpretacji i ostatecznej formy zostały podjęte przez człowieka.

Podziel się swoją opinią

Jeden komentarz

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *