Zapisz jako PDF

Transkrypt

Zapisz jako PDF
Spis treści
1 Sekwencje i iteracja
1.1 Pętla for
1.1.1 Ogólna postać pętli for
1.2 Więcej o listach
1.3 Więcej o napisach
1.4 Pętla while
2 Ćwiczenia
Sekwencje i iteracja
Sekwencje to typ danych charakteryzujący się tym, że składają się z elementów zgromadzonych w
pewnej kolejności. Elementem sekwencji może być cokolwiek (w tym - inna sekwencja), ale w
najprostszym przypadku elementami tymi są liczby.
Sekwencje to szczególny przypadek kolekcji - takich typów danych, które składają się z
elementów, ale niekoniecznie są one uporządkowane. Innym przykładem kolekcji jest
zbiór (set).
Najczęściej używanym typem sekwencji jest lista (list). Listę można stworzyć (i zapamiętać) np.
nadając jej pewien początkowy skład:
numerki = [, 1, 2, 3, 5, 8]
To co stoi po prawej stronie znaku równości to literalny zapis listy - ciąg elementów, oddzielonych
przecinkami, wewnątrz pary nawiasów kwadratowych. Oczywiście jako elementy mogą występować
zarówno stałe literalne - jak w tym przykładzie, jak i nazwy (zmienne).
Z listy - podobnie jak z każdej sekwencji - można pobrać element stojący w dowolnej pozycji:
print(numerki[4])
→ 5
Uwaga: pozycje numerowane są kolejnymi liczbami naturalnymi, począwszy od zera - podobnie, jak
w większości języków programowania.
Można też podmienić istniejący element na inny:
numerki[] = -1
print(numerki)
→ [-1, 1, 2, 3, 5, 8]
a nawet przedłużyć ją o kolejny element:
numerki.append(13)
print(numerki)
→ [-1, 1, 2, 3, 5, 8, 13]
oraz usunąć element (skracając listę):
del numerki[]
print numerki
→ [1, 2, 3, 5, 8, 13]
Łatwo też ustalić, jaka jest ,,długość" listy, czyli liczba jej elementów:
print(len(numerki))
→ 6
Jest jeszcze sporo innych ,,gotowych do użytku" operacji na listach. Ale najważniejsza cecha listy jest
taka: można zmieniać jej skład, a nawet długość, a pozostaje ona tą samą listą. Nawet jeśli
występuje w programie pod więcej niż jedną nazwą.
Pętla for
Naczelne zastosowanie listy (czy ogólniej -sekwencji), to iteracja - czyli wykonanie jakiejś operacji
dla każdego elementu. I tak wygląda najprostszy rodzaj iteracji - Pętla for:
for x in numerki:
print(x)
Zamiast print(x) pętlę for może tworzyć dowolny blok instrukcji, zgodnie z zasadami jakie już
poznaliśmy przy omawianiu instrukcji warunkowej. Cały blok tworzący wnętrze pętli będzie
wykonany wielokrotnie, tyle razy, ile elementów ma lista, a za każdym razem pod nazwę stojącą
bezpośrednio po słowie for podstawiony będzie kolejny element listy (przywołanej po słowie in) kolejny, tzn. zgodnie z kolejnością, w jakiej umieszczone są one w liście.
Inny, znany nam już rodzaj sekwencji to napis (string), zwany czasami łańcuchem znakowym. Napis
składa się ze znaków, i jest w szczególności sekwencją, której elementami są znaki. Analogicznie jak
w przypadku listy, można pobierać znaki stojące na poszczególnych pozycjach w napisie. Nie można
natomiast podmieniać znaków w napisie, ani ich usuwać bądź dopisywać: w odróżnieniu od listy,
napis raz utworzony jest niezmienny. Można go zastąpić innym napisem, i ewentualnie opatrzyć ten
nowy napis tą samą nazwą, ale nie da się go zmodyfikować. I nie jest to dzielenie włosa na czworo,
własność ta ma namacalne konsekwencje:
napis1 = 'abc'
napis2 = napis1
napis1 = 'ABC'
print(napis1, napis2)
→ ABC abc
# dla porównania, listy:
lista1 = ['a', 'b', 'c']
lista2 = lista1
lista1[] = 'A'
print(lista1, lista2)
→ ['A', 'b', 'c'] ['A', 'b', 'c']
Powraca jeszcze raz pytanie: czym są poszczególne znaki? Tzn. jaki typ danych
reprezentują? Otóż w Pythonie pojedyncze znaki też są po prostu napisami, tyle że o
długości jeden. Poza długością nic ich szczególnie nie wyróżnia. Ta uwaga jest na użytek
tych z Was, którzy znają jakiś inny język programowania, gdyż w wielu z nich znak jest
oddzielnym, innym niż napis typem danych.
Pętlę for można zatem zastosować do napisu - zamiast do listy, wówczas w kolejnych iteracjach
będą uwzględniane kolejne znaki, a których składa się napis.
Ogólna postać pętli for
for element in sekwencja:
<blok instrukcji>
else:
<blok instrukcji>
Pierwszy blok instrukcji będzie wykonany tyle razy, ile elementów ma sekwencja
Za każdym razem nazwa element oznaczać będzie kolejny element sekwencji, zgodnie z ich
porządkiem
sekwencja może być pusta; nie jest to błąd, ale wtedy pierwszy blok nie będzie wykonany ani
razu
Gdy elementy sekwencji się wyczerpią, wykonany zostanie blok po else
Blok else (wraz z linijką go otwierającą) jest opcjonalny (niekonieczny)
W pierwszym bloku mogą wystąpić specjalne polecenia: break i continue
break znaczy: przerwij pętlę natychmiast, pomiń wszystkie pozostałe elementy
sekwekcji, pomiń również ewentualny blok else
continue oznacza: przerwij działania na aktualnym elemencie, i wróć do początku bloku
biorąc kolejny element. Jeśli już zabrakło elementów, przejdź do bloku else, albo (gdy
go nie ma) do polecenia następnego po pętli
W miejscu gdzie stoi sekwencja może tak naprawdę stać dowolny obiekt iterowalny - np.
kolekcja. Ale innych typów kolekcji jeszcze nie poznaliśmy...
Blok else w pętli for jest stosunkowo rzadko widywany. Nawet wielu programistów
dość biegłych w Pythonie nie wie (lub zapomniało) o istnieniu tej opcji.
A co, jeśli chcielibyśmy za pomocą pętli for (lub inaczej) zmienić w jakiś sposób skład samej
sekwencji? Na przykład:
for x in lista:
x = x + 1
TO NIE ZADZIAŁA - w tym sensie, że lista będzie dalej miała te same elementy co poprzednio, a nie
- powiększone o 1. W istocie operacja taka nic nie osiąga - oprócz tego, że po jej zakończeniu nazwa
x ma wartość ostatniego elementu listy, powiększonego o 1. To samo można dostać bez pisania pętli.
Jak więc osiągnąć zmianę - przeliczenie - wszystkich elementów sekwencji wg. jakiejś reguły (np.
powiększ każdy z nich o 1)?
Pożytecznym sposobem tworzenia sekwencji jest funkcja range:
for x in range(3):
print(x)
→
→ 1
→ 2
Argument (tu: 3) oznacza liczbę elementów w wyprodukowanej sekwencji. Domyślnie zaczyna się
ona od zera, tak jak numeracja pozycji w sekwencjach - ale można użyć wywołania range(a, b)
aby uzyskać elementy dowolnego ciągu arytmetycznego - o elemencie początkowym a i przyroście b.
Tu jest pewne oszustwo: wynikiem wywołania range nie jest tak naprawdę lista ani
sekwencja, ale jeszcze pewnego innego rodzaju obiekt iterowalny, czyli mogący służyć za
źródło elementów w iteracji. Na razie to jest jednak drobny szczegół. Jeżeli potrzebujemy
dosłownej listy o takich elementach, wystarczy wykonać tzw. rzutowanie, czyli przyłożyć
funkcję list: lista = list(range(3))
Wracając do problemu przeliczenia wszystkich elementów listy:
lista = [3, 5, 8]
for k in range(3):
lista[k] += 1
print lista
→ [4, 6, 9]
I to działa. Nie jest to jednak optymalne rozwiązanie.
Pisząc to co powyżej wiedzieliśmy, że mamy do czynienia z listą o długości 3. W ogólności
musielibyśmy użyć funkcji len;
Można to jednak zrobić bardziej elegancko:
for k, x in enumerate(lista):
lista[k] = x + 1
Funkcja enumerate produkuje sekwencję par: nr pozycji, element - i jest bardzo przydatna w takich
sytuacjach.
Z dokonywaniem wewnątrz pętli zmian na sekwencji, po której iterujemy, należy jednak uważać. To,
co robimy w tym przykładzie jest akurat niegroźne, natomiast umieszczenie wewnątrz pętli operacji
zmieniających długość sekwencji, po której iterujemy mogłoby dać nieoczekiwane wyniki.
Więcej o listach
Elementy listy (innych rodzajów sekwencji również) można numerować od końca, używając
ujemnych wartości wskaźników pozycji:
numerki = [, 1, 2, 3, 5, 8]
numerki[-1]
→ 8
numerki[-3]
→ 3
Z list (i innych sekwencji) można wyjmować nie tylko poszczególne elementy, ale również
podsekwencje, zwane też wycinkami:
numerki = [, 1, 2, 3, 5, 8]
nn = numerki[1:4]
→ [1, 2, 3]
nn = numerki[2:]
→ [2, 3, 5, 8]
nn = numerki[:3]
→ [, 1, 2]
nn = numerki[1:4:2]
→ [1, 3]
nn = numerki[4:1:-1]
→ [5, 3, 2]
nn = numerki[:]
→ [, 1, 2, 3, 5, 8]
Jak widać, pominięcie pozycji początkowej lub końcowej oznacza: ,,do oporu". Trzecia liczba
charakteryzująca wycinek, o ile występuje - to ,,skok" wskaźnika. Przykładowo, a[::2] oznaczałoby
listę zawierającą co drugi element listy a, natomiast a[::-1]: listę składającą się z tych samych
elementów, co a - lecz w odwrotnej kolejności.
Wyrażenie numerki[:], tzw. pełny wycinek, tworzy pełną kopię listy numerki; tzn. nie jest to ta
sama lista, chociaż składa się z tych samych elementów. Jest to tzw. kopia płytka - oznacza to tyle, że
jeżeli wśród elementów kopiowanej listy były obiekty złożone (np. inne listy), to elementami kopii
będą te same listy, a nie - ich kopie.
Wycinek jest zawsze nową listą, również w ostatnim przypadku - gdy jej skład jest taki sam, jak
oryginalnej. Wtedy stanowi kopię pierwotnej listy. Można jednak też podstawiać do wycinka:
numerki[4:5] = [4]
→ [, 1, 2, 3, 4, 8]
numerki[5:5] = [5, 6, 7]
→ [, 1, 2, 3, 4, 5, 6, 7, 8]
i jest to jeszcze jeden sposób, by zmienić zawartość listy - w tym być może jej długość - zachowując
jej tożsamość.
Listy można do siebie dodawać:
l = ['a', 'b', 'c'] + ['y', 'z']
→ ['a', 'b', 'c', 'y', 'z']
w ten sposób powstaje nowa lista, która ze składników bierze elementy, ale poza tym nie ma z nimi
nic wspólnego; późniejsze zmiany w listach-składnikach nie mają wpływu na sumę.
Listy można też zwielokratniać; np. aby uzyskać listę siedmiu dwójek:
l = [2] * 7
→ [2, 2, 2, 2, 2, 2, 2]
ta sama co poprzednio uwaga stosuje się i tu.
Elementy listy można posumować:
x = sum(range(101))
→ 5050
(wprawdzie range(101) nie jest dosłownie listą, ale z ,,prawdziwą" listą można zrobić to samo).
Podobnie jak inne obiekty, listy posiadają szereg metod, za pomocą których można na nich
wykonywać różne działania. Przykładowo:
numerki.append(9)
→ [, 1, 2, 3, 4, 5, 6, 7, 8, 9]
numerki.extend([10, 11])
→ [, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
Zwróćcie uwagę na notację: kropka sygnalizuje ,,wyciągnięcie" metody z danego obiektu (tu: listy), w
nawiasach wpisujemy dane dla tej metody (argumenty - tu pojedyncze, ale może być więcej).
Więcej o napisach
Napisy dopuszczają tylko część operacji dostępnych dla list, ze względu na własność
niemodyfikowalności. Posiadają za to szereg swoistych metod. Trzeba pamiętać, że żadna z tych
metod nie zmienia napisu, którego dotyczy - wynikiem może być jedynie nowy napis, stworzony na
podstawie oryginalnego.
Przykład: metoda upper (zamienia małe litery na wielkie):
'abcde'.upper()
→ 'ABCDE'
Napis zawsze można łatwo zamienić na listę znaków:
l = list('abcde')
→ ['a', 'b', 'c', 'd', 'e']
Do operacji odwrotnej można użyć metody join:
''.join(l)
→ 'abcde'
', '.join(l)
→ 'a, b, c, d, e'
Pętla while
To jeszcze jeden sposób iteracji, tak naprawdę prostszy od pętli for - gdyż nie oparty na
sekwencjach; zwykle mniej wygodny w użyciu, ale w niektórych przypadkach nieodzowny.
# postać najprostsza
while WARUNEK:
BLOK INSTRUKCJI
# ogólna postać:
while WARUNEK:
BLOK1
else:
BLOK2
Polega na powtarzaniu bloku instrukcji nieokreśloną liczbę razy; przed każdym kolejnym
wykonaniem na nowo sprawdzany jest warunek, i jeśli okaże się fałszywy - powtarzanie się kończy.
Innym sposobem przerwania pętli while jest umieszczenie gdzieś w bloku instrukcji break - zwykle
pod pewnym warunkiem (tzn. wewnątrz instrukcji warunkowej if). Wykonanie break polega na
,,wyskoczeniu" z pętli - i przejściu do dalszego ciągu programu, po bloku wewnętrznym pętli.
Oczywiście aby WARUNEK mógł okazać się za którymś razem fałszywy, i spowodować przerwanie
pętli, musi on być zbudowany z wykorzystaniem zmiennych, których wartości ulegają zmianom
wewnątrz pętli. Zdarza się jednak widzieć pętlę zaczynającą się od while True: - formalnie jest to
pętla nieskończona, którą może zakończyć jedynie wywołanie instrukcji break występującej gdzieś
w wewnętrznym bloku.
Wewnątrz bloku może wystąpić również instrukcja continue - działa ona analogicznie, jak w pętli
for, a więc powoduje przerwanie wykonywania aktualnej iteracji i przeskok do początku pętli, czyli
sprawdzenia warunku jej kontynuowania.
W ogólnej postaci, blok występujący po linijce else: jest wykonywany po zakończeniu pętli wskutek
niespełnienia warunku początkowego, natomiast jest pomijany, jeśli przerwanie pętli było
spowodowane instrukcją break.
Zasadniczo każdą pętlę for dałoby się przepisać jako równoważną pętlę while - przykładowo:
for x in lista:
działaj_na(x)
# równoważnie:
k =
while k < len(lista):
działaj_na(lista[k])
k += 1
nie należy jednak zazwyczaj tego robić, ponieważ (najczęściej) pętla for jest bardziej czytelna.
Ćwiczenia
1. Napisać program, który sumuje liczby naturalne od 1 do 100:
z wykorzystaniem pętli for
z wykorzystaniem pętli while
2. Wykorzystując pętlę while napisać program, który sprawdza czy zadana liczba naturalna jest
liczbą pierwszą.
3. Napisać program, który sprawdza jaka jest najmniejsza liczba wyrazów szeregu harmonicznego,
jaką należy posumować, aby wynik przekroczył daną liczbę dodatnią (,,próg").
4. Napisać program, który gra z użytkownikiem w zgadywanie liczby (,,sekretna" liczba do
odgadnięcia jest wpisana w kod programu). Użytkownik jest proszony o próbę zgadnięcia, w
odpowiedzi otrzymuje informację, czy sekretna liczba jest większa czy mniejsza od podanej przez
niego; w przypadku trafnego zgadnięcia, program składa gratulacje i podaje, po ilu próbach udało
się zgadnąć.
poprzednie | strona główna | dalej
RobertJB (dyskusja) 12:22, 29 cze 2016 (CEST)