Pętle zagnieżdżone w Pythonie
Pętle zagnieżdżone to po prostu pętla wewnątrz innej pętli. Brzmi prosto, ale sporo osób się na tym gubi. Używamy ich, gdy musimy przejść przez dane wielowymiarowe - tabele w excelu, skanowanie powierzchni planety punkt po punkcie, przeszukiwanie map czy analizowanie obrazów satelitarnych.
Zacznijmy od prostej pętli
Najpierw zobaczmy, jak działa zwykła pętla. Wyobraź sobie, że skanujemy jeden rząd powierzchni Marsa podzielony na kwadraty 1 x 1 km:
# Skanujemy jeden rząd powierzchni Marsa
for x_position in range(5):
print(f"Skanowanie pozycji X: {x_position}")
To da nam:
Skanowanie pozycji X: 0 Skanowanie pozycji X: 1 Skanowanie pozycji X: 2 Skanowanie pozycji X: 3 Skanowanie pozycji X: 4
Problem w tym, że to tylko jedna linia. Powierzchnia Marsa ma dwa wymiary - długość i szerokość geograficzną. x_position w tym wypadku pokazuje nam krok po kroku który kwadrat skanujemy. print() tak naprawdę niczego nie skanuje na marsie, chodzi tylko a zaobserowanie zmieniającego się licznika i wykonanie jakiejś operacji w danym przebiegu pętli.
Dodajemy drugą pętlę
Teraz zeskanujmy cały sektor - czyli wiele rzędów:
# Skanujemy cały sektor 5x5 km
for y_position in range(5):
for x_position in range(5):
print(f"Skanowanie ({x_position}, {y_position})")
Co się tutaj dzieje?
Zewnętrzna pętla (y_position) odpowiada za rzędy. Dla każdego rzędu wewnętrzna pętla (x_position) przechodzi przez wszystkie kolumny zanim przejdzie do kolejnego rzędu. Czyli:
- Gdy
y_position = 0,x_positionprzejdzie przez 0, 1, 2, 3, 4 - Potem
y_position = 1, i znowux_positionprzez 0, 1, 2, 3, 4 - I tak dalej...
Razem mamy 25 punktów (5×5).

Dlaczego NIE używamy tu popularnych i, j?
Zobaczysz w internecie mnóstwo przykładów z i i j. Problem w tym, że nikt nie wie, co one oznaczają:
# ŹLE - co to jest i? Co to j?
for i in range(5):
for j in range(5):
print(i, j)
Porównaj to z:
# DOBRZE - od razu wiadomo co to
for row in range(5):
for column in range(5):
print(row, column)
Kiedy wrócisz do tego kodu za tydzień, od razu zrozumiesz co robi druga wersja. W przykładach marsjańskich używamy nazw jak x_position, y_position, scan_x, rover_id - wszystko co pomoże zrozumieć kod.
Praktyczny przykład: Poszukiwanie zaginionych łazików
Stworzymy system radarowy, który skanuje powierzchnię Marsa i szuka łazików, które straciły kontakt z bazą. Najpierw losowo rozmieścimy kilka łazików, potem je znajdziemy. Bardziej przyziemny przykład mógłby obejmować przeszukiwanie wyników w tabeli w celu zlokalizowania błednych obliczeń finansowych. Szukanie łazików na Marsie jest ciekawsze :D
import random
# Generujemy pozycje zaginionych łazików w sektorze 10x10 km
lost_rovers = []
rover_names = ["Spirit", "Opportunity", "Curiosity", "Perseverance", "Zhurong"]
for rover_id in range(5):
x = random.randint(0, 9)
y = random.randint(0, 9)
lost_rovers.append((x, y, rover_names[rover_id]))
print("=== MAPA POWIERZCHNI MARSA ===\n")
# Skanujemy powierzchnię punkt po punkcie
for scan_y in range(10):
for scan_x in range(10):
# Sprawdzamy czy na tej pozycji jest łazik
rover_found = None
for x, y, name in lost_rovers:
if x == scan_x and y == scan_y:
rover_found = name
break
if rover_found:
print("🔴", end=" ") # Łazik!
else:
print("⚫", end=" ") # Pusta powierzchnia
print() # Nowa linia po każdym rzędzie
# Lista znalezionych łazików
print("\n=== RAPORT Z ODNALEZIONYCH ŁAZIKÓW ===\n")
for scan_y in range(10):
for scan_x in range(10):
for x, y, name in lost_rovers:
if x == scan_x and y == scan_y:
print(f"🛰️ Łazik {name} odnaleziony na współrzędnych ({scan_x}, {scan_y})")
Wynik może wyglądać tak:
=== MAPA POWIERZCHNI MARSA === ⚫ ⚫ ⚫ 🔴 ⚫ ⚫ ⚫ ⚫ ⚫ ⚫
⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫
⚫ ⚫ ⚫ ⚫ ⚫ 🔴 ⚫ ⚫ ⚫ ⚫
⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫
⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫
⚫ 🔴 ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫
⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫
⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ 🔴 ⚫ ⚫
⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫
⚫ ⚫ ⚫ ⚫ ⚫ ⚫ 🔴 ⚫ ⚫ ⚫ === RAPORT Z ODNALEZIONYCH ŁAZIKÓW === 🛰️ Łazik Spirit odnaleziony na współrzędnych (3, 0) 🛰️ Łazik Opportunity odnaleziony na współrzędnych (5, 2) 🛰️ Łazik Curiosity odnaleziony na współrzędnych (1, 5) 🛰️ Łazik Perseverance odnaleziony na współrzędnych (7, 7) 🛰️ Łazik Zhurong odnaleziony na współrzędnych (6, 9)
Zauważ, że pierwsza pętla tworzy wizualizację (rysuje mapę), a druga wypisuje listę tekstową. Obie robią to samo skanowanie, tylko wyświetlają wyniki inaczej.
Częste błędy początkujących
Błąd 1: Te same nazwy zmiennych
# ŹLE - wewnętrzna pętla nadpisuje x!
for x in range(3):
for x in range(3): # ← Nadpisuje zewnętrzne x
print(x)
Python nie wyrzuci błędu, ale dostaniesz dziwne wyniki. Zawsze używaj różnych nazw.
Błąd 2: Niewłaściwe wcięcia
# Gdzie powinno być to print?
for y in range(3):
for x in range(3):
print(f"({x}, {y})", end=" ")
print() # ← To się wykona po każdym rzędzie
print("Skanowanie zakończone") # ← To się wykona raz na końcu
Wcięcia w Pythonie to nie ozdoba - one określają, który kod należy do której pętli.
Błąd 3: Mylenie kolejności
# Czy to skanuje poziomo czy pionowo?
for y in range(3):
for x in range(3):
print(f"({x}, {y})")
Zewnętrzna pętla (y) zmienia się wolniej. Wewnętrzna (x) przebiega kompletnie dla każdej wartości zewnętrznej. Jeśli to Cię myli, dodaj więcej print() żeby zobaczyć co się dzieje:
for y in range(3):
print(f"--- Rząd {y} ---")
for x in range(3):
print(f" Pozycja ({x}, {y})")
Bardziej złożony przykład: Diagnostyka systemów łazika
Pętli możemy zagnieżdżać więcej niż dwie. Po odnalezieniu łazika musimy sprawdzić wszystkie jego systemy. Każdy łazik ma 8 wewnętrznych czujników, które musimy przeskanować. Importem random i time na razie się nie przejmuj, chociaż pewnie domyślasz się do czego nam tu posłużą :)
import random
import time
# Lista łazików z ich pozycjami
rovers = [
{"name": "Spirit", "x": 3, "y": 5},
{"name": "Opportunity", "x": 7, "y": 2},
{"name": "Curiosity", "x": 1, "y": 8}
]
# Nazwy systemów do sprawdzenia
systems = [
"Panel słoneczny",
"Bateria główna",
"System komunikacji",
"Kamera HD",
"Sensor temperatury",
"Napęd kół",
"Ramię robotyczne",
"Moduł analizy gruntu"
]
print("=== ROZPOCZYNAM SKANOWANIE SEKTORA ===\n")
# Pierwsza pętla: skanujemy mapę
for scan_y in range(10):
for scan_x in range(10):
# Druga pętla: sprawdzamy każdy łazik
for rover in rovers:
if rover["x"] == scan_x and rover["y"] == scan_y:
print(f"\n🛰️ KONTAKT! Łazik {rover['name']} na pozycji ({scan_x}, {scan_y})")
print(f"Rozpoczynam diagnostykę systemów...\n")
time.sleep(0.5)
# Trzecia pętla: sprawdzamy systemy w łaziku
for system_id in range(len(systems)):
system_name = systems[system_id]
# Losowo generujemy status (80% szans na OK)
is_working = random.random() > 0.2
if is_working:
status = "✓ OK"
else:
status = "✗ USZKODZONY"
print(f" System {system_id + 1}/8 - {system_name}: {status}")
time.sleep(0.2)
print(f"\n--- Diagnostyka łazika {rover['name']} zakończona ---\n")
print("\n=== SKANOWANIE UKOŃCZONE ====")
Ten kod wykona się tak:
- Zewnętrzna pętla - skanuje współrzędne Y (0-9)
- Druga pętla - dla każdego Y skanuje współrzędne X (0-9)
- Trzecia pętla - sprawdza czy na tej pozycji jest jakiś łazik
- Czwarta pętla - jeśli łazik znaleziony, sprawdza każdy z 8 systemów
Wynik:
=== ROZPOCZYNAM SKANOWANIE SEKTORA === 🛰️ KONTAKT! Łazik Opportunity na pozycji (7, 2) Rozpoczynam diagnostykę systemów... System 1/8 - Panel słoneczny: ✓ OK System 2/8 - Bateria główna: ✓ OK System 3/8 - System komunikacji: ✗ USZKODZONY System 4/8 - Kamera HD: ✓ OK System 5/8 - Sensor temperatury: ✓ OK System 6/8 - Napęd kół: ✓ OK System 7/8 - Ramię robotyczne: ✓ OK System 8/8 - Moduł analizy gruntu: ✓ OK --- Diagnostyka łazika Opportunity zakończona --- 🛰️ KONTAKT! Łazik Spirit na pozycji (3, 5) Rozpoczynam diagnostykę systemów... System 1/8 - Panel słoneczny: ✓ OK System 2/8 - Bateria główna: ✗ USZKODZONY System 3/8 - System komunikacji: ✓ OK System 4/8 - Kamera HD: ✓ OK System 5/8 - Sensor temperatury: ✓ OK System 6/8 - Napęd kół: ✓ OK System 7/8 - Ramię robotyczne: ✓ OK System 8/8 - Moduł analizy gruntu: ✓ OK --- Diagnostyka łazika Spirit zakończona --- 🛰️ KONTAKT! Łazik Curiosity na pozycji (1, 8) Rozpoczynam diagnostykę systemów... System 1/8 - Panel słoneczny: ✓ OK System 2/8 - Bateria główna: ✓ OK System 3/8 - System komunikacji: ✓ OK System 4/8 - Kamera HD: ✓ OK System 5/8 - Sensor temperatury: ✗ USZKODZONY System 6/8 - Napęd kół: ✓ OK System 7/8 - Ramię robotyczne: ✓ OK System 8/8 - Moduł analizy gruntu: ✓ OK --- Diagnostyka łazika Curiosity zakończona --- === SKANOWANIE UKOŃCZONE ====
Zauważ jak każda pętla ma swoje zadanie:
- Pętla 1 i 2: Skanują współrzędne na mapie
- Pętla 3: Sprawdza listę łazików
- Pętla 4: Przechodzi przez systemy w łaziku
Kiedy używać pętli zagnieżdżonych?
Oto sytuacje, gdzie się przydają:
- Dane 2D/3D - mapy, obrazy satelitarne, siatki współrzędnych
- Porównywanie każdego z każdym - sprawdzanie odległości między wszystkimi obiektami
- Przeszukiwanie zagnieżdżonych struktur - jak sprawdzanie systemów w każdym pojeździe
- Generowanie kombinacji - wszystkie możliwe pary, trójki itp.
- Operacje na macierzach - obliczenia matematyczne na tablicach
Misje treningowe
Czas przećwiczyć! Spróbuj zrobić te zadania:
Misja 1: Mapa temperatury
Stwórz mapę temperatury powierzchni Marsa 8×8. Losowo wygeneruj temperatury od -100°C do 20°C dla każdego punktu. Wyświetl mapę używając kolorowych emotek:
- 🟦 poniżej -50°C
- 🟨 od -50°C do 0°C
- 🟥 powyżej 0°C
Misja 2: Odległości między łazikami
Masz listę łazików z ich pozycjami (x, y). Użyj zagnieżdżonych pętli żeby obliczyć odległość między każdą parą łazików. Wzór: sqrt((x2-x1)² + (y2-y1)²)
import math
rovers = [
("Spirit", 2, 3),
("Opportunity", 5, 1),
("Curiosity", 4, 4),
("Perseverance", 7, 2)
]
Misja 3: Analiza próbek gruntu
Każdy łazik zebrał 5 próbek gruntu. Każda próbka ma 3 parametry: pH, wilgotność (%), zawartość żelaza (%). Użyj trzech zagnieżdżonych pętli żeby:
- Przejść przez wszystkie łaziki
- Dla każdego łazika przejść przez wszystkie próbki
- Dla każdej próbki wyświetlić wszystkie parametry
Dodatkowo: Znajdź próbkę z najwyższą zawartością żelaza spośród wszystkich łazików.
Pętle zagnieżdżone wyglądają strasznie na początku, ale jak zrozumiesz zasadę "zewnętrzna zmienia się wolniej, wewnętrzna szybciej" - wszystko staje się proste. Najlepszy sposób nauki? Napisz kilka własnych przykładów i użyj print() żeby zobaczyć co się dzieje w każdym kroku.
Powodzenia w skanowaniu Marsa!
import random
import time
# Lista łazików z ich pozycjami
rovers = [
{"name": "Spirit", "x": 3, "y": 5},
{"name": "Opportunity", "x": 7, "y": 2},
{"name": "Curiosity", "x": 1, "y": 8}
]
# Nazwy systemów do sprawdzenia
systems = [
"Panel słoneczny",
"Bateria główna",
"System komunikacji",
"Kamera HD",
"Sensor temperatury",
"Napęd kół",
"Ramię robotyczne",
"Moduł analizy gruntu"
]
print("=== ROZPOCZYNAM SKANOWANIE SEKTORA ===\n")
# Pierwsza pętla: skanujemy mapę
for scan_y in range(10):
for scan_x in range(10):
# Druga pętla: sprawdzamy każdy łazik
for rover in rovers:
if rover["x"] == scan_x and rover["y"] == scan_y:
print(f"\n?️ KONTAKT! Łazik {rover['name']} na pozycji ({scan_x}, {scan_y})")
print(f"Rozpoczynam diagnostykę systemów...\n")
time.sleep(0.5)
# Trzecia pętla: sprawdzamy systemy w łaziku
for system_id in range(len(systems)):
system_name = systems[system_id]
# Losowo generujemy status (80% szans na OK)
is_working = random.random() > 0.2
if is_working:
status = "✓ OK"
else:
status = "✗ USZKODZONY"
print(f" System {system_id + 1}/8 - {system_name}: {status}")
time.sleep(0.2)
print(f"\n--- Diagnostyka łazika {rover['name']} zakończona ---\n")
print("\n=== SKANOWANIE UKOŃCZONE ====")
