Z pętlami spotkasz się w każdym języku programowania. Pętle pozwalają na wykonywanie czynności w powtarzalny sposób na podstawie kryteriów, które określasz ty. Pętle spotykasz także w życiu codziennym i to na każdym kroku. Pętle oszczędzają nam czas. Kiedy wysyłasz kogoś do sklepu po 5 bułek, to nie mówisz mu:
„Weź bułkę i zapakuj do koszyka, potem weź bułkę i zapakuj do koszyka, potem weź bułkę i zapakuj do koszyka, potem weź bułkę i zapakuj do koszyka, potem weź bułkę i zapakuj do koszyka”. Prościej powiedzieć „Weź pięć bułek i zapakuj do koszyka.” Przełóżmy tą filozofię na nasze zadanie, czyli dobranie się do trzech kolejno występujących po sobie wyrazów. Bez użycia pętli trzeba by zrobić coś takiego:
tekst_zrodlowy = "W Pythonie wartości, a nie zmienne, posiadają typ \
– tak więc Python jest językiem z typami dynamicznymi, podobnie \
jak Lisp, a w przeciwieństwie do Javy. Wszystkie wartości \
przekazywane są przez referencję."
lista = tekst_zrodlowy.split()
wyrazy1 = lista[0:3]
print(wyrazy1)
wyrazy2 = lista[1:4]
print(wyrazy2)
wyrazy3 = lista[2:5]
print(wyrazy3)
I tak aż do końca. Pamiętaj, że naszym celem jest sprawdzenie częstości występowania trójek wyrazów w książkach, nie akapitach. Taka metoda jest całkiem kiepska, ale dla porządku zobaczmy efekt powyższego kodu:
======================== RESTART: F:/python38/wpis 7.py ========================
['W', 'Pythonie', 'wartości,']
['Pythonie', 'wartości,', 'a']
['wartości,', 'a', 'nie']
>>>
Z pomocą przyjdzie nam pętla for. Ta pętla pozwala na powtarzanie polecenia na każdym kolejnym elemencie zmiennej, bądź powtarzanie polecenia określoną ilość razy. Zajmijmy się pierwszym przypadkiem, powtarzaniem polecenia na każdym elemencie zmiennej. Naszą zmienną będzie lista, która jest typem danych lista, a każdy kolejny element listy to słowo. Napisz taki kod. Wyjaśnimy go krok po kroku:
tekst_zrodlowy = "W Pythonie wartości, a nie zmienne, posiadają typ \
– tak więc Python jest językiem z typami dynamicznymi, podobnie \
jak Lisp, a w przeciwieństwie do Javy. Wszystkie wartości \
przekazywane są przez referencję."
lista = tekst_zrodlowy.split()
for slowo in lista:
print(slowo)
for slowo in lista:– tu zaczyna się nasza pętla.for– określa, że chcemy zacząć pętlę for.slowo– tak nazywamy każdy kolejny element listy, możesz tu zamiast slowo użyć x, i, ids, ale dla przejrzystości czytania kodu programu warto używać nazw ułatwiających zrozumienie kodu.in– w, czyli czytając od początku dla każdego elementu w.lista– nasza zmienna, która w tym przypadku jest listą, czyli znów czytając od początku dla każdego elementu w zmiennej lista.:każda pętla po określeniu czego dotyczy ma dwukropek, wszystko co pojawia się jako polecenie dla zdefiniowanej pętli jest po dwukropku, w nowej linijce kodu i musi być wcięte, do wcięcia najlepiej użyć klawisza Tab (znajdziesz go koło litery Q na klawiaturze), IDLE po wciśnięciu enter po dwukropku sam doda potrzebne wcięcie.print(slowo)– wydrukuj element listy, w naszym przypadku nazwaliśmy elementy listy slowo, więc będziemy drukować slowo. Polecenie jest wcięte, bo dotyczy naszej pętli. Jeśli chcesz napisać coś poza pętlą musisz zacząć w kolejnej linijce i cofnąć się w lewo o jedną tabulację.
Zobaczmy działanie naszego programu z pętlą:
======================== RESTART: F:\python38\wpis 7.py ========================
W
Pythonie
wartości,
a
nie
zmienne,
posiadają
typ
–
tak
więc
Python
jest
językiem
z
typami
dynamicznymi,
podobnie
jak
Lisp,
a
w
przeciwieństwie
do
Javy.
Wszystkie
wartości
przekazywane
są
przez
referencję.
>>>
Udało nam się wydrukować każde ze słów, ale my przecież nie potrzebujemy pojedynczych słów, a trójek słów i nauczyłeś się jak wykorzystać do tego indeksy, które są liczbami. Użyjmy pętli for do wygenerowania liczb, napisz najpierw kod i przeanalizujemy jego działanie:
for indeks in range(10):
print(indeks)
for indeks in range(10): tu zaczyna się nasza pętla. Początek niewiele się zmieniłfor indeks inmówi nam dla indeksu w.range()informuje o zakresie w jakim porusza się nasza pętla, argumentem range zawsze będzie liczba całkowita lub liczby całkowite.range(10)oznacza w zakresie do 10. Czyli całość można przeczytać dla indeksu w zakresie 0-9 (pamiętaj, Python zaczyna liczenie od zera, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 to 10 cyfr).print(indeks)– wydrukuj indeks.
Zobaczmy co robi nasz program:
======================== RESTART: F:\python38\wpis 7.py ========================
0
1
2
3
4
5
6
7
8
9
>>>
Pokombinujmy teraz trochę. By wydrukować pierwsze 3 wyrazy potrzebujesz [0:3], czyli liczby całkowitej 0 i liczby całkowitej 3. Wiesz, jak łatwo liczby dodawać. Wiesz, jak posługiwać się indeksami. No i wiesz, jak definiuje się zmienne liczbowe. To może zdefiniujmy zmienną o wartości 0 i dodajmy do niej 3, by uzyskać pożądany efekt:
tekst_zrodlowy = "W Pythonie wartości, a nie zmienne, posiadają typ \
– tak więc Python jest językiem z typami dynamicznymi, podobnie \
jak Lisp, a w przeciwieństwie do Javy. Wszystkie wartości \
przekazywane są przez referencję."
lista = tekst_zrodlowy.split()
indeks = 0
print(lista[indeks:indeks + 3])
W 7 linijce zdefiniowaliśmy zmienną indeks równą 0 indeks = 0. W 9 linijce wykorzystaliśmy ją do wskazania, jaki zakres elementów listy chcemy wybrać lista[indeks:indeks + 3]. Na koniec wybrane elementy drukujemy print(lista[indeks:indeks + 3]). Sprawdźmy jak to działa, uruchom program:
======================== RESTART: F:\python38\wpis 7.py ========================
['W', 'Pythonie', 'wartości,']
>>>
Teraz mamy wszystkie klocki potrzebne do poskładania pętli for, drukującej trzy kolejne wyrazy! Wiemy, jak zmusić pętlę for do podstawienia pod wartość zmiennej indeks kolejne liczby, wiemy, jak wydrukować elementy listy z użyciem indeksów. Poskładajmy to, co wiemy w całość wraz z wydrukowaniem informacji, co się dzieje w 10 wykonaniach polecenia pętli:
tekst_zrodlowy = "W Pythonie wartości, a nie zmienne, posiadają typ \
– tak więc Python jest językiem z typami dynamicznymi, podobnie \
jak Lisp, a w przeciwieństwie do Javy. Wszystkie wartości \
przekazywane są przez referencję."
lista = tekst_zrodlowy.split()
for indeks in range(10):
print(f"\nUżywam zakresu indeksów {indeks} - {indeks + 3}")
print(lista[indeks:indeks + 3])
Teraz w pętli, która wykonuje się 10 razy range(10) mamy dwa polecenia print(), oba są wcięte w prawo i oba wykonają się 10 razy. Zobaczmy efekt:
======================== RESTART: F:\python38\wpis 7.py ========================
Używam zakresu indeksów 0 - 3
['W', 'Pythonie', 'wartości,']
Używam zakresu indeksów 1 - 4
['Pythonie', 'wartości,', 'a']
Używam zakresu indeksów 2 - 5
['wartości,', 'a', 'nie']
Używam zakresu indeksów 3 - 6
['a', 'nie', 'zmienne,']
Używam zakresu indeksów 4 - 7
['nie', 'zmienne,', 'posiadają']
Używam zakresu indeksów 5 - 8
['zmienne,', 'posiadają', 'typ']
Używam zakresu indeksów 6 - 9
['posiadają', 'typ', '–']
Używam zakresu indeksów 7 - 10
['typ', '–', 'tak']
Używam zakresu indeksów 8 - 11
['–', 'tak', 'więc']
Używam zakresu indeksów 9 - 12
['tak', 'więc', 'Python']
>>>
Została już tylko drobnostka do pełni szczęścia, każdy tekst ma różną długość, zamiast na sztywno podawać wartość dla range(), użyjmy funkcji podającej długość listy w postaci liczby len().
tekst_zrodlowy = "W Pythonie wartości, a nie zmienne, posiadają typ \
– tak więc Python jest językiem z typami dynamicznymi, podobnie \
jak Lisp, a w przeciwieństwie do Javy. Wszystkie wartości \
przekazywane są przez referencję."
lista = tekst_zrodlowy.split()
for indeks in range(len(lista)):
print(lista[indeks:indeks + 3])
Zobaczmy efekt!
======================== RESTART: F:\python38\wpis 7.py ========================
['W', 'Pythonie', 'wartości,']
['Pythonie', 'wartości,', 'a']
['wartości,', 'a', 'nie']
['a', 'nie', 'zmienne,']
['nie', 'zmienne,', 'posiadają']
['zmienne,', 'posiadają', 'typ']
['posiadają', 'typ', '–']
['typ', '–', 'tak']
['–', 'tak', 'więc']
['tak', 'więc', 'Python']
['więc', 'Python', 'jest']
['Python', 'jest', 'językiem']
['jest', 'językiem', 'z']
['językiem', 'z', 'typami']
['z', 'typami', 'dynamicznymi,']
['typami', 'dynamicznymi,', 'podobnie']
['dynamicznymi,', 'podobnie', 'jak']
['podobnie', 'jak', 'Lisp,']
['jak', 'Lisp,', 'a']
['Lisp,', 'a', 'w']
['a', 'w', 'przeciwieństwie']
['w', 'przeciwieństwie', 'do']
['przeciwieństwie', 'do', 'Javy.']
['do', 'Javy.', 'Wszystkie']
['Javy.', 'Wszystkie', 'wartości']
['Wszystkie', 'wartości', 'przekazywane']
['wartości', 'przekazywane', 'są']
['przekazywane', 'są', 'przez']
['są', 'przez', 'referencję.']
['przez', 'referencję.']
['referencję.']
>>>
No tak, prawie dobrze. Popatrz na dwie ostatnie linijki. W pewnym momencie wyrażenie indeks + 3 wychodzi poza elementy listy. Obejrzyjmy to na prostszym przykładzie, napisz taki oto program:
tekst_zrodlowy = "W Pythonie wartości, a nie zmienne, posiadają typ"
lista = tekst_zrodlowy.split()
print(f"długość listy to {len(lista)} elementów")
print(f"lista ma indeksy od 0 do {len(lista) - 1}")
for indeks in range(len(lista)):
print(f"drukuję elementy dla indeksów {indeks}, {indeks + 1}, {indeks + 2}")
print(lista[indeks:indeks + 3])
W tym programie w 1 linijce pod zmienną tekst_zrodlowy podstawiamy tekstowy typ danych. W 2 linijce pod zmienną lista podstawiamy listę wyrazów oddzielanych spacją, pozyskanych ze zmiennej tekst_zrodlowy. W 4 linijce drukujemy liczbę elementów listy. W 5 drukujemy indeksy, wiemy, że lista zaczyna numerowanie od zera, dlatego też ostatni indeks będzie o jeden mniejszy niż długość listy. W 7 linijce zaczyna się pętla for działająca w zakresie od 0 do 7 (len(lista) = 8. 0 do 7 to osiem cyfr). W 8 linijce drukujemy sobie potwierdzenie dla których indeksów powstaje wycinek listy. W 9 linijce drukujemy wycinki. Zobaczmy efekt:
======================== RESTART: F:\python38\wpis 7.py ========================
długość listy to 8 elementów
lista ma indeksy od 0 do 7
drukuję elementy dla indeksów 0, 1, 2
['W', 'Pythonie', 'wartości,']
drukuję elementy dla indeksów 1, 2, 3
['Pythonie', 'wartości,', 'a']
drukuję elementy dla indeksów 2, 3, 4
['wartości,', 'a', 'nie']
drukuję elementy dla indeksów 3, 4, 5
['a', 'nie', 'zmienne,']
drukuję elementy dla indeksów 4, 5, 6
['nie', 'zmienne,', 'posiadają']
drukuję elementy dla indeksów 5, 6, 7
['zmienne,', 'posiadają', 'typ']
drukuję elementy dla indeksów 6, 7, 8
['posiadają', 'typ']
drukuję elementy dla indeksów 7, 8, 9
['typ']
>>>
Dwie ostatnie linijki wychodzą poza indeks i nasza pętla nie ma co wydrukować jako trzeci element, a potem jako drugi i trzeci element. W takim razie ograniczmy range() pętli o dwa w 7 linijce:
tekst_zrodlowy = "W Pythonie wartości, a nie zmienne, posiadają typ"
lista = tekst_zrodlowy.split()
print(f"długość listy to {len(lista)} elementów")
print(f"lista ma indeksy od 0 do {len(lista) - 1}")
for indeks in range(len(lista) - 2):
print(f"drukuję elementy dla indeksów {indeks}, {indeks + 1}, {indeks + 2}")
print(lista[indeks:indeks + 3])
I sprawdźmy rezultat:
======================== RESTART: F:\python38\wpis 7.py ========================
długość listy to 8 elementów
lista ma indeksy od 0 do 7
drukuję elementy dla indeksów 0, 1, 2
['W', 'Pythonie', 'wartości,']
drukuję elementy dla indeksów 1, 2, 3
['Pythonie', 'wartości,', 'a']
drukuję elementy dla indeksów 2, 3, 4
['wartości,', 'a', 'nie']
drukuję elementy dla indeksów 3, 4, 5
['a', 'nie', 'zmienne,']
drukuję elementy dla indeksów 4, 5, 6
['nie', 'zmienne,', 'posiadają']
drukuję elementy dla indeksów 5, 6, 7
['zmienne,', 'posiadają', 'typ']
Świetnie! Skoro testowy program zadziałał, zobaczmy czy ograniczenie range() o 2 przyniesie oczekiwany rezultat:
tekst_zrodlowy = "W Pythonie wartości, a nie zmienne, posiadają typ \
– tak więc Python jest językiem z typami dynamicznymi, podobnie \
jak Lisp, a w przeciwieństwie do Javy. Wszystkie wartości \
przekazywane są przez referencję."
lista = tekst_zrodlowy.split()
for indeks in range(len(lista) - 2):
print(lista[indeks:indeks + 3])
Efekt:
======================== RESTART: F:\python38\wpis 7.py ========================
['W', 'Pythonie', 'wartości,']
['Pythonie', 'wartości,', 'a']
['wartości,', 'a', 'nie']
['a', 'nie', 'zmienne,']
['nie', 'zmienne,', 'posiadają']
['zmienne,', 'posiadają', 'typ']
['posiadają', 'typ', '–']
['typ', '–', 'tak']
['–', 'tak', 'więc']
['tak', 'więc', 'Python']
['więc', 'Python', 'jest']
['Python', 'jest', 'językiem']
['jest', 'językiem', 'z']
['językiem', 'z', 'typami']
['z', 'typami', 'dynamicznymi,']
['typami', 'dynamicznymi,', 'podobnie']
['dynamicznymi,', 'podobnie', 'jak']
['podobnie', 'jak', 'Lisp,']
['jak', 'Lisp,', 'a']
['Lisp,', 'a', 'w']
['a', 'w', 'przeciwieństwie']
['w', 'przeciwieństwie', 'do']
['przeciwieństwie', 'do', 'Javy.']
['do', 'Javy.', 'Wszystkie']
['Javy.', 'Wszystkie', 'wartości']
['Wszystkie', 'wartości', 'przekazywane']
['wartości', 'przekazywane', 'są']
['przekazywane', 'są', 'przez']
['są', 'przez', 'referencję.']
Wszystko jest jak należy. W tym rozdziale dowiedziałeś się jak działa pętla for, jak jej użyć, by polecenie napisać raz w pętli zamiast mnóstwo razy poza pętlą. Wiesz też, jak ważne jest sprawdzanie działania programu i wprowadzanie drobnych poprawek, by działał dokładnie tak, jak sobie tego życzysz.
Zadanie domowe
Podążanie za instrukcjami, nawet jeśli je wszystkie wykonujesz samodzielnie, nie zrobi z ciebie programisty. Zadania domowe mogą wydawać się na początku trudne. Tu nie ma rozwiązania podanego na talerzu, użyj dowolnych źródeł, by znaleźć odpowiedź.
- Nic nie stoi na przeszkodzie, by w pętli for znalazła się druga pętla for. Użyj pętli w pętli by uzyskać taki efekt:
0 0
0 1
0 2
1 0
1 1
1 2
2 0
2 1
2 2
- funkcja
range()może przyjmować więcej niż jeden argument. Przerób program z pkt 1. na taki, który da efekt:
1 0
1 2
2 0
2 2