Zanurkuj w Pythonie/Programowanie funkcyjne/Odwzorowywanie listy
Jeszcze o odwzorowywaniu list
edytujWiecie już, w jaki sposób użyć wyrażeń listowych w celu odwzorowania jednej listy w inną. Można to osiągnąć również w inny sposób, używając wbudowanej funkcji map. Działa ona podobnie do funkcji filter.
Przykład 16.10. Wprowadzenie do funkcji map
>>> def double(n): ... return n*2 ... >>> li = [1, 2, 3, 5, 9, 10, 256, -3] >>> map(double, li) #(1) [2, 4, 6, 10, 18, 20, 512, -6] >>> [double(n) for n in li] #(2) [2, 4, 6, 10, 18, 20, 512, -6] >>> newlist = [] >>> for n in li: #(3) ... newlist.append(double(n)) ... >>> newlist [2, 4, 6, 10, 18, 20, 512, -6]
- Funkcja map pobiera jako parametry funkcję oraz listę[1], a zwraca nową listę, która powstaje w wyniku wywołania funkcji przekazanej w pierwszym parametrze dla każdego elementu listy przekazanej w drugim parametrze. W tym przypadku każdy element listy został pomnożony przez 2.
- Ten sam efekt można osiągnąć wykorzystując wyrażenia listowe. Wyrażenia listowe pojawiły się w języku Python w wersji 2.0; funkcja map istniała w języku od zawsze.
- Jeśli bardzo chcecie myśleć jak programista Visual Basica, to moglibyście również do tego celu użyć pętli.
Przykład 16.11. Funkcja map z listami zawierającymi elementy różnych typów
>>> li = [5, 'a', (2, 'b')] >>> map(double, li) #(1) [10, 'aa', (2, 'b', 2, 'b')]
- Chciałbym zwrócić uwagę, że funkcja, której używamy jako argumentu map może być bez problemu zastosowana do list zawierających elementy różnych typów, o ile oczywiście poprawnie obsługuje każdy z typów, jakie posiadają elementy listy. W tym przypadku funkcja double mnoży swój argument przez 2, a Python wykona w tym momencie operację właściwą dla typu tego argumentu. W przypadku wartości całkowitych oznacza to pomnożenie wartości przez 2; w przypadku napisów oznacza to wydłużenie napisu o samego siebie; dla krotek oznacza to utworzenie nowej krotki zawierającej wszystkie elementy krotki oryginalnej, a po nich ponownie wszystkie elementy krotki oryginalnej.
Dobra, koniec zabawy. Popatrzmy na kawałek prawdziwego kodu.
Przykład 16.12. Funkcja map w regression.py
filenameToModuleName = lambda f: os.path.splitext(f)[0] #(1)
moduleNames = map(filenameToModuleName, files) #(2)
- Jak widzieliśmy w podrozdziale 4.7 Wyrażenia lambda, lambda pozwala na zdefiniowanie funkcji w locie. W przykładzie 6.17 “Rozdzielanie ścieżek” (w podrozdziale Praca z katalogami), os.path.splitext pobiera nazwę pliku i zwraca parę (nazwa, rozszerzenie). A więc funkcja filenameToModuleName bierze nazwę pliku jako parametr i odcina od niej rozszerzenie, zwracając nazwę bez rozszerzenia.
- Wywołanie map spowoduje wywołanie funkcji filenameToModuleName dla każdego elementu z listy files , a w rezultacie zwrócenie listy wartości, jakie powstały po każdym z tych wywołań. Innymi słowy, odcinamy rozszerzenie dla każdej nazwy pliku i zbieramy powstałe w ten sposób nazwy bez rozszerzeń do listy moduleNames.
Jak zobaczycie w dalszej części rozdziału, tego typu myślenie, które jest mocno skoncentrowane na przetwarzanych danych, można rozciągnąć przez wszystkie etapy pisania kodu, aż do ostatecznego celu, jakim jest zdefiniowanie i uruchomienie pojedynczego zestawu testów jednostkowych zawierającego testy ze wszystkich poszczególnych przypadków testowych.
Przypisy
- ↑ Patrz przypis w poprzednim podrozdziale, Filtrowanie listy