Pętle
Pętle to podstawowy mechanizm sterowania przepływem programu. Umożliwiają wielokrotne wykonywanie fragmentu kodu w sposób kontrolowany – do momentu spełnienia określonego warunku albo dla każdego elementu danej kolekcji. Bez nich praktycznie nie da się pisać programów przetwarzających dane, wykonujących obliczenia iteracyjne czy operujących na strukturach takich jak listy i słowniki. Zagadnienie Pętle Python obejmuje kilka konstrukcji językowych oraz dodatkowe mechanizmy pomocnicze, które razem tworzą spójny system iteracji.
Spis treści
Pętle Python – konstrukcja for jako podstawowy mechanizm iteracji po sekwencjach i iteratorach
Czym jest pętla for i jak działa w Pythonie
W Pythonie pętla for nie jest klasyczną pętlą licznikową znaną z języka C. Jest to konstrukcja iteracyjna oparta na protokole iteratora. Oznacza to, że nie operuje bezpośrednio na liczniku, lecz na obiekcie dostarczającym kolejne wartości.
Ogólna postać:
for zmienna in obiekt_iterowalny:
instrukcje
Działanie:
- Python pobiera iterator z obiektu (wywołując wewnętrznie metodę
__iter__()). - W każdej iteracji wywoływana jest metoda
__next__(). - Jeśli pojawi się wyjątek
StopIteration, pętla kończy działanie.
Przykład:
for x in [10, 20, 30]:
print(x)
Każdy element listy zostaje przypisany do zmiennej x.
Iteracja po różnych typach danych
Pętla for działa z każdym obiektem iterowalnym:
- listy
- krotki
- napisy
- zbiory
- słowniki
- zakresy (
range) - pliki
- generatory
Iteracja po napisie:
for znak in "abc":
print(znak)
Iteracja po słowniku:
d = {"a": 1, "b": 2}
for klucz in d:
print(klucz)Aby uzyskać pary klucz-wartość:
for klucz, wartosc in d.items():
print(klucz, wartosc)
Funkcja range() jako generator liczb
range() zwraca obiekt typu range, który generuje liczby całkowite w określonym zakresie.
Postacie:
range(stop)
range(start, stop)
range(start, stop, krok)
Przykład:
for i in range(5):
print(i)
Wynik:
0 1 2 3 4
range() nie tworzy listy – generuje wartości dynamicznie, co jest oszczędne pamięciowo.
Iteracja z indeksem – enumerate()
Częsty problem: potrzebny jest zarówno element, jak i jego indeks.
lista = ["a", "b", "c"]for i, wartosc in enumerate(lista):
print(i, wartosc)
enumerate() zwraca iterator par (indeks, element).
Zagnieżdżone pętle for
Możliwe jest zagnieżdżanie pętli:
for i in range(3):
for j in range(2):
print(i, j)
Złożoność czasowa rośnie multiplikatywnie. Dla dwóch pętli o długości n mamy złożoność O(n²).
Pętle Python – konstrukcja while, warunki zakończenia i kontrola przepływu programu
Podstawowa konstrukcja while
Pętla while wykonuje blok kodu tak długo, jak warunek logiczny jest prawdziwy.
while warunek:
instrukcje
Przykład:
i = 0
while i < 5:
print(i)
i += 1
Warunek sprawdzany jest przed każdą iteracją.
Ryzyko pętli nieskończonej
Jeżeli warunek nigdy nie stanie się fałszywy, pętla będzie wykonywana bez końca:
while True:
print("dziala")
Taka konstrukcja jest używana celowo w serwerach, pętlach głównych programów czy systemach wbudowanych.
Instrukcja break
Natychmiastowe przerwanie pętli.
while True:
x = int(input())
if x == 0:
break
Po wykonaniu break sterowanie przechodzi za blok pętli.
Instrukcja continue
Pomija bieżącą iterację i przechodzi do następnej.
for i in range(5):
if i == 2:
continue
print(i)
Wynik: 0 1 3 4
Klauzula else w pętlach
Python posiada mniej znany mechanizm else po pętli.
for i in range(5):
print(i)
else:
print("koniec")
Blok else wykona się, jeśli pętla zakończyła się naturalnie (bez break).
Przykład z wyszukiwaniem:
liczby = [1, 3, 5, 7]for x in liczby:
if x == 4:
print("znaleziono")
break
else:
print("nie znaleziono")
Pętle Python – zaawansowane mechanizmy: list comprehensions, generatory, iteratory własne i aspekty wydajnościowe
List comprehensions jako skrócona forma pętli
Składnia:
[wyrazenie for element in sekwencja if warunek]
Przykład:
kwadraty = [x*x for x in range(10)]
Z warunkiem:
parzyste = [x for x in range(20) if x % 2 == 0]
Mechanizm:
- Tworzona jest nowa lista.
- Iteracja odbywa się podobnie jak w
for. - Wyrażenie generuje element wynikowy.
List comprehensions są zwykle szybsze niż ręczne dodawanie elementów przez append().
Generator expressions
Różnią się nawiasami:
gen = (x*x for x in range(10))
Nie tworzą listy w pamięci. Wartości generowane są na żądanie.
Użycie:
for x in gen:
print(x)
Własne iteratory
Aby obiekt był iterowalny, musi implementować:
__iter__()__next__()
Minimalny przykład:
class Licznik:
def __init__(self, max):
self.max = max
self.i = 0 def __iter__(self):
return self def __next__(self):
if self.i < self.max:
self.i += 1
return self.i - 1
else:
raise StopIteration
Użycie:
for x in Licznik(3):
print(x)
Funkcja iter() i next()
Możliwe jest ręczne sterowanie iteracją:
it = iter([1,2,3])
print(next(it))
print(next(it))
Po wyczerpaniu elementów pojawi się StopIteration.
Porównanie z C i C++
W C klasyczna pętla licznikowa:
#include <stdio.h>int main() {
int i;
for(i = 0; i < 5; i++) {
printf("%d\n", i);
}
return 0;
}W C++:
#include <iostream>
using namespace std;int main() {
for(int i = 0; i < 5; i++) {
cout << i << endl;
}
}
W Pythonie:
for i in range(5):
print(i)
Python nie udostępnia bezpośrednio zmiennej sterującej jako mechanizmu językowego — opiera się na iteratorach.
Wydajność i złożoność
- Pętla
forpo liście: O(n) - Zagnieżdżone pętle: O(n²), O(n³), itd.
- List comprehension: często minimalnie szybsze
- Generator: oszczędność pamięci kosztem niewielkiego narzutu wywołań
Koszt operacji wewnątrz pętli dominuje nad samą konstrukcją pętli.
Uwagi praktyczne i typowe błędy
- Modyfikowanie listy podczas iteracji może prowadzić do nieprzewidywalnych efektów.
- Brak inkrementacji w
whilepowoduje pętlę nieskończoną. - Nadużywanie zagnieżdżonych pętli prowadzi do problemów wydajnościowych.
- W wielu przypadkach operacje na całych kolekcjach (
sum,map,any,all) są czytelniejsze niż ręczne pętle. - Zbyt skomplikowane list comprehensions obniżają czytelność.
Pętle stanowią rdzeń sterowania przepływem w Pythonie. Konstrukcje for, while, mechanizm iteratorów oraz generatory tworzą spójny model iteracji oparty na protokole iteratora. Zrozumienie ich działania na poziomie wewnętrznym pozwala pisać kod przewidywalny, wydajny i poprawny logicznie.