Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00000 003800 19001233 na godz. na dobę w sumie
Python. Programowanie funkcyjne - książka
Python. Programowanie funkcyjne - książka
Autor: Liczba stron: 352
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-283-5069-4 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> inne - programowanie
Porównaj ceny (książka, ebook (-35%), audiobook).

Zgodnie z paradygmatem programowania funkcyjnego największy nacisk należy kłaść na stałe i funkcje. Polega to na konstruowaniu funkcji oraz na obliczaniu wartości wyrażeń. W ten sposób otrzymuje się kod odporny na błędy. Python nie jest w pełni funkcyjnym językiem programowania, jednak pozwala na taki sposób pisania programów. Dzięki temu umożliwia tworzenie zwięzłego i eleganckiego kodu. Na przykład stosowanie wyrażeń generatorowych w Pythonie sprawia, że tworzone programy działają szybciej, ponieważ zużywają mniej zasobów. Niezależnie więc od stosowanego paradygmatu warto zapożyczyć pewne elementy programowania funkcyjnego i wykorzystać je do tworzenia ekspresyjnych i zwięzłych aplikacji w Pythonie.

To znakomity podręcznik dla programistów, którzy chcą wykorzystać techniki i wzorce projektowe z funkcyjnych języków programowania, aby tworzyć w Pythonie zwięzłe, eleganckie i ekspresyjne programy - z czytelnym i łatwym w utrzymaniu kodem. Zawiera ogólny przegląd koncepcji funkcyjnych oraz wyjaśnia tak istotne pojęcia jak funkcje pierwszej klasy, funkcje wyższego rzędu, funkcje czyste, leniwe wartościowanie i wiele innych. Wnikliwie omawia sposób korzystania z tych funkcji w Pythonie 3.6, a także techniki przygotowywania i eksploracji danych. Ponadto pokazuje, w jaki sposób standardowa biblioteka Pythona pasuje do funkcyjnego modelu programowania. Co ważne, w książce znalazło się kilka przykładów prezentujących w praktyce opisane koncepcje.

W książce między innymi:

Python: kod funkcyjny i funkcjonalny!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Tytuł oryginału: Functional Python Programming, Second Edition Tłumaczenie: Radosław Meryk ISBN: 978-83-283-5069-4 Copyright © Packt Publishing 2018. First published in the English language under the title ‘Functional Python Programming - Second Edition – (9781788627061)’ Polish edition copyright © 2019 by Helion SA All rights reserved. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Helion SA dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Helion SA nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Helion SA ul. Kościuszki 1c, 44-100 Gliwice tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/pythpf.zip Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/pythpf Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Printed in Poland • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis tre(cid:258)ci O autorze O recenzencie Przedmowa Rozdzia(cid:239) 1. Zrozumie(cid:202) programowanie funkcyjne Paradygmat programowania Podzia(cid:239) paradygmatu proceduralnego Korzystanie z paradygmatu funkcyjnego Korzystanie z funkcyjnych hybryd Tworzenie obiektu Stos (cid:285)ó(cid:239)wi Klasyczny przyk(cid:239)ad programowania funkcyjnego Eksploracyjna analiza danych Podsumowanie Rozdzia(cid:239) 2. Podstawowe poj(cid:218)cia programowania funkcyjnego Funkcje pierwszej klasy Czyste funkcje Funkcje wy(cid:285)szego rz(cid:218)du Dane niemutowalne Warto(cid:258)ciowanie (cid:258)cis(cid:239)e i nie(cid:258)cis(cid:239)e Rekurencja zamiast jawnego stanu p(cid:218)tli Funkcyjne systemy typów Znajome terytorium Poj(cid:218)cia zaawansowane Podsumowanie 9 10 9 17 18 19 20 22 23 24 25 28 29 31 32 32 33 34 36 37 41 41 42 43 Poleć książkęKup książkę Spis tre(cid:286)ci Rozdzia(cid:239) 3. Funkcje, iteratory i generatory Pisanie czystych funkcji Funkcje jako obiekty pierwszej klasy Korzystanie z (cid:239)a(cid:241)cuchów znaków U(cid:285)ywanie krotek i krotek nazwanych Korzystanie z wyra(cid:285)e(cid:241) generatorowych Odkrywanie ogranicze(cid:241) generatorów (cid:146)(cid:200)czenie wyra(cid:285)e(cid:241) generatorowych Czyszczenie surowych danych za pomoc(cid:200) funkcji generatorowych Korzystanie z list, s(cid:239)owników i zbiorów Korzystanie z mapowa(cid:241) stanowych Wykorzystanie modu(cid:239)u bisect do tworzenia mapowania U(cid:285)ywanie stanowych zbiorów Podsumowanie Rozdzia(cid:239) 4. Praca z kolekcjami Przegl(cid:200)d rodzajów funkcji Praca z obiektami iterowalnymi Parsowanie pliku XML Parsowanie pliku na wy(cid:285)szym poziomie Tworzenie par elementów z sekwencji Jawne u(cid:285)ycie funkcji iter() Rozszerzanie prostej p(cid:218)tli Stosowanie wyra(cid:285)e(cid:241) generatorowych do funkcji skalarnych Wykorzystanie funkcji any() i all() jako redukcji U(cid:285)ywanie funkcji len() i sum() U(cid:285)ywanie sum i zlicze(cid:241) w obliczeniach statystycznych Korzystanie z funkcji zip() do tworzenia struktury i sp(cid:239)aszczania sekwencji Rozpakowywanie spakowanej sekwencji Sp(cid:239)aszczanie sekwencji Nadawanie struktury p(cid:239)askim sekwencjom Tworzenie struktury p(cid:239)askich sekwencji — podej(cid:258)cie alternatywne Wykorzystanie funkcji reverse() do zmiany kolejno(cid:258)ci elementów Wykorzystanie funkcji enumerate() w celu uwzgl(cid:218)dnienia numeru porz(cid:200)dkowego Podsumowanie Rozdzia(cid:239) 5. Funkcje wy(cid:285)szego rz(cid:218)du Wykorzystanie funkcji max() i min() do wyszukiwania ekstremów Korzystanie z formatu wyra(cid:285)e(cid:241) lambda w Pythonie Wyra(cid:285)enia lambda i rachunek lambda Korzystanie z funkcji map() w celu zastosowania funkcji do kolekcji Wykorzystanie wyra(cid:285)e(cid:241) lambda i funkcji map() U(cid:285)ycie funkcji map() w odniesieniu do wielu sekwencji Wykorzystanie funkcji filter() do przekazywania lub odrzucania danych U(cid:285)ycie funkcji filter() do identyfikacji warto(cid:258)ci odstaj(cid:200)cych Funkcja iter() z warto(cid:258)ci(cid:200) „stra(cid:285)nika” Wykorzystanie funkcji sorted() do porz(cid:200)dkowania danych Pisanie funkcji wy(cid:285)szego rz(cid:218)du 4 45 46 48 49 50 52 54 56 56 58 61 63 64 65 67 68 68 69 71 73 76 77 80 81 83 84 87 88 89 90 92 93 94 94 97 98 101 103 103 104 105 107 108 109 110 111 Poleć książkęKup książkę Spis tre(cid:286)ci Pisanie mapowa(cid:241) i filtrów wy(cid:285)szego rz(cid:218)du Rozpakowywanie danych podczas mapowania Opakowywanie dodatkowych danych podczas mapowania Sp(cid:239)aszczanie danych podczas mapowania Strukturyzacja danych podczas filtrowania Pisanie funkcji generatorowych Budowanie funkcji wy(cid:285)szego rz(cid:218)du z wykorzystaniem obiektów wywo(cid:239)ywalnych Zapewnienie dobrego projektu funkcyjnego Przegl(cid:200)d wybranych wzorców projektowych Podsumowanie Rozdzia(cid:239) 6. Rekurencje i redukcje Proste rekurencje numeryczne Implementacja optymalizacji ogonowej Pozostawienie rekurencji bez zmian Obs(cid:239)uga trudnego przypadku optymalizacji ogonowej Przetwarzanie kolekcji za pomoc(cid:200) rekurencji Optymalizacja ogonowa dla kolekcji Redukcje i sk(cid:239)adanie kolekcji z wielu elementów w jeden element Redukcja grupowania — z wielu elementów do mniejszej liczby Budowanie mapowania za pomoc(cid:200) metody Counter Budowanie mapowania przez sortowanie Grupowanie lub podzia(cid:239) danych wed(cid:239)ug warto(cid:258)ci klucza Pisanie bardziej ogólnych redukcji grupuj(cid:200)cych Pisanie redukcji wy(cid:285)szego rz(cid:218)du Pisanie parserów plików Podsumowanie Rozdzia(cid:239) 7. Dodatkowe techniki przetwarzania krotek U(cid:285)ywanie krotek do zbierania danych U(cid:285)ywanie krotek nazwanych do zbierania danych Budowanie nazwanych krotek za pomoc(cid:200) konstruktorów funkcyjnych Unikanie stanowych klas dzi(cid:218)ki wykorzystaniu rodzin krotek Przypisywanie rang statystycznych Opakowanie zamiast zmiany stanu Wielokrotne opakowanie zamiast zmian stanu Obliczanie korelacji rangowej Spearmana Polimorfizm i dopasowywanie typów z wzorcami Podsumowanie Rozdzia(cid:239) 8. Modu(cid:239) itertools Praca z iteratorami niesko(cid:241)czonymi Liczenie za pomoc(cid:200) count() Zliczanie z wykorzystaniem argumentów zmiennoprzecinkowych Wielokrotne iterowanie cyklu za pomoc(cid:200) funkcji cycle() Powtarzanie pojedynczej warto(cid:258)ci za pomoc(cid:200) funkcji repeat() 112 113 115 116 118 119 121 123 124 125 127 128 129 130 131 132 133 134 136 136 137 139 142 143 144 150 153 154 156 159 160 163 165 166 167 169 174 175 176 176 177 179 181 5 Poleć książkęKup książkę Spis tre(cid:286)ci U(cid:285)ywanie iteratorów sko(cid:241)czonych Przypisywanie liczb za pomoc(cid:200) funkcji enumerate() Obliczanie sum narastaj(cid:200)cych za pomoc(cid:200) funkcji accumulate() (cid:146)(cid:200)czenie iteratorów za pomoc(cid:200) funkcji chain() Podzia(cid:239) iteratora na partycje za pomoc(cid:200) funkcji groupby() Scalanie obiektów iterowalnych za pomoc(cid:200) funkcji zip_longest() i zip () Filtrowanie z wykorzystaniem funkcji compress() Zbieranie podzbiorów za pomoc(cid:200) funkcji islice() Filtrowanie stanowe z wykorzystaniem funkcji dropwhile() i takewhile() Dwa podej(cid:258)cia do filtrowania za pomoc(cid:200) funkcji filterfalse() i filter() Zastosowanie funkcji do danych z wykorzystaniem funkcji starmap() i map() Klonowanie iteratorów za pomoc(cid:200) funkcji tee() Receptury modu(cid:239)u itertools Podsumowanie Rozdzia(cid:239) 9. Dodatkowe techniki itertools Wyliczanie iloczynu kartezja(cid:241)skiego Redukowanie iloczynu Obliczanie odleg(cid:239)o(cid:258)ci Uzyskanie wszystkich pikseli i wszystkich kolorów Analiza wydajno(cid:258)ci Przeformowanie problemu (cid:146)(cid:200)czenie dwóch transformacji Permutacje zbioru warto(cid:258)ci Generowanie wszystkich kombinacji Receptury Podsumowanie Rozdzia(cid:239) 10. Modu(cid:239) functools Narz(cid:218)dzia przetwarzania funkcji Memoizacja wcze(cid:258)niejszych wyników za pomoc(cid:200) dekoratora lru_cache Definiowanie klas z dekoratorem total_ordering Definiowanie klas liczbowych Stosowanie argumentów cz(cid:218)(cid:258)ciowych za pomoc(cid:200) funkcji partial() Redukcja zbiorów danych za pomoc(cid:200) funkcji reduce() (cid:146)(cid:200)czenie funkcji map() i reduce() Korzystanie z funkcji reduce() i partial() U(cid:285)ycie funkcji map() i reduce() do oczyszczania surowych danych Korzystanie z funkcji reduce() i partial() Podsumowanie Rozdzia(cid:239) 11. Techniki projektowania dekoratorów Dekoratory jako funkcje wy(cid:285)szego rz(cid:218)du Korzystanie z funkcji update_wrapper() z modu(cid:239)u functools Zagadnienia przekrojowe Funkcje z(cid:239)o(cid:285)one Wst(cid:218)pne przetwarzanie nieprawid(cid:239)owych danych Dekoratory z parametrami 6 182 182 185 186 187 188 189 190 191 192 193 194 195 197 199 200 200 202 204 205 207 207 209 210 212 213 215 216 216 218 221 222 223 224 226 226 227 230 231 231 235 236 236 238 239 Poleć książkęKup książkę Implementacja bardziej z(cid:239)o(cid:285)onych dekoratorów Kwestie z(cid:239)o(cid:285)onego projektu Podsumowanie Rozdzia(cid:239) 12. Modu(cid:239)y multiprocessing i threading Programowanie funkcyjne a wspó(cid:239)bie(cid:285)no(cid:258)(cid:202) Co naprawd(cid:218) oznacza wspó(cid:239)bie(cid:285)no(cid:258)(cid:202)? Warunki brzegowe Wspó(cid:239)dzielenie zasobów za pomoc(cid:200) procesów lub w(cid:200)tków Jak uzyska(cid:202) najwi(cid:218)ksze korzy(cid:258)ci? Korzystanie z pul wieloprocesowych i zada(cid:241) Przetwarzanie wielu du(cid:285)ych plików Parsowanie plików logu — pobieranie wierszy Parsowanie wierszy logu do postaci obiektów namedtuple Parsowanie dodatkowych pól obiektu Access Filtrowanie szczegó(cid:239)ów dost(cid:218)pu Analiza szczegó(cid:239)ów dost(cid:218)pu Pe(cid:239)ny proces analizy Korzystanie z puli wieloprocesowej w celu przetwarzania równoleg(cid:239)ego Korzystanie z funkcji apply() do wykonywania pojedynczych (cid:285)(cid:200)da(cid:241) Korzystanie z funkcji map_async(), starmap_async() i apply_async() Bardziej z(cid:239)o(cid:285)one architektury przetwarzania wieloprocesowego Korzystanie z modu(cid:239)u concurrent.futures Korzystanie z pul w(cid:200)tków modu(cid:239)u concurrent.futures Korzystanie z modu(cid:239)ów threading i queue Projektowanie wspó(cid:239)bie(cid:285)nego przetwarzania Podsumowanie Rozdzia(cid:239) 13. Wyra(cid:285)enia warunkowe i modu(cid:239) operator Ocena wyra(cid:285)e(cid:241) warunkowych Wykorzystywanie nie(cid:258)cis(cid:239)ych regu(cid:239) s(cid:239)ownikowych Filtrowanie wyra(cid:285)e(cid:241) warunkowych zwracaj(cid:200)cych True Wyszukiwanie pasuj(cid:200)cego wzorca U(cid:285)ywanie modu(cid:239)u operator zamiast wyra(cid:285)e(cid:241) lambda Pobieranie warto(cid:258)ci nazwanych atrybutów podczas korzystania z funkcji wy(cid:285)szego rz(cid:218)du Wykorzystanie funkcji starmap z operatorami Redukcje z wykorzystaniem funkcji modu(cid:239)u operator Podsumowanie Rozdzia(cid:239) 14. Biblioteka pymonad Pobieranie i instalacja modu(cid:239)u pymonad Kompozycja funkcyjna i rozwijanie funkcji Korzystanie z rozwijanych funkcji wy(cid:285)szego rz(cid:218)du Rozwijanie funkcji w trudny sposób Kompozycja funkcyjna i operator * z biblioteki pymonad Funktory zwyk(cid:239)e i aplikatywne Korzystanie z leniwego funktora List() Spis tre(cid:286)ci 242 243 246 247 248 248 249 249 250 251 252 253 254 256 259 261 262 263 265 265 266 267 267 268 268 270 271 272 273 274 275 276 278 279 281 282 283 284 284 286 288 288 290 291 7 Poleć książkęKup książkę Spis tre(cid:286)ci Funkcja bind() i operator Implementacja symulacji za pomoc(cid:200) monad Dodatkowe w(cid:239)asno(cid:258)ci biblioteki pymonad Podsumowanie Rozdzia(cid:239) 15. Podej(cid:258)cie funkcyjne do us(cid:239)ug sieciowych Model HTTP (cid:285)(cid:200)danie-odpowied(cid:283) Wstrzykiwanie stanu za pomoc(cid:200) plików cookie Serwer o projekcie funkcyjnym Szczegó(cid:239)y widoku funkcyjnego Zagnie(cid:285)d(cid:285)anie us(cid:239)ug Standard WSGI Zg(cid:239)aszanie wyj(cid:200)tków podczas przetwarzania WSGI Praktyczne aplikacje WSGI Definiowanie us(cid:239)ug sieciowych jako funkcji Tworzenie aplikacji WSGI Pobieranie surowych danych Stosowanie filtra Serializowanie wyników Serializacja danych w formatach JSON lub CSV Serializacja danych do formatu XML Serializacja danych do formatu HTML Monitorowanie u(cid:285)ycia Podsumowanie Rozdzia(cid:239) 16. Optymalizacje i ulepszenia Memoizacja i buforowanie Specjalizacja memoizacji Ogonowe optymalizacje rekurencji Optymalizacja pami(cid:218)ci Optymalizacja dok(cid:239)adno(cid:258)ci Redukcja dok(cid:239)adno(cid:258)ci w zale(cid:285)no(cid:258)ci od wymaga(cid:241) odbiorców Studium przypadku — podejmowanie decyzji na podstawie testu zgodno(cid:258)ci chi-kwadrat Filtrowanie i redukcja surowych danych z wykorzystaniem obiektu Counter Odczyt podsumowanych danych Obliczanie sum za pomoc(cid:200) obiektu Counter Obliczanie prawdopodobie(cid:241)stw na podstawie obiektów Counter Obliczanie oczekiwanych warto(cid:258)ci i wy(cid:258)wietlanie tabeli krzy(cid:285)owej Obliczanie warto(cid:258)ci chi-kwadrat Obliczanie progu warto(cid:258)ci chi-kwadrat Obliczanie niekompletnej funkcji gamma Obliczanie kompletnej funkcji gamma Obliczanie szans na losow(cid:200) dystrybucj(cid:218) Funkcyjne wzorce projektowe Podsumowanie Skorowidz 8 294 295 298 299 301 302 303 304 304 305 306 309 310 311 312 314 315 316 317 318 319 320 322 323 324 325 327 328 329 329 330 332 333 334 335 337 339 339 340 343 344 346 348 349 Poleć książkęKup książkę 5 Funkcje wy(cid:285)szego rz(cid:218)du Bardzo wa(cid:285)n(cid:200) cech(cid:200) paradygmatu programowania funkcyjnego s(cid:200) funkcje wy(cid:285)szego rz(cid:218)du. S(cid:200) to funkcje, które akceptuj(cid:200) funkcje jako argumenty lub zwracaj(cid:200) funkcje jako wyniki. Python oferuje kilka rodzajów funkcji wy(cid:285)szego rz(cid:218)du. Przyjrzymy si(cid:218) im oraz ich niektórym logicznym rozszerzeniom. Jak mo(cid:285)na zauwa(cid:285)y(cid:202), istniej(cid:200) trzy odmiany funkcji wy(cid:285)szego rz(cid:218)du: (cid:81) Funkcje, które pobieraj(cid:200) funkcje jako jeden (lub wi(cid:218)cej) swoich argumentów. (cid:81) Funkcje, które zwracaj(cid:200) funkcj(cid:218). (cid:81) Funkcje, które pobieraj(cid:200) funkcj(cid:218) i zwracaj(cid:200) funkcj(cid:218) — tzn. po(cid:239)(cid:200)czenie dwóch poprzednich funkcji. Python oferuje kilka funkcji wy(cid:285)szego rz(cid:218)du tego pierwszego typu. W tym rozdziale przyjrzymy si(cid:218) wbudowanym funkcjom wy(cid:285)szego rz(cid:218)du tego rodzaju. W kolejnych rozdzia(cid:239)ach przyjrzymy si(cid:218) kilku modu(cid:239)om bibliotecznym, które oferuj(cid:200) funkcje wy(cid:285)szego rz(cid:218)du. Koncepcja funkcji, która zwraca inne funkcje, mo(cid:285)e wydawa(cid:202) si(cid:218) nieco dziwna. Jednak gdy spojrzymy na klas(cid:218) Callable, mo(cid:285)emy zauwa(cid:285)y(cid:202), (cid:285)e definicja klasy jest funkcj(cid:200), która przy ocenie warto(cid:258)ci zwraca obiekty Callable. Jest to jeden z przyk(cid:239)adów funkcji, która tworzy inn(cid:200) funkcj(cid:218). W(cid:258)ród funkcji, które pobieraj(cid:200) funkcje i tworz(cid:200) funkcje, mo(cid:285)na znale(cid:283)(cid:202) zarówno z(cid:239)o(cid:285)one kla- sy wywo(cid:239)ywalne, jak i funkcje dekoratorów. Koncepcj(cid:218) dekoratorów wprowadzimy w tym roz- dziale, ale bardziej wnikliw(cid:200) ich analiz(cid:218) od(cid:239)o(cid:285)ymy do rozdzia(cid:239)u 11. „Techniki projektowania de- koratorów”. Czasami chcieliby(cid:258)my, aby w Pythonie by(cid:239)y wersje wy(cid:285)szego rz(cid:218)du funkcji przetwarzania kolekcji opisanych w poprzednim rozdziale. W tym rozdziale w celu wykonania redukcji okre(cid:258)lonych pól wyodr(cid:218)bnionych z wi(cid:218)kszej krotki zaprezentujemy wzorzec projektowy zredukuj(wyodr(cid:218)bnij()). Przyjrzymy si(cid:218) równie(cid:285) definiowaniu w(cid:239)asnej wersji tych powszechnie wykorzystywanych funkcji przetwarzania kolekcji. Poleć książkęKup książkę Python. Programowanie funkcyjne W tym rozdziale przyjrzymy si(cid:218) nast(cid:218)puj(cid:200)cym funkcjom: (cid:81) max() i min(); (cid:81) map(); (cid:81) filter(); (cid:81) iter(); (cid:81) sorted(). Przyjrzymy si(cid:218) tak(cid:285)e formatowi wyra(cid:285)e(cid:241) lambda, których mo(cid:285)na u(cid:285)y(cid:202) w celu uproszczenia korzystania z funkcji wy(cid:285)szego rz(cid:218)du. Szereg funkcji wy(cid:285)szego rz(cid:218)du jest dost(cid:218)pnych w module itertools. Przyjrzymy si(cid:218) temu modu(cid:239)owi w rozdziale 8. „Modu(cid:239) itertools” oraz w rozdziale 9. „Dodatkowe techniki itertools”. Ponadto w module functools jest dost(cid:218)pna funkcja ogólnego przeznaczenia reduce(). Przyj- rzymy si(cid:218) jej w rozdziale 10. „Modu(cid:239) funktools”, poniewa(cid:285) nie jest tak powszechnie stosowana jak inne funkcje wy(cid:285)szego rz(cid:218)du opisane w tym rozdziale. Funkcje max() i min() s(cid:200) redukcjami — tworz(cid:200) pojedyncz(cid:200) warto(cid:258)(cid:202) z kolekcji. Pozosta(cid:239)e funkcje to mapowania. Nie redukuj(cid:200) warto(cid:258)ci wej(cid:258)ciowej do pojedynczej warto(cid:258)ci. Funkcje max(), min() i sorted() maj(cid:200) zarówno zachowania domy(cid:258)lne, jak i zachowania funkcji wy(cid:285)szego rz(cid:218)du. Funkcj(cid:218) mo(cid:285)na dostarczy(cid:202) za pomoc(cid:200) argumentu key=. Funkcje map() i filter() przyjmuj(cid:200) funkcj(cid:218) jako pierwszy argument pozycyjny. Wykorzystanie funkcji max() i min() do wyszukiwania ekstremów Funkcje max() i min() „wiod(cid:200) podwójne (cid:285)ycie”. S(cid:200) prostymi funkcjami maj(cid:200)cymi zastosowanie do kolekcji. S(cid:200) równie(cid:285) funkcjami wy(cid:285)szego rz(cid:218)du. Ich domy(cid:258)lne zachowanie mo(cid:285)emy zaobser- wowa(cid:202) w nast(cid:218)puj(cid:200)cym kodzie: max(1, 2, 3) 3 max((1,2,3,4)) 4 Obie funkcje przyjmuj(cid:200) nieokre(cid:258)lon(cid:200) liczb(cid:218) argumentów. Funkcje s(cid:200) zaprojektowane tak, aby akceptowa(cid:239)y sekwencj(cid:218) lub obiekt iterowalny jako jedyny argument i lokalizowa(cid:239)y warto(cid:258)(cid:202) maksymaln(cid:200) (lub minimaln(cid:200)) tego obiektu iterowalnego. 98 Poleć książkęKup książkę Rozdzia(cid:225) 5. • Funkcje wy(cid:298)szego rz(cid:266)du Wykonuj(cid:200) równie(cid:285) bardziej wyrafinowane dzia(cid:239)ania. Za(cid:239)ó(cid:285)my, (cid:285)e mamy dane podró(cid:285)y z przyk(cid:239)a- dów w rozdziale 4. „Praca z kolekcjami”. Mamy funkcj(cid:218) generuj(cid:200)c(cid:200) sekwencj(cid:218) krotek, która wygl(cid:200)da nast(cid:218)puj(cid:200)co: ( ((37.54901619777347, -76.33029518659048), (37.840832, -76.273834), 17.7246), ((37.840832, -76.273834), (38.331501, -76.459503), 30.7382), ((38.331501, -76.459503), (38.845501, -76.537331), 31.0756), ((36.843334, -76.298668), (37.549, -76.331169), 42.3962), ((37.549, -76.331169), (38.330166, -76.458504), 47.2866), ((38.330166, -76.458504), (38.976334, -76.473503), 38.8019) ) Ka(cid:285)da krotka w tej kolekcji sk(cid:239)ada si(cid:218) z trzech warto(cid:258)ci: lokalizacji pocz(cid:200)tkowej, ko(cid:241)cowej i odle- g(cid:239)o(cid:258)ci pomi(cid:218)dzy nimi. Lokalizacje s(cid:200) podane za pomoc(cid:200) par z(cid:239)o(cid:285)onych z szeroko(cid:258)ci i d(cid:239)ugo(cid:258)ci geograficznej. Wschodnia szeroko(cid:258)(cid:202) geograficzna jest dodatnia, wi(cid:218)c s(cid:200) to punkty wzd(cid:239)u(cid:285) wschodniego wybrze(cid:285)a USA, oko(cid:239)o 76° na zachód. Odleg(cid:239)o(cid:258)ci mi(cid:218)dzy punktami s(cid:200) wyra(cid:285)one w milach morskich. Istniej(cid:200) trzy sposoby uzyskania maksymalnych i minimalnych odleg(cid:239)o(cid:258)ci z tej sekwencji warto(cid:258)ci. Oto one: (cid:81) Wyodr(cid:218)bnienie odleg(cid:239)o(cid:258)ci za pomoc(cid:200) funkcji generatorowej. W ten sposób uzyskamy tylko odleg(cid:239)o(cid:258)ci, poniewa(cid:285) odrzucili(cid:258)my pozosta(cid:239)e dwa atrybuty ka(cid:285)dego odcinka. Takie rozwi(cid:200)zanie nie zadzia(cid:239)a dobrze, je(cid:258)li b(cid:218)dziemy mieli jakiekolwiek dodatkowe wymagania co do przetwarzania. (cid:81) Wykorzystanie wzorca rozpakuj(przetwarzaj(opakuj())). Za jego pomoc(cid:200) uzyskamy najd(cid:239)u(cid:285)szy i najkrótszy odcinek. Na tej podstawie mo(cid:285)emy wydoby(cid:202) element opisuj(cid:200)cy odleg(cid:239)o(cid:258)(cid:202), je(cid:258)li to on jest potrzebny. (cid:81) Wykorzystanie max() i min() jako funkcji wy(cid:285)szego rz(cid:218)du — wstawienie funkcji, która wykonuje ekstrakcj(cid:218) istotnych warto(cid:258)ci odleg(cid:239)o(cid:258)ci. W celu zaprezentowania kontekstu poni(cid:285)ej zamieszczono skrypt, który buduje obiekt trip reprezentuj(cid:200)cy podró(cid:285): from ch02_ex3 import ( float_from_pair, lat_lon_kml, limits, haversine, legs ) path = float_from_pair(float_lat_lon(row_iter_kml(source))) trip = tuple( (start, end, round(haversine(start, end), 4)) for start, end in legs(iter(path))) Powy(cid:285)szy skrypt wymaga, aby argument source by(cid:239) otwartym plikiem zawieraj(cid:200)cym punkty danych w formacie KML. Najwa(cid:285)niejszy obiekt trip to krotka z(cid:239)o(cid:285)ona z pojedynczych odcinków. Ka(cid:285)dy odcinek jest trójelementow(cid:200) krotk(cid:200) sk(cid:239)adaj(cid:200)c(cid:200) si(cid:218) z punktu pocz(cid:200)tkowego, ko(cid:241)cowego oraz odleg(cid:239)o(cid:258)ci obliczanej za pomoc(cid:200) funkcji haversine. Na podstawie ogólnej (cid:258)cie(cid:285)ki punktów w oryginalnym pliku KML funkcja leg tworzy pary punktów pocz(cid:200)tek i koniec. 99 Poleć książkęKup książkę Python. Programowanie funkcyjne Po uzyskaniu obiektu trip mo(cid:285)emy wyodr(cid:218)bni(cid:202) odleg(cid:239)o(cid:258)ci i obliczy(cid:202) ich warto(cid:258)ci maksymaln(cid:200) i minimaln(cid:200). Kod s(cid:239)u(cid:285)(cid:200)cy do tego celu i korzystaj(cid:200)cy z funkcji generatorowej wygl(cid:200)da nast(cid:218)puj(cid:200)co: long = max(dist for start, end, dist in trip) short = min(dist for start, end, dist in trip) Aby wyodr(cid:218)bni(cid:202) odpowiedni element z ka(cid:285)dego odcinka nale(cid:285)(cid:200)cego do krotki trip, u(cid:285)yli(cid:258)my funkcji generatorowej. Musieli(cid:258)my powtórzy(cid:202) funkcj(cid:218) generatorow(cid:200), poniewa(cid:285) ka(cid:285)de wyra(cid:285)enie generatorowe mo(cid:285)e by(cid:202) u(cid:285)yte tylko raz. Oto wyniki uzyskane na podstawie wi(cid:218)kszego zbioru danych ni(cid:285) ten, który pokazano wcze(cid:258)niej: long 129.7748 short 0.1731 Poni(cid:285)ej zamieszczono wersj(cid:218) z wykorzystaniem wzorca rozpakuj(przetwarzaj(opakuj())). Aby to by(cid:239)o jasne, w przyk(cid:239)adzie wykorzystano funkcje o nazwach wrap() i unwrap(). Oto funkcje i ich wywo(cid:239)ania: from typing import Iterator, Iterable, Tuple, Any Wrapped = Tuple[Any, Tuple] def wrap(leg_iter: Iterable[Tuple]) - Iterable[Wrapped]: return ((leg[2], leg) for leg in leg_iter) def unwrap(dist_leg: Tuple[Any, Any]) - Any: distance, leg = dist_leg return leg long = unwrap(max(wrap(trip))) short = unwrap(min(wrap(trip))) W przeciwie(cid:241)stwie do poprzedniej wersji funkcje max() i min() lokalizuj(cid:200) wszystkie atrybuty odcinków o najd(cid:239)u(cid:285)szej i najkrótszej odleg(cid:239)o(cid:258)ci. Zamiast po prostu wyodr(cid:218)bnia(cid:202) odleg(cid:239)o(cid:258)ci, naj- pierw umieszczamy odleg(cid:239)o(cid:258)ci w ka(cid:285)dej opakowanej krotce. Mo(cid:285)emy nast(cid:218)pnie u(cid:285)y(cid:202) domy(cid:258)l- nych formatów funkcji min() i max() w celu przetworzenia dwóch krotek, które zawieraj(cid:200) odleg(cid:239)o(cid:258)(cid:202) i szczegó(cid:239)y odcinka. Po przetworzeniu mo(cid:285)emy usun(cid:200)(cid:202) pierwszy element, pozosta- wiaj(cid:200)c tylko szczegó(cid:239)y odcinka. Wynik ma nast(cid:218)puj(cid:200)c(cid:200) posta(cid:202): ((27.154167, -80.195663), (29.195168, -81.002998), 129.7748) ((35.505665, -76.653664), (35.508335, -76.654999), 0.1731) W ostatnim i najwa(cid:285)niejszym formacie wykorzystali(cid:258)my cech(cid:218) wy(cid:285)szego rz(cid:218)du funkcji max() i min(). Najpierw zdefiniujemy funkcj(cid:218) pomocnicz(cid:200), a nast(cid:218)pnie wykorzystamy j(cid:200) do zreduko- wania kolekcji odcinków do (cid:285)(cid:200)danych podsumowa(cid:241) za pomoc(cid:200) poni(cid:285)szego fragmentu kodu: def by_dist(leg: Tuple[Any, Any, Any]) - Any: lat, lon, dist = leg return dist 100 Poleć książkęKup książkę Rozdzia(cid:225) 5. • Funkcje wy(cid:298)szego rz(cid:266)du long = max(trip, key=by_dist) short = min(trip, key=by_dist) Funkcja by_dist() wybiera z krotki ka(cid:285)dego odcinka trzy elementy i zwraca element reprezen- tuj(cid:200)cy odleg(cid:239)o(cid:258)(cid:202). U(cid:285)yjemy jej z funkcjami max() i min(). Funkcje max() i min() pobieraj(cid:200) jako argumenty zarówno iteracj(cid:218), jak i funkcj(cid:218). Wszystkie funkcje wy(cid:285)szego rz(cid:218)du w Pythonie do dostarczenia funkcji, która b(cid:218)dzie u(cid:285)ywana do wyodr(cid:218)b- nienia niezb(cid:218)dnej warto(cid:258)ci klucza, u(cid:285)ywaj(cid:200) parametru ze s(cid:239)owem kluczowym key=. Aby lepiej wyobrazi(cid:202) sobie sposób, w jaki funkcja max() u(cid:285)ywa funkcji key, mo(cid:285)emy skorzysta(cid:202) z poni(cid:285)szego kodu: from typing import Iterable, Any, Callable def max_like(trip: Iterable[Any], key: Callable) - Any: wrap = ((key(leg), leg) for leg in trip) return sorted(wrap)[-1][1] Funkcje max() i min() zachowuj(cid:200) si(cid:218) tak, jakby wynik podanej funkcji key() by(cid:239) u(cid:285)ywany do opa- kowania ka(cid:285)dego elementu w sekwencji w dwuelementow(cid:200) krotk(cid:218). Po posortowaniu dwuele- mentowych krotek wybranie pierwszej z nich (jako minimum) lub ostatniej (jako maksimum) pozwala na zwrócenie krotki z warto(cid:258)ci(cid:200) ekstremaln(cid:200). Mo(cid:285)na j(cid:200) zdekomponowa(cid:202), aby odzyska(cid:202) oryginaln(cid:200) warto(cid:258)(cid:202). Aby funkcja key() by(cid:239)a opcjonalna, nale(cid:285)y okre(cid:258)li(cid:202) jej warto(cid:258)(cid:202) domy(cid:258)ln(cid:200) lambda x: x. Korzystanie z formatu wyra(cid:285)e(cid:241) lambda w Pythonie W wielu przypadkach wydaje si(cid:218), (cid:285)e definicja funkcji pomocniczej to zbyt wiele kodu. Cz(cid:218)sto mo(cid:285)emy sprowadzi(cid:202) funkcj(cid:218) key do pojedynczego wyra(cid:285)enia. Konieczno(cid:258)(cid:202) pisania instrukcji def i return, aby opakowa(cid:202) pojedyncze wyra(cid:285)enie, mo(cid:285)e wydawa(cid:202) si(cid:218) marnotrawstwem. Python oferuje format lambda jako sposób na uproszczenie korzystania z funkcji wy(cid:285)szego rz(cid:218)du. Format lambda pozwala zdefiniowa(cid:202) niewielk(cid:200) funkcj(cid:218) anonimow(cid:200). Tre(cid:258)(cid:202) funkcji ogranicza si(cid:218) do pojedynczego wyra(cid:285)enia. Oto przyk(cid:239)ad u(cid:285)ycia prostego wyra(cid:285)enia lambda jako funkcji key: long = max(trip, key=lambda leg: leg[2]) short = min(trip, key=lambda leg: leg[2]) Do zastosowanego wyra(cid:285)enia lambda zostanie przekazany element sekwencji. W tym przypadku do wyra(cid:285)enia lambda przeka(cid:285)emy poszczególne trójelementowe krotki reprezentuj(cid:200)ce odcinki. Do zmiennej leg argumentu wyra(cid:285)enia lambda jest podstawiana krotka, a nast(cid:218)pnie wyzna- czana jest warto(cid:258)(cid:202) leg[2], która z trójelementowej krotki pobiera odleg(cid:239)o(cid:258)(cid:202). W przypadkach, 101 Poleć książkęKup książkę Python. Programowanie funkcyjne gdy wyra(cid:285)enie lambda jest u(cid:285)ywane dok(cid:239)adnie raz, ten format jest idealny. Je(cid:258)li wykorzy- stujemy wyra(cid:285)enia lambda wielokrotnie, powinni(cid:258)my unika(cid:202) kopiowania i wklejania. Jaka jest alternatywa? Mo(cid:285)emy przypisa(cid:202) wyra(cid:285)enia lambda do zmiennych. Na przyk(cid:239)ad: start = lambda x: x[0] end = lambda x: x[1] dist = lambda x: x[2] Ka(cid:285)dy z tych formatów wyra(cid:285)e(cid:241) lambda jest obiektem wywo(cid:239)ywalnym, podobnym do zdefinio- wanej funkcji. Mo(cid:285)na ich u(cid:285)ywa(cid:202) tak jak funkcji. Poni(cid:285)szy przyk(cid:239)ad przedstawia interaktywn(cid:200) sesj(cid:218): leg = ((27.154167, -80.195663), (29.195168, -81.002998), 129.7748) start = lambda x: x[0] end = lambda x: x[1] dist = lambda x: x[2] dist(leg) 129.7748 Python oferuje dwa sposoby przypisywania opisowych nazw do elementów krotek: nazwane krotki (obiekty namedtuple) i kolekcje wyra(cid:285)e(cid:241) lambda. Oba s(cid:200) równowa(cid:285)ne. Mo(cid:285)emy u(cid:285)ywa(cid:202) wyra(cid:285)e(cid:241) lambda zamiast nazwanych krotek. Aby rozszerzy(cid:202) ten przyk(cid:239)ad, przyjrzymy si(cid:218), jak uzyska(cid:202) warto(cid:258)ci szeroko(cid:258)ci lub d(cid:239)ugo(cid:258)ci geo- graficznej punktu pocz(cid:200)tkowego lub ko(cid:241)cowego. Mo(cid:285)na to zrobi(cid:202) poprzez zdefiniowanie do- datkowych wyra(cid:285)e(cid:241) lambda. Oto kontynuacja wcze(cid:258)niejszej interaktywnej sesji: start(leg) (27.154167, -80.195663) lat = lambda x: x[0] lon = lambda x: x[1] lat(start(leg)) 27.154167 Nie ma wyra(cid:283)nej przewagi z u(cid:285)ywania jako sposobu na wyodr(cid:218)bnianie pól wyra(cid:285)e(cid:241) lambda zamiast nazwanych krotek. Zbiór obiektów lambda do wyodr(cid:218)bniania pól wymaga zdefinio- wania wi(cid:218)cej linijek kodu ni(cid:285) nazwana krotka. Z drugiej strony wyra(cid:285)enia lambda pozwalaj(cid:200) na korzystanie z notacji prefiksowej, która mo(cid:285)e by(cid:202) czytelniejsza w kontek(cid:258)cie programowania funkcyjnego. Co wa(cid:285)niejsze, jak przekonamy si(cid:218) pó(cid:283)niej w przyk(cid:239)adzie u(cid:285)ycia funkcji sorted(), z wyra(cid:285)e(cid:241) lambda mo(cid:285)na korzysta(cid:202) bardziej efektywnie ni(cid:285) z atrybutów nazwanych krotek w funkcjach sorted(), min() i max(). 102 Poleć książkęKup książkę Rozdzia(cid:225) 5. • Funkcje wy(cid:298)szego rz(cid:266)du Wyra(cid:285)enia lambda i rachunek lambda W ksi(cid:200)(cid:285)ce po(cid:258)wi(cid:218)conej czysto funkcyjnemu j(cid:218)zykowi programowania by(cid:239)oby konieczne wyja- (cid:258)nienie rachunku lambda i techniki wymy(cid:258)lonej przez Haskella Curry’ego okre(cid:258)lanej jako rozwijanie funkcji (ang. currying). Python nie trzyma si(cid:218) jednak (cid:258)ci(cid:258)le tego rodzaju rachunku lambda. Funkcje nie s(cid:200) rozwijane w celu zredukowania ich do jednoargumentowych wyra(cid:285)e(cid:241) lambda. Format wyra(cid:285)e(cid:241) lambda w Pythonie nie ogranicza si(cid:218) do funkcji jednoargumentowych. Lambdy mog(cid:200) mie(cid:202) dowoln(cid:200) liczb(cid:218) argumentów. S(cid:200) jednak ograniczone do pojedynczego wyra(cid:285)enia. U(cid:285)ywaj(cid:200)c funkcji functools.partial, mo(cid:285)emy zaimplementowa(cid:202) rozwijanie funkcji. Omówienie tego tematu od(cid:239)o(cid:285)ymy do rozdzia(cid:239)u 10. „Modu(cid:239) functools”. Korzystanie z funkcji map() w celu zastosowania funkcji do kolekcji Funkcja skalarna mapuje warto(cid:258)ci z dziedziny na zakres. Kiedy spojrzymy na przyk(cid:239)ad funkcji math.sqrt(), widzimy mapowanie warto(cid:258)ci x typu float na inn(cid:200) warto(cid:258)(cid:202) float y = sqrt(x), tak(cid:200) (cid:285)e y2 = x. Dziedzina jest ograniczona do warto(cid:258)ci dodatnich. Mapowanie mo(cid:285)na wykona(cid:202) poprzez obliczenie lub interpolacj(cid:218) tabeli. Funkcja map() wyra(cid:285)a podobn(cid:200) koncepcj(cid:218) — mapuje warto(cid:258)ci z jednej kolekcji, aby utworzy(cid:202) inn(cid:200) kolekcj(cid:218). To daje pewno(cid:258)(cid:202), (cid:285)e podana funkcja zostanie u(cid:285)yta do zmapowania ka(cid:285)dego pojedynczego elementu z kolekcji reprezentuj(cid:200)cej dziedzin(cid:218) na kolekcj(cid:218) zakresu — idealny sposób zastosowania funkcji wbudowanej do zbioru danych. Nasz pierwszy przyk(cid:239)ad obejmuje parsowanie bloku tekstu w celu uzyskania sekwencji liczb. Za(cid:239)ó(cid:285)my, (cid:285)e mamy nast(cid:218)puj(cid:200)cy fragment tekstu: text= \ ... 2 3 5 7 11 13 17 19 23 29 ... 31 37 41 43 47 53 59 61 67 71 ... 73 79 83 89 97 101 103 107 109 113 ... 127 131 137 139 149 151 157 163 167 173 ... 179 181 191 193 197 199 211 223 227 229 ... Mo(cid:285)emy zmieni(cid:202) struktur(cid:218) tego tekstu za pomoc(cid:200) nast(cid:218)puj(cid:200)cej funkcji generatorowej: data= list( ... v for line in text.splitlines() ... for v in line.split()) 103 Poleć książkęKup książkę Python. Programowanie funkcyjne Wykonanie tego kodu spowoduje podzielenie tekstu na wiersze. Powy(cid:285)szy kod dzieli ka(cid:285)dy wiersz na wyrazy rozdzielone spacjami i iteruje po ci(cid:200)gach uzyskanych w wyniku. Wyniki te maj(cid:200) nast(cid:218)puj(cid:200)c(cid:200) posta(cid:202): [ 2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 , 29 , 31 , 37 , 41 , 43 , 47 , 53 , 59 , 61 , 67 , 71 , 73 , 79 , 83 , 89 , 97 , 101 , 103 , 107 , 109 , 113 , 127 , 131 , 137 , 139 , 149 , 151 , 157 , 163 , 167 , 173 , 179 , 181 , 191 , 193 , 197 , 199 , 211 , 223 , 227 , 229 ] Do ka(cid:285)dej z warto(cid:258)ci tekstowych nadal trzeba zastosowa(cid:202) funkcj(cid:218) int(). Do tego doskonale nadaje si(cid:218) funkcja map(). Przyjrzyjmy si(cid:218) poni(cid:285)szemu przyk(cid:239)adowi kodu: list(map(int, data)) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229] Funkcja map() zastosowa(cid:239)a funkcj(cid:218) int() do ka(cid:285)dej warto(cid:258)ci w kolekcji. Wynik jest sekwencj(cid:200) z(cid:239)o(cid:285)on(cid:200) z liczb, a nie sekwencj(cid:200) ci(cid:200)gów znaków. Wyniki funkcji map() s(cid:200) iterowalne. Funkcja map() mo(cid:285)e przetwarza(cid:202) dowolny obiekt iterowalny. Idea jest taka, (cid:285)e przy u(cid:285)yciu funkcji map() mo(cid:285)e by(cid:202) zastosowana do elementów kolekcji ka(cid:285)da funkcja Pythona. Istnieje wiele wbudowanych funkcji, które mo(cid:285)na wykorzysta(cid:202) w kontek(cid:258)cie przetwarzania z mapowaniem. Wykorzystanie wyra(cid:285)e(cid:241) lambda i funkcji map() Powiedzmy, (cid:285)e chcemy dokona(cid:202) konwersji odleg(cid:239)o(cid:258)ci z mil morskich na l(cid:200)dowe. Chcemy po- mno(cid:285)y(cid:202) odleg(cid:239)o(cid:258)(cid:202) ka(cid:285)dego odcinka przez 6076,12/5280, czyli 1,150780. Takie obliczenia mo(cid:285)emy wykona(cid:202) za pomoc(cid:200) funkcji map() w nast(cid:218)puj(cid:200)cy sposób: map( lambda x: (start(x), end(x), dist(x)*6076.12/5280), trip ) Zdefiniowali(cid:258)my wyra(cid:285)enie lambda, które zostanie zastosowane do ka(cid:285)dego odcinka podró(cid:285)y za po(cid:258)rednictwem funkcji map(). Wyra(cid:285)enie lambda u(cid:285)ywa innych wyra(cid:285)e(cid:241) lambda w celu wy- dzielenia z ka(cid:285)dego odcinka warto(cid:258)ci pocz(cid:200)tku, ko(cid:241)ca i odleg(cid:239)o(cid:258)ci. Wyra(cid:285)enie oblicza skorygo- wan(cid:200) odleg(cid:239)o(cid:258)(cid:202) i na podstawie warto(cid:258)ci pocz(cid:200)tku, ko(cid:241)ca i odleg(cid:239)o(cid:258)ci w milach l(cid:200)dowych tworzy now(cid:200) krotk(cid:218) odcinka. Dok(cid:239)adnie takie dzia(cid:239)anie wykonuje nast(cid:218)puj(cid:200)ce wyra(cid:285)enie generatorowe: ((start(x), end(x), dist(x)*6076.12/5280) for x in trip) 104 Poleć książkęKup książkę Rozdzia(cid:225) 5. • Funkcje wy(cid:298)szego rz(cid:266)du W wyra(cid:285)eniu generatorowym wykonali(cid:258)my identyczne przetwarzanie dla ka(cid:285)dego elementu kolekcji. Wa(cid:285)n(cid:200) ró(cid:285)nic(cid:200) pomi(cid:218)dzy funkcj(cid:200) map() a wyra(cid:285)eniem generatorowym jest to, (cid:285)e w funkcji map() mo(cid:285)na pos(cid:239)ugiwa(cid:202) si(cid:218) definicj(cid:200) wyra(cid:285)enia lambda lub funkcji wielokrotnego u(cid:285)ytku. Lepszym rozwi(cid:200)zaniem jest wykorzystanie nast(cid:218)puj(cid:200)cego kodu: to_miles = lambda x: start(x), end(x), dist(x)*6076.12/5280 trip_m = map(to_miles, trip) W tym wariancie oddzielili(cid:258)my transformacj(cid:218) to_miles od procesu stosowania tej transformacji do danych. U(cid:285)ycie funkcji map() w odniesieniu do wielu sekwencji Czasami mamy dwie kolekcje danych, które musz(cid:200) by(cid:202) do siebie równoleg(cid:239)e. W rozdziale 4. „Praca z kolekcjami” widzieli(cid:258)my, (cid:285)e za pomoc(cid:200) funkcji zip() mo(cid:285)na przeplata(cid:202) dwie sekwencje w celu utworzenia sekwencji par. W wielu przypadkach w istocie próbujemy zrobi(cid:202) co(cid:258) takiego: map(function, zip(one_iterable, another_iterable)) Utworzyli(cid:258)my krotki argumentów na podstawie dwóch (lub wi(cid:218)kszej liczby) równoleg(cid:239)ych obiektów iterowalnych i zastosowali(cid:258)my funkcj(cid:218) do tych krotek argumentów. Mo(cid:285)emy równie(cid:285) spojrze(cid:202) na to w nast(cid:218)puj(cid:200)cy sposób: (function(x,y) for x,y in zip(jeden_obiekt_iterowalny, inny_obiekt_iterowalny) ) W tym przypadku zast(cid:200)pili(cid:258)my funkcj(cid:218) map() równowa(cid:285)nym wyra(cid:285)eniem generatorowym. Mogliby(cid:258)my uogólni(cid:202) ca(cid:239)o(cid:258)(cid:202) do nast(cid:218)puj(cid:200)cej postaci: def star_map(function, *iterables) return (function(*args) for args in zip(*iterables)) Istnieje jednak lepsze podej(cid:258)cie. W istocie nie potrzebujemy tych technik. Przyjrzyjmy si(cid:218) konkretnemu przyk(cid:239)adowi podej(cid:258)cia alternatywnego. W rozdziale 4. „Praca z kolekcjami” przyjrzeli(cid:258)my si(cid:218) danym dotycz(cid:200)cym podró(cid:285)y, które wyod- r(cid:218)bnili(cid:258)my z pliku XML jako ci(cid:200)g punktów po(cid:258)rednich. Chcieli(cid:258)my stworzy(cid:202) z tej listy punktów odcinki, które zawieraj(cid:200) dane na temat pocz(cid:200)tku i ko(cid:241)ca. Poni(cid:285)ej znajduje si(cid:218) uproszczona wersja, w której u(cid:285)yto funkcji zip() do specjalnego rodzaju obiektu iterowalnego: 105 Poleć książkęKup książkę Python. Programowanie funkcyjne waypoints = range(4) zip(waypoints, waypoints[1:]) zip object at 0x101a38c20 list(_) [(0, 1), (1, 2), (2, 3)] Stworzyli(cid:258)my sekwencj(cid:218) par, które wybrali(cid:258)my z pojedynczej, p(cid:239)askiej listy. Ka(cid:285)da para ma dwie s(cid:200)siednie warto(cid:258)ci. Funkcja zip() prawid(cid:239)owo zatrzymuje si(cid:218), gdy krótsza lista si(cid:218) wyczer- pie. Ten wzorzec zip(x, x [1:]) dzia(cid:239)a tylko dla sekwencji zmaterializowanych oraz obiektów iterowalnych utworzonych za pomoc(cid:200) funkcji range(). Stworzyli(cid:258)my pary, (cid:285)eby zastosowa(cid:202) do ka(cid:285)dej z nich funkcj(cid:218) haversine(). W ten sposób ob- liczymy odleg(cid:239)o(cid:258)(cid:202) pomi(cid:218)dzy dwoma punktami na (cid:258)cie(cid:285)ce. Oto jak wygl(cid:200)da jedna sekwencja kroków: from ch02_ex3 import (lat_lon_kml, float_from_pair, haversine) path = tuple(float_from_pair(lat_lon_kml())) distances_1 = map( lambda s_e: (s_e[0], s_e[1], haversine(*s_e)), zip(path, path[1:]) ) Za(cid:239)adowali(cid:258)my niezb(cid:218)dn(cid:200) sekwencj(cid:218) punktów do zmiennej path. Jest to uporz(cid:200)dkowana sekwencja par szeroko(cid:258)ci i d(cid:239)ugo(cid:258)ci geograficznej. Poniewa(cid:285) zamierzamy u(cid:285)y(cid:202) wzorca projektowego zip (cid:180)(path, path[1:]), musimy mie(cid:202) zmaterializowan(cid:200) sekwencj(cid:218), a nie prosty obiekt iterowalny. Wynikami funkcji zip() s(cid:200) pary, które maj(cid:200) pocz(cid:200)tek i koniec. Chcemy, aby wynik by(cid:239) trójk(cid:200) sk(cid:239)adaj(cid:200)c(cid:200) si(cid:218) z pocz(cid:200)tku, ko(cid:241)ca i odleg(cid:239)o(cid:258)ci. Zastosowane wyra(cid:285)enie lambda dekomponuje wej- (cid:258)ciow(cid:200) dwuelementow(cid:200) krotk(cid:218) z(cid:239)o(cid:285)on(cid:200) z danych na temat pocz(cid:200)tku i ko(cid:241)ca i tworzy now(cid:200), trójelementow(cid:200) krotk(cid:218) zawieraj(cid:200)c(cid:200) pocz(cid:200)tek, koniec i odleg(cid:239)o(cid:258)(cid:202). Jak wspomniano wcze(cid:258)niej, mo(cid:285)emy to upro(cid:258)ci(cid:202), u(cid:285)ywaj(cid:200)c sprytnej w(cid:239)asno(cid:258)ci funkcji map(), jak pokazano poni(cid:285)ej: distances_2 = map( lambda s, e: (s, e, haversine(s, e)), path, path[1:]) Zauwa(cid:285)my, (cid:285)e dostarczyli(cid:258)my do funkcji map() funkcj(cid:218) i dwa obiekty iterowalne. Funkcja map() pobierze nast(cid:218)pny element z ka(cid:285)dego obiektu iterowalnego i zastosuje te dwie warto(cid:258)ci jako argumenty do podanej funkcji. W tym przypadku podana funkcja jest wyra(cid:285)eniem lambda, które tworzy po(cid:285)(cid:200)dan(cid:200) trójelementow(cid:200) krotk(cid:218) z(cid:239)o(cid:285)on(cid:200) z pocz(cid:200)tku, ko(cid:241)ca i odleg(cid:239)o(cid:258)ci. Formalna definicja funkcji map() mówi, (cid:285)e funkcja ta wykonuje przetwarzanie typu „mapa gwiazd” dla nieokre(cid:258)lonej liczby obiektów iterowalnych. Pobiera elementy z ka(cid:285)dego obiektu iterowalnego, aby utworzy(cid:202) krotk(cid:218) warto(cid:258)ci argumentów dla podanej funkcji. 106 Poleć książkęKup książkę Rozdzia(cid:225) 5. • Funkcje wy(cid:298)szego rz(cid:266)du Wykorzystanie funkcji filter() do przekazywania lub odrzucania danych Zadaniem funkcji filter() jest u(cid:285)ycie funkcji decyzyjnej zwanej predykatem do ka(cid:285)dej warto(cid:258)ci w kolekcji. Decyzja True oznacza, (cid:285)e warto(cid:258)(cid:202) zostanie przekazana; w przeciwnym razie warto(cid:258)(cid:202) zostanie odrzucona. Modu(cid:239) itertools zawiera funkcj(cid:218) filterfalse(), która jest odmian(cid:200) funkcji filter(). U(cid:285)ycie funkcji filterfalse() z modu(cid:239)u itertools zaprezentowano w rozdziale 8. „Modu(cid:239) itertools”. Mo(cid:285)emy zastosowa(cid:202) t(cid:218) funkcj(cid:218) do naszych danych podró(cid:285)y, aby utworzy(cid:202) podzbiór odcinków o d(cid:239)ugo(cid:258)ci ponad 50 mil morskich: long= list( filter(lambda leg: dist(leg) = 50, trip)) ) Predykat lambda zwróci True dla d(cid:239)ugich odcinków, które zostan(cid:200) zwrócone. Krótkie odcinki zo- stan(cid:200) odrzucone. Wynik to 14 odcinków, które pomy(cid:258)lnie przesz(cid:239)y ten test odleg(cid:239)o(cid:258)ci. W przetwarzaniu tego rodzaju wyra(cid:283)nie oddzielono zasad(cid:218) filtrowania (lambda leg: dist(leg) = 50) od innego przetwarzania, które tworzy obiekt trip lub analizuje d(cid:239)ugie odcinki. W ramach kolejnego, prostego przyk(cid:239)adu przyjrzyjmy si(cid:218) poni(cid:285)szemu fragmentowi kodu: filter(lambda x: x 3==0 or x 5==0, range(10)) filter object at 0x101d5de50 sum(_) 23 Aby sprawdzi(cid:202), czy liczba jest wielokrotno(cid:258)ci(cid:200) trzech lub wielokrotno(cid:258)ci(cid:200) pi(cid:218)ciu, zdefiniowali- (cid:258)my proste wyra(cid:285)enie lambda. Zastosowali(cid:258)my t(cid:218) funkcj(cid:218) do obiektu iterowalnego range(10). Wynikiem jest iterowalna sekwencja liczb, które „przesz(cid:239)y” warunek regu(cid:239)y decyzyjnej. Liczby, dla których wyra(cid:285)enie lambda ma warto(cid:258)(cid:202) True, to [0, 3, 5, 6, 9], wi(cid:218)c te warto(cid:258)ci zostan(cid:200) przekazane dalej. Poniewa(cid:285) wyra(cid:285)enie lambda ma warto(cid:258)(cid:202) False dla wszystkich innych liczb, to zostan(cid:200) one odrzucone. Mo(cid:285)na to równie(cid:285) zrobi(cid:202) za pomoc(cid:200) wyra(cid:285)enia generatorowego, uruchamiaj(cid:200)c nast(cid:218)puj(cid:200)cy kod: list(x for x in range(10) if x 3==0 or x 5==0) [0, 3, 5, 6, 9] Mo(cid:285)emy to sformalizowa(cid:202) za pomoc(cid:200) nast(cid:218)puj(cid:200)cej notacji zbioru sk(cid:239)adanego (ang. set comprehension): 10 (cid:31)(cid:100) 03mod (cid:155)(cid:32) (cid:12) (cid:96)05mod (cid:32) (cid:94) x (cid:154) (cid:11) x 0| x x 107 Poleć książkęKup książkę Python. Programowanie funkcyjne Oznacza ona, (cid:285)e budujemy zbiór warto(cid:258)ci x takich, (cid:285)e x nale(cid:285)y do range(10) oraz x 3 == 0 lub x 5 == 0. Istnieje elegancka symetria pomi(cid:218)dzy funkcj(cid:200) filter() a formalnym, matema- tycznym rozumieniem zbioru sk(cid:239)adanego. Cz(cid:218)sto chcemy u(cid:285)y(cid:202) funkcji filter() ze zdefiniowanymi funkcjami zamiast wyra(cid:285)e(cid:241) lambda. Oto przyk(cid:239)ad wielokrotnego u(cid:285)ycia zdefiniowanego wcze(cid:258)niej predykatu: from ch01_ex1 import isprimeg list(range(100)) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] W tym przyk(cid:239)adzie zaimportowali(cid:258)my funkcj(cid:218) z innego modu(cid:239)u o nazwie isprimeg(). Nast(cid:218)pnie zastosowali(cid:258)my t(cid:218) funkcj(cid:218) do kolekcji warto(cid:258)ci, aby przekaza(cid:202) liczby pierwsze i odrzuci(cid:202) z kolek- cji wszystkie liczby, które nie s(cid:200) liczbami pierwszymi. Mo(cid:285)e to by(cid:202) bardzo niewydajny sposób generowania tabeli liczb pierwszych. Powierzchowna prostota jest czym(cid:258), co prawnicy nazywaj(cid:200) atrakcyjn(cid:200) uci(cid:200)(cid:285)liwo(cid:258)ci(cid:200). Wydaje si(cid:218), (cid:285)e mo(cid:285)e by(cid:202) interesuj(cid:200)ca, ale si(cid:218) dobrze nie skaluje. Funkcja isprimeg() dubluje wszystkie „wysi(cid:239)ki testowe” dla ka(cid:285)dej nowej warto(cid:258)ci. Dla zapewnienia wielokrotnego wykorzystania testu sprawdzaj(cid:200)cego, czy liczby s(cid:200) pierwsze, potrzebujemy jakiego(cid:258) rodzaju pami(cid:218)ci podr(cid:218)cznej. Lepszym algoryt- mem jest sito Eratostenesa. Ten algorytm zapami(cid:218)tuje wcze(cid:258)niej znalezione liczby pierwsze i wykorzystuje je, aby zapobiec konieczno(cid:258)ci ponownego obliczania. U(cid:285)ycie funkcji filter() do identyfikacji warto(cid:258)ci odstaj(cid:200)cych W poprzednim rozdziale zdefiniowali(cid:258)my kilka przydatnych funkcji statystycznych do obliczenia (cid:258)redniej i odchylenia standardowego oraz normalizacji warto(cid:258)ci. Mo(cid:285)emy wykorzysta(cid:202) te funkcje do zlokalizowania warto(cid:258)ci odstaj(cid:200)cych z naszych danych dotycz(cid:200)cych podró(cid:285)y. Do war- to(cid:258)ci odleg(cid:239)o(cid:258)ci ka(cid:285)dego odcinka podró(cid:285)y mo(cid:285)emy zastosowa(cid:202) funkcje mean() i stdev(), aby uzyska(cid:202) (cid:258)redni rozk(cid:239)ad i odchylenie standardowe. Nast(cid:218)pnie mo(cid:285)emy u(cid:285)y(cid:202) funkcji z() w celu obliczenia znormalizowanej warto(cid:258)ci dla ka(cid:285)dego odcinka. Je(cid:258)li znormalizowana warto(cid:258)(cid:202) jest wi(cid:218)ksza ni(cid:285) 3, dane s(cid:200) bardzo odleg(cid:239)e od (cid:258)redniej. Je(cid:258)li odrzucimy te odstaj(cid:200)ce warto(cid:258)ci, uzyskamy bardziej jednorodny zbiór danych, w którym istnieje mniejsze prawdopodobie(cid:241)stwo wyst(cid:218)powania b(cid:239)(cid:218)dów raportowania lub pomiaru. Oto jak mo(cid:285)emy sobie z tym poradzi(cid:202): from stats import mean, stdev, z dist_data = list(map(dist, trip)) (cid:349)_d = mean(dist_data) (cid:31)_d = stdev(dist_data) outlier = lambda leg: z(dist(leg), (cid:349)_d, (cid:31)_d) 3 108 Poleć książkęKup książkę Rozdzia(cid:225) 5. • Funkcje wy(cid:298)szego rz(cid:266)du print( Elementy odstaj(cid:200)ce , list(filter(outlier, trip))) Dla ka(cid:285)dego odcinka w kolekcji trip zmapowali(cid:258)my funkcj(cid:218) odleg(cid:239)o(cid:258)ci. Poniewa(cid:285) robimy z wynikiem kilka rzeczy, musimy zmaterializowa(cid:202) obiekt listy. Nie mo(cid:285)emy polega(cid:202) na iteratorze, poniewa(cid:285) pierwsza funkcja go wyczerpie. Zmaterializowanej listy mo(cid:285)emy nast(cid:218)pnie u(cid:285)y(cid:202) do obliczenia statystyk populacji (cid:349)_d i (cid:31)_d zawieraj(cid:200)cych (cid:258)rednie i odchylenie standardowe. Na podstawie statystyk u(cid:285)yli(cid:258)my do filtrowania danych wyra(cid:285)enia lambda outlier. Je(cid:258)li znorma- lizowana warto(cid:258)(cid:202) jest zbyt du(cid:285)a, dane odstaj(cid:200). Wynikiem wyra(cid:285)enia list(filter(outlier, trip)) jest lista z(cid:239)o(cid:285)ona z dwóch odcinków, które s(cid:200) do(cid:258)(cid:202) d(cid:239)ugie w porównaniu z reszt(cid:200) odcinków w populacji. (cid:165)redni odcinek wynosi oko(cid:239)o 34 mil morskich, przy standardowym odchyleniu 24 mil morskich. (cid:191)adna podró(cid:285) nie mo(cid:285)e mie(cid:202) znormalizowanej odleg(cid:239)o(cid:258)ci mniejszej ni(cid:285) –1,407. Do(cid:258)(cid:202) z(cid:239)o(cid:285)ony problem mo(cid:285)na roz(cid:239)o(cid:285)y(cid:202) na szereg niezale(cid:285)nych funkcji, z których ka(cid:285)da mo(cid:285)e by(cid:202) (cid:239)atwo przetestowana w izolacji. Nasze przetwarzanie to kompozycja prostszych funkcji. Takie podej(cid:258)cie pro- wadzi do zwi(cid:218)z(cid:239)ego, ekspresywnego programowania funkcyjnego. Funkcja iter() z warto(cid:258)ci(cid:200) „stra(cid:285)nika” Wbudowana funkcja iter() tworzy iterator po obiekcie klasy reprezentuj(cid:200)cej kolekcj(cid:218). Funkcja iter() dzia(cid:239)a dla klas list, dict i set. Tworzy obiekt iteratora dla elementów w przetwarza- nej kolekcji. W wi(cid:218)kszo(cid:258)ci przypadków pozwalamy, aby niejawnie realizowa(cid:239)a to instrukcja for. Jednak istniej(cid:200) sytuacje, kiedy musimy jawnie utworzy(cid:202) iterator. Jednym z przyk(cid:239)adów mo(cid:285)e by(cid:202) oddzielenie g(cid:239)owy od ogona kolekcji. Inne zastosowania obejmuj(cid:200) budowanie iteratorów w celu konsumowania warto(cid:258)ci utworzonych przez obiekt wywo(cid:239)ywalny (na przyk(cid:239)ad funkcj(cid:218)) a(cid:285) do znalezienia warto(cid:258)ci stra(cid:285)nika. T(cid:218) funkcj(cid:218) czasami wykorzystuje si(cid:218) razem z funkcj(cid:200) read() obiektu file w celu konsumowania elementów tak d(cid:239)ugo, dopóki nie zostanie znaleziona warto(cid:258)(cid:202) znaku ko(cid:241)ca linii lub znaku ko(cid:241)ca pliku. Wyra(cid:285)enie takie jak iter(file.read, \ n ) b(cid:218)dzie ocenia(cid:202) warto(cid:258)(cid:202) przekazanej funkcji, dopóki nie zostanie znaleziona warto(cid:258)(cid:202) stra(cid:285)nika \ n . Z tej w(cid:239)asno(cid:258)ci nale(cid:285)y korzysta(cid:202) ostro(cid:285)nie: je(cid:258)li stra(cid:285)nik nie zostanie znaleziony, konstrukcja mo(cid:285)e bez ko(cid:241)ca próbowa(cid:202) czy- ta(cid:202) ci(cid:200)gi o zerowej d(cid:239)ugo(cid:258)ci. Dostarczenie wywo(cid:239)ywalnej funkcji do metody iter() mo(cid:285)e by(cid:202) do(cid:258)(cid:202) trudne, poniewa(cid:285) funkcja, któr(cid:200) dostarczamy, musi wewn(cid:218)trznie utrzymywa(cid:202) pewien stan. W programowaniu funkcyjnym jest to na ogó(cid:239) niepo(cid:285)(cid:200)dane. Ukryty stan jest jednak cech(cid:200) otwartego pliku. Na przyk(cid:239)ad ka(cid:285)de wywo(cid:239)anie funkcji read() lub readline() przesuwa wewn(cid:218)trzny stan do nast(cid:218)pnego znaku lub nast(cid:218)pnego wiersza. Innym przyk(cid:239)adem jawnej iteracji jest sposób, w jaki metoda pop() mutowalnego obiektu kolekcji dokonuje stanowej zmiany w obiekcie kolekcji. Oto przyk(cid:239)ad u(cid:285)ycia metody pop(): 109 Poleć książkęKup książkę Python. Programowanie funkcyjne tail = iter([1, 2, 3, None, 4, 5, 6].pop, None) list(tail) [6, 5, 4] Zmienn(cid:200) tail ustawiono na iterator po li(cid:258)cie [1, 2, 3, None, 4, 5, 6], która b(cid:218)dzie przegl(cid:200)dana przez funkcj(cid:218) pop(). Domy(cid:258)lnym zachowaniem metody pop() jest pop(-1), czyli elementy s(cid:200) pobierane w odwrotnej kolejno(cid:258)ci. To powoduje zmian(cid:218) stanu obiektu listy: za ka(cid:285)dym razem, gdy zostanie wywo(cid:239)ana funkcja pop(), z listy zostanie usuni(cid:218)ty element — co j(cid:200) zmieni. Po znale- zieniu warto(cid:258)ci stra(cid:285)nika iterator zatrzymuje zwracanie warto(cid:258)ci. Je(cid:258)li go nie znajdzie, nast(cid:218)puje zg(cid:239)oszenie wyj(cid:200)tku IndexError. Tego rodzaju wewn(cid:218)trzne zarz(cid:200)dzanie stanem jest czym(cid:258), czego chcieliby(cid:258)my unikn(cid:200)(cid:202). W zwi(cid:200)zku z tym nie b(cid:218)dziemy nalegali na korzystanie z tej funkcji. Wykorzystanie funkcji sorted() do porz(cid:200)dkowania danych Kiedy trzeba generowa(cid:202) wyniki w zdefiniowanym porz(cid:200)dku, Python daje nam dwie mo(cid:285)liwo(cid:258)ci. Mo(cid:285)emy stworzy(cid:202) obiekt listy i u(cid:285)y(cid:202) metody list.sort() w celu zwrócenia elementów w odpowiednim porz(cid:200)dku. Alternatyw(cid:200) jest u(cid:285)ycie funkcji sorted(). Ta funkcja dzia(cid:239)a z ka(cid:285)dym obiektem iterowalnym, ale w ramach operacji sortowania tworzy ko(cid:241)cowy obiekt listy. Z funkcji sorted() mo(cid:285)na korzysta(cid:202) na dwa sposoby. Mo(cid:285)na j(cid:200) po prostu zastosowa(cid:202) do kolekcji. Mo(cid:285)na jej tak(cid:285)e u(cid:285)y(cid:202) jako funkcji wy(cid:285)szego rz(cid:218)du za pomoc(cid:200) argumentu key=. Za(cid:239)ó(cid:285)my, (cid:285)e mamy dane podró(cid:285)y z przyk(cid:239)adów w rozdziale 4. „Praca z kolekcjami”. Mamy funk- cj(cid:218), która generuje sekwencj(cid:218) krotek zawieraj(cid:200)cych dane pocz(cid:200)tku, ko(cid:241)ca i odleg(cid:239)o(cid:258)ci ka(cid:285)dego odcinka podró(cid:285)y. Dane maj(cid:200) nast(cid:218)puj(cid:200)c(cid:200) posta(cid:202): ( ((37.54901619777347, -76.33029518659048), (37.840832, -76.273834), 17.7246), ((37.840832, -76.273834), (38.331501, -76.459503), 30.7382), ((38.331501, -76.459503), (38.845501, -76.537331), 31.0756), ((36.843334, -76.298668), (37.549, -76.331169), 42.3962), ((37.549, -76.331169), (38.330166, -76.458504), 47.2866), ((38.330166, -76.458504), (38.976334, -76.473503), 38.8019) ) Domy(cid:258)lne zachowanie funkcji sorted() mo(cid:285)na zaobserwowa(cid:202) w nast(cid:218)puj(cid:200)cej interaktywnej sesji: sorted(dist(x) for x in trip) [0.1731, 0.1898, 1.4235, 4.3155, ... 86.2095, 115.1751, 129.7748] U(cid:285)yli(cid:258)my wyra(cid:285)enia generatorowego (dist(x) for x in trip), aby wyodr(cid:218)bni(cid:202) odleg(cid:239)o(cid:258)ci z da- nych podró(cid:285)y. Nast(cid:218)pnie posortowali(cid:258)my t(cid:218) iterowaln(cid:200) kolekcj(cid:218) liczb, aby uzyska(cid:202) odleg(cid:239)o(cid:258)ci od 0,17 mili morskiej do 129,77 mili morskiej. 110 Poleć książkęKup książkę Rozdzia(cid:225) 5. • Funkcje wy(cid:298)szego rz(cid:266)du Je(cid:258)li chcemy zachowa(cid:202) odcinki i odleg(cid:239)o(cid:258)ci w ich oryginalnych trójelementowych krotkach, mo(cid:285)emy zastosowa(cid:202) do funkcji sorted() funkcj(cid:218) key(), która okre(cid:258)la sposób sortowania krotek, jak pokazano w poni(cid:285)szym fragmencie kodu: sorted(trip, key=dist) [ ((35.505665, -76.653664), (35.508335, -76.654999), 0.1731), ((35.028175, -76.682495), (35.031334, -76.682663), 0.1898), ((27.154167, -80.195663), (29.195168, -81.002998), 129.7748) ] Korzystaj(cid:200)c z wyra(cid:285)enia distlambda, aby wyodr(cid:218)bni(cid:202) odleg(cid:239)o(cid:258)(cid:202) z ka(cid:285)dej krotki, posortowali(cid:258)my dane podró(cid:285)y. Funkcja dist jest zdefiniowana nast(cid:218)puj(cid:200)co: dist = lambda leg: leg[2] To pokazuje mo(cid:285)liwo(cid:258)(cid:202) u(cid:285)ycia prostego wyra(cid:285)enia lambda w celu roz(cid:239)o(cid:285)enia z(cid:239)o(cid:285)onej krotki na jej elementy sk(cid:239)adowe. Pisanie funkcji wy(cid:285)szego rz(cid:218)du Mo(cid:285)emy zidentyfikowa(cid:202) trzy odmiany funkcji wy(cid:285)szego rz(cid:218)du. Oto one: (cid:81) Funkcje, które pobieraj(cid:200) funkcj(cid:218) jako jeden z argumentów. (cid:81) Funkcje, które zwracaj(cid:200) funkcj(cid:218). Popularnym przyk(cid:239)adem tego rodzaju funkcji wy(cid:285)szego rz(cid:218)du s(cid:200) obiekty klasy Callable. Funkcja, która zwraca wyra(cid:285)enie generatorowe, mo(cid:285)e by(cid:202) uwa(cid:285)ana za funkcj(cid:218) wy(cid:285)szego rz(cid:218)du. (cid:81) Funkcje, które pobieraj(cid:200) funkcj(cid:218) jako argument i zwracaj(cid:200) inn(cid:200) funkcj(cid:218). Cz(cid:218)stym tego przyk(cid:239)adem jest funkcja functools.partial(). Omówienie tego tematu od(cid:239)o(cid:285)ymy do rozdzia(cid:239)u 10. „Modu(cid:239) functools”. Drugim przyk(cid:239)adem jest dekorator. Opiszemy go w rozdziale 11. „Techniki projektowania dekoratorów”. Rozszerzymy te proste wzorce, u(cid:285)ywaj(cid:200)c funkcji wy(cid:285)szego rz(cid:218)du, aby jednocze(cid:258)nie przekszta(cid:239)- ca(cid:202) struktur(cid:218) danych. Mo(cid:285)emy wykona(cid:202) kilka typowych przekszta(cid:239)ce(cid:241), na przyk(cid:239)ad: (cid:81) opakowanie obiektów w celu tworzenia bardziej z(cid:239)o(cid:285)onych obiektów; (cid:81) rozpakowywanie z(cid:239)o(cid:285)onych obiektów na komponenty; (cid:81) sp(cid:239)aszczanie struktury; (cid:81) nadawanie struktury p(cid:239)askiej sekwencji. Powszechnie wykorzystywanym przyk(cid:239)adem funkcji zwracaj(cid:200)cej obiekt wywo(cid:239)ywalny jest eg- zemplarz klasy Callable. Przyjrzymy si(cid:218) mu jako sposobowi pisania elastycznych funkcji, do których mo(cid:285)na wstrzykiwa(cid:202) parametry konfiguracyjne. W tym rozdziale zaprezentujemy równie(cid:285) proste dekoratory. Dok(cid:239)adniejszy opis dekoratorów od(cid:239)o(cid:285)ymy do rozdzia(cid:239)u 11. „Techniki projektowania dekoratorów”. 111 Poleć książkęKup książkę Python. Programowanie funkcyjne Pisanie mapowa(cid:241) i filtrów wy(cid:285)szego rz(cid:218)du Dwie wbudowane funkcje wy(cid:285)szego rz(cid:218)du w Pythonie — map() i filter() — ogólnie rzecz bior(cid:200)c, obs(cid:239)uguj(cid:200) prawie wszystkie obiekty, które do nich przeka(cid:285)emy. Trudno zoptymalizowa(cid:202) je w ogólny sposób, aby osi(cid:200)gn(cid:200)(cid:202) wy(cid:285)sz(cid:200) wydajno(cid:258)(cid:202). Funkcjom Pythona 3.4, takim jak imap(), ifilter() oraz ifilterfalse(), przyjrzymy si(cid:218) w rozdziale 8. „Modu(cid:239) itertools”. Istniej(cid:200) trzy w du(cid:285)ym stopniu równowa(cid:285)ne sposoby wyra(cid:285)ania mapowania. Za(cid:239)ó(cid:285)my, (cid:285)e mamy jak(cid:200)(cid:258) funkcj(cid:218) f(x) i pewn(cid:200) kolekcj(cid:218) obiektów C. Mamy trzy ca(cid:239)kowicie równowa(cid:285)ne sposoby wyra(cid:285)enia mapowania. Oto one: (cid:81) Funkcja map(): map(f, C) (cid:81) Wyra(cid:285)enie generatorowe: (f(x) for x in C) (cid:81) Funkcja generatorowa z instrukcj(cid:200) yield: def mymap(f, C): for x in C: yield f(x) mymap(f, C) Podobnie istniej(cid:200) trzy sposoby zastosowania funkcji filter do kolekcji. Wszystkie s(cid:200) równowa(cid:285)ne: (cid:81) Funkcja filter(): (cid:81) filter(f, C) (cid:81) Wyra(cid:285)enie generatorowe: (cid:81) (x for x in C if f(x)) (cid:81) Funkcja generatorowa z instrukcj(cid:200) yield: def myfilter(f, C): for x in C: if f(x): yield x myfilter(f, C) Wyst(cid:218)puj(cid:200) pewne ró(cid:285)nice w wydajno(cid:258)ci. Cz(cid:218)sto zastosowanie funkcji map() i filter() jest rozwi(cid:200)zaniem najszybszym. Co wa(cid:285)niejsze, istniej(cid:200) ró(cid:285)ne rodzaje rozszerze(cid:241), które pasuj(cid:200) do tych projektów mapowania i filtrowania. Oto one: (cid:81) Mo(cid:285)emy stworzy(cid:202) bardziej zaawansowan(cid:200) funkcj(cid:218) g(x), która b(cid:218)dzie zastosowana do ka(cid:285)dego elementu, lub mo(cid:285)emy zastosowa(cid:202) funkcj(cid:218) do ca(cid:239)ej kolekcji przed przetwarzaniem. Jest to najbardziej ogólne podej(cid:258)cie i dotyczy wszystkich trzech projektów. W tym rozwi(cid:200)zaniu zainwestujemy wi(cid:218)kszo(cid:258)(cid:202) naszej energii projektowej w programowanie funkcyjne. (cid:81) Mo(cid:285)emy dostosowa(cid:202) p(cid:218)tl(cid:218) for wewn(cid:200)trz wyra(cid:285)enia generatorowego lub funkcji generatorowej. Jedn(cid:200) z oczywistych poprawek jest po(cid:239)(cid:200)czenie mapowania i filtrowania w jedn(cid:200) operacj(cid:218) poprzez rozszerzenie wyra(cid:285)enia generatorowego 112 Poleć książkęKup książkę Rozdzia(cid:225) 5. • Funkcje wy(cid:298)szego rz(cid:266)du za pomoc(cid:200) klauzuli if. Mo(cid:285)emy równie(cid:285) po(cid:239)(cid:200)czy(cid:202) funkcje mymap() i myfilter(), aby po(cid:239)(cid:200)czy(cid:202) mapowanie z filtrowaniem. Gdy oprogramowanie ewoluuje i dojrzewa, na ogó(cid:239) zachodz(cid:200) w nim g(cid:239)(cid:218)bokie zmiany, które cz(cid:218)sto przekszta(cid:239)caj(cid:200) struktur(cid:218) danych przetwarzanych przez p(cid:218)tl(cid:218). Istnieje wiele wzorców pro- jektowych, w tym opakowywanie, rozpakowywanie (lub wyodr(cid:218)bnianie), sp(cid:239)aszczanie i nadawa- nie struktury. Kilku z tych technik przyjrzeli(cid:258)my si(cid:218) w poprzednich rozdzia(cid:239)ach. Podczas projektowania mapowa(cid:241), które (cid:239)(cid:200)cz(cid:200) zbyt wiele transformacji w jednej funkcji, trzeba zachowa(cid:202) ostro(cid:285)no(cid:258)(cid:202). O ile to mo(cid:285)liwe, nale(cid:285)y unika(cid:202) tworzenia funkcji, które nie s(cid:200) zwi(cid:218)- z(cid:239)e lub nie wyra(cid:285)aj(cid:200) pojedynczej koncepcji. Poniewa(cid:285) Python nie ma kompilatora optymaliza- cyjnego, mo(cid:285)emy by(cid:202) zmuszeni do r(cid:218)cznej optymalizacji wolno dzia(cid:239)aj(cid:200)cych aplikacji po- przez (cid:239)(cid:200)czenie funkcji. Tego rodzaju optymalizacje powinny by(cid:202) wykonywane w ostateczno(cid:258)ci, dopiero po sprofilowaniu wolno dzia(cid:239)aj(cid:200)cego programu. Rozpakowywanie danych podczas mapowania Gdy u(cid:285)ywamy takiej konstrukcji jak (f(x) for x, y in C), pos(cid:239)ugujemy si(cid:218) wieloma podstawie- niami w instrukcji for, tak aby rozpakowa(cid:202) wielowarto(cid:258)ciow(cid:200) krotk(cid:218), a nast(cid:218)pnie zastosowa(cid:202) funkcj(cid:218) do jej elementów. Ca(cid:239)e wyra(cid:285)enie jest mapowaniem. Jest to typowa optymalizacja Pythona wykonywana w celu zmiany struktury i zastosowania funkcji. Do zaprezentowania tego mechanizmu wykorzystamy dane dotycz(cid:200)ce podró(cid:285)y z rozdzia(cid:239)u 4. „Praca z kolekcjami”. Oto konkretny przyk(cid:239)ad rozpakowywania podczas mapowania: from typing import Callable, Iterable, Tuple, Iterator, Any Conv_F = Callable[[float], float] Leg = Tuple[Any, Any, float] def convert( conversion: Conv_F, trip: Iterable[Leg]) - Iterator[float]: return ( conversion(distance) for start, end, distance in trip ) Ta funkcja wy(cid:285)szego rz(cid:218)du b(cid:218)dzie obs(cid:239)ugiwana przez funkcje konwersji, które mo(cid:285)na zastosowa(cid:202) do surowych danych w nast(cid:218)puj(cid:200)cy sposób: to_miles = lambda nm: nm*5280/60
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Python. Programowanie funkcyjne
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: