Zanurkuj w Pythonie/Pętla for
Pętla for
[edytuj]Podobnie jak wiele innych języków, Python posiada pętlę for. Jedynym powodem, dla którego nie widzieliśmy tej pętli wcześniej jest to, że Python posiada tyle innych użytecznych rzeczy, że nie potrzebujemy jej aż tak często.
Wiele języków programowania nie posiada typu danych o takich możliwościach, jakie daje lista w Pythonie, dlatego też w tych językach trzeba wykonywać dużo manualnej pracy, trzeba określać początek, koniec i krok, aby przejść zakres liczb całkowitych, znaków lub innych iteracyjnych jednostek. Jednak pythonowa pętla for, przechodzi całą listę w identyczny sposób, jak ma to miejsce w wyrażeniach listowych.
for >>> li = ['a', 'b', 'e'] >>> for s in li: #(1) ... print s #(2) a b e >>> print "\n".join(li) #(3) a b e
- Składnia pętli
forjest bardzo podobna do składni wyrażenia listowego.lijest listą, a zmiennasbędzie przyjmować kolejne wartości elementów tej listy podczas wykonywania pętli, zaczynając od elementu pierwszego. - Podobnie jak wyrażenie
ifi inne bloki tworzone za pomocą wcięć, pętlaformoże posiadać dowolną liczbę linii kodu. - To główna przyczyna, dla której jeszcze nie widzieliśmy pętli
for. Po prostu jej nie potrzebowaliśmy. Jest to zadziwiające, jak często trzeba wykorzystywać pętleforw innych językach, podczas gdy tak naprawdę potrzebujemy metodyjoin, czy też wyrażenia listowego.
>>> for i in range(3): #(1) ... print i 0 1 2 >>> li = ['a', 'b', 'c', 'd'] >>> for i in range(len(li)): #(2) ... print li[i] a b c d
- Jak zobaczyliśmy w przykładzie 3.23, "Przypisywanie kolejnych wartości", funkcja
rangetworzy listę liczb całkowitych, a tę listę będziemy chcieli przejść za pomocą pętli. Powyższy kod być może wygląda trochę dziwacznie, lecz bywa przydatny do tworzenia pętli licznikowej. - Nigdy tego nie róbmy. Jest to visualbasicowy styl myślenia. Skończmy z nim. Powinno się iterować listę, jak pokazano to w poprzednim przykładzie.
Pętle for nie zostały stworzone do tworzenia prostych pętli licznikowych. Służą one raczej do przechodzenia po wszystkich elementach w danym obiekcie. Poniżej pokazano przykład, jak można iterować po słowniku za pomocą pętli for:
>>> import os >>> for k, v in os.environ.items(): #(1) (2) ... print ("%s=%s" % (k, v)) USERPROFILE=C:\Documents and Settings\mpilgrim OS=Windows_NT COMPUTERNAME=MPILGRIM USERNAME=mpilgrim ... >>> print ("\n".join(["%s=%s" % (k, v) for k, v in os.environ.items()]) ) #(3) USERPROFILE=C:\Documents and Settings\mpilgrim OS=Windows_NT COMPUTERNAME=MPILGRIM USERNAME=mpilgrim ... os.environjest słownikiem zmiennych środowiskowych zdefiniowanych w systemie operacyjnym. W Windowsie mamy tutaj zmienne użytkownika i systemu dostępne z MS-DOS-a. W Uniksie mamy tu zmienne wyeksportowane w twojej powłoce przez skrypty startowe. W systemie Mac OS nie ma czegoś takiego jak zmienne środowiskowe, więc słownik ten jest pusty.os.environ.items()zwraca listę krotek w postaci[(klucz1, wartosc1), (klucz2, wartosc2), ...]. Pętlaforiteruje po tej liście. W pierwszym przebiegu pętli, przypisuje ona wartośćklucz1do zmiennejk, a wartośćwartosc1dov, więck = "USERPROFILE", av = "C:\Documents and Settings\mpilgrim". W drugim przebiegu pętli,kprzyjmuje wartość drugiego klucza, czyli"OS", avbierze odpowiadającą temu kluczowi wartość, czyli"Windows_NT".- Za pomocą wielozmiennego przypisania i wyrażeń listowych, możemy zastąpić całą pętle
forjednym wyrażeniem. Z której metody będziemy korzystać w kodzie, jest kwestią stylu pisania. Niektórym się to może podobać, ponieważ za pomocą wyrażenia listowego jasno stwierdzamy, że to co robimy to odwzorowywanie słownika na listę, a następnie łączymy otrzymaną listę w jeden napis. Inni z kolei preferują pisanie z użyciem pętlifor. Otrzymane wyjście programu jest identyczne w obydwu przypadkach, jakkolwiek druga wersja w tym przykładzie jest nieco szybsza, ponieważ tylko raz wykorzystujemy instrukcjęprint.
Spójrzmy teraz na pętlę for w MP3FileInfo z przykładu fileinfo.py wprowadzonego w rozdziale 5.
for w MP3FileInfo tagDataMap = {u"tytuł" : ( 3, 33, stripnulls), "artysta" : ( 33, 63, stripnulls), "album" : ( 63, 93, stripnulls), "rok" : ( 93, 97, stripnulls), "komentarz" : ( 97, 126, stripnulls), "gatunek" : (127, 128, ord)} #(1) # [...] if tagdata[:3] == 'TAG': for tag, (start, end, parseFunc) in self.tagDataMap.items(): #(2) self[tag] = parseFunc(tagdata[start:end]) #(3) tagDataMapjest atrybutem klasy, który definiuje tagi, jakie będziemy szukali w pliku MP3. Tagi są przechowywane w polach o ustalonej długości. Ponieważ czytamy ostatnie 128 bajtów pliku, bajty od 3 do 32 z przeczytanych danych są zawsze tytułem utworu, bajty od 33 do 62 są zawsze nazwą artysty, od 63 do 92 mamy nazwę albumu itd. Zauważmy, żetagDataMapjest słownikiem krotek, a każda krotka przechowuje dwie liczby całkowite i jedną referencję do funkcji.- Wygląda to skomplikowanie, jednak takie nie jest. Struktura zmiennych w pętli
forodpowiada strukturze elementów listy zwróconej poprzez metodęitems. Pamiętamy, żeitemszwraca listę krotek w formie(klucz, wartosc). Jeśli pierwszym elementem tej listy jest(u"tytuł", (3, 33, <function stripnulls at 0xb7c91f7c>)), tak więc podczas pierwszego przebiegu pętli,tagjest równeu"tytuł",startprzyjmuje wartość3,endwartość33, aparseFunczawiera funkcjęstripnulls. - Kiedy już wydobędziemy wszystkie parametry tagów pliku MP3, zapisanie danych odnoszących się do określonych tagów będzie proste. W tym celu wycinamy napis
tagdataod wartości w zmiennejstartdo wartości w zmiennejend, aby pobrać aktualne dane dla tego tagu, a następnie wywołujemy funkcjęparseFunc, aby przetworzyć te dane, a potem przypisujemy zwróconą wartość do kluczatagw słownikuself(ściślej,selfjest instancją podklasy słownika). Po przejściu wszystkich elementów wtagDataMap,selfbędzie przechowywał wartości dla wszystkich tagów, a my będziemy mogli się dowiedzieć o utworze, co tylko będziemy chcieli.