czyli nie tylko obiektowość rządzi 1 z 40
O czym będę mówił... Jak najmniej teorii bo nie czas i miejsce... Próba odpowiedzi na pythanie: Czy warto programować nie tylko obiektowo? Jak język Python wspiera programowanie funkcyjne? Jak się w to zanurzyć :) Ogólnie... Będzie nieformalnie i subiektywnie... Bez świętych wojen... Nie skupiam się na problemie polskowatość kontra angielskość Nie mam ambicji by wyczerpać temat w tak krótkim czasie 2 z 40
Programowanie... jakie? Paradygmaty programowania:... Imperatywne jawny ciąg czynności do wykonania Obiektowe program realizowany poprzez komunikację pomiędzy samodzielnymi obiektami Funkcyjne operacje na funkcjach nie posiadających stanu czyli czysta matematyka :) Subiektywnie: jeśli język programowania wspiera wiele paradygmatów programowania (a tak jest z językiem Python), to jeden z nich jest jego rdzeniem, w konsekwencji inne są wspierające. 3 z 40
Programowanie funkcyjne czego się spodziewać Powszechnie jest stosowana rekurencja zamiast pętli Brak efektów ubocznych (brak globalnego stanu, języki czysto funkcyjne) Leniwe wartościowanie Funkcje to podstawowe pojęcia (ang. first-class ) Funkcje mogą operować na funkcjach (ang. high-order ) Listy są podstawową strukturą danych Inne pojęcie czasu... (gr. panta rhei )
Profit i niebezpieczeństwo... Co daje w praktyce programowanie funkcyjne? Z racji bezstanowości - łatwiejsze odpluskwianie :) Z racji automatycznych interatorów - krótszy kod = szybciej powstanie program Z racji innego pojęcia czasu brak problemów z wielowątkowością (no, to w Pythonie to jeszcze za chwilę) Zadowolenie :-) (wreszcie naprawdę ładne algorytmy) Niebezpieczeństwa: Jedna z zawodowych alergii: Dla niektórych (programistów) rekurencja jest zabójcza :-) Lubię to co znam: Programowanie funkcyjne jest inne... Mam ulubione zabawki: Stosowanie młotka do usypiania dzieci (bo obsługę młotka znam!)
W jakim stopniu język Python wspiera programowanie funkcyjne? Python probably has the reputation of supporting functional programming based on the inclusion of lambda, map, filter, and reduce in the language, but in my eyes these are just syntactic sugar, and not the fundamental building blocks that they are in functional languages. Guido van Rossum Masterminds of Programming
Funkcyjność i pochodne w skrzynce narzędziowej... Lambda funkcje nienazwane Domknięcia (ang. closure ) Dekoratory Generatory w listach (ang. list comprehensions ) Generatory samodzielne w terminologii funkcyjnej strumienie Funkcje map, filter, reduce, any, all, apply Moduły functools, operator, itertools 7 z 40
Instrukcja obsługi narzędzi w skrzynce... Jeśli ktoś coś wie i umie... to przepraszam i pomidorem proszę nie rzucać :)
Lambda Funkcja nienazwana W ciele funkcji lambda nie można stosować rozgałęzień ani pętli Dozwolone jest użycie wyrażeń warunkowych Brak instrukcji return lub yield W praktyce często stosowane wartościowanie wynikające z działania or oraz and
Lambda przykład (1 z 2) Funkcja tradycyjna : import math def myhypot(dx, dy): return math.hypot(dx,dy) Reprezentacja w postaci lambda: myhypot = lambda dx, dy: math.hypot(dx, dy)
Lambda przykład (2 z 2) Zastosowanie instrukcji warunkowej: wprzedziale = lambda x: tak if x > 12 \ and x < 21 else nie Uwaga: Sekcja else jest w tym przypadku obowiązkowa. Czasem nie da się inaczej niż... substancja = lambda x : ( x == mokre ) \ and woda or ( x == suche ) and piasek
Domknięcie (ang. closure ) W OOP dostępny podobny wzorzec command pattern Funkcja z pamięcią stanu lub inaczej dołączonym środowiskiem : def mylogger(id): def completemessage(message): return id + : + message return completemessage myloggerinstance = mylogger( SantaClaus ) print myloggerinstance = myloggerinstance( Ho ho ho ) print myloggerinstance = myloggerinstance( Is dead... )
Dekorator najprościej... Działanie identyczne z OOP dekorator... Jest to jedno z możliwych zastosowań domknięcia w języku Python Dekorator (w języku Python), to idiom funkcji która jako argument/y przyjmuje inną funkcję def callargs(func): def funcargs(*arg, **karg): print arg, karg return func(*arg, **karg) return funcargs @callargs def mysum(x,y): return x + y
Dekorator przykładowe zastosowanie Przykład zastosowania dekoratora powtórzenie wywołania (tu mocno uproszczony) def repeatof(n): def decofunction(func): def functionrepeat(*args, **kwargs): counter = n while counter > 1: func(*args, **kwargs) counter -= 1 return func(*args, **kwargs) return functionretry return decofunction
Generator w liście Tworzenie listy z użyciem składni z języka Haskell :) dane = [ 2**x for x in range(10) if not ( x % 2) ] A skomplikowane struktury także... [ [ i*j for j in range(1, 10) ] for i in range(1,10) ] [ (x, y) for x in (1, 2, 3, 5) for y in (10, 13, 41) if y // x > 3 ]
Generator samodzielny (1 z 2) Stosowany do leniwego wartościowania Często wykorzystywany przy okazji pętli for myvalues = (x**2 for x in range(10)) for i in myvalues: print i
Generator samodzielny (2 z 2) Dzięki instrukcji yield, generator umożliwia zaimplementowanie pamięci stanu # fibonacci a dlaczego nie :) # def fibonacci(n): x0, x1 = 1,1 for i in range(n) yield x0 x0, x1 = x1, x0 + x1 for i in fibonacci(4): print i
Instrukcje wspierające funkcyjność (1 z 2) Funkcje operujące na listach: (tu przykłady z lambda bo.. krócej) map zastosowanie funkcji dla każdego elementu map(lambda x: x**2, range(1,5)) filter wybieranie elementów które spełniają predykat filter(lambda x: x%3 == 0, range(20)) reduce redukcja elementów kolekcji reduce(lambda x, y: x*y, [23, 44, 55, 61])
Instrukcje wspierające funkcyjność (2 z 2) Przydatne i proste... all zwraca prawdę jeśli wszystkie elementy kolekcji (iterowanej) mają wartość True any zwraca prawdę jeśli jakikolwiek element kolekcji (iterowanej) ma wartość True apply umożliwia wywołanie funkcji z argumentami (uwaga: oznaczona jako przestarzała) apply(mycalc[, args [, kwargs]])
Jeśli jeden slajd to ten :-) Skrócona instrukcja funkcyjności w języku Python: Zamiast if/elif/else, stosowanie or i and Zamiast for, stosowanie map Zamiast while, stosowanie postaci: wynik1 if warunek else wynik2 Zamiast wybierania elementów z kolekcji, filter Obliczenia na elementach kolekcji (nie wszystkie), reduce Dodatkowo moduły functools, operator, itertools
if/elif elif/elseelse i and oraz or # tradycyjne... def checkx(x): if x > 0 and x < 2501: return ok elif x > 2500 and x < 5000: return red else: return error # z użyciem or i and checkx = lambda x: \ (x > 0 and x < 2501 and ok ) \ or (x > 2500 and x < 500 and red ) \ or error Uwaga: W przykładzie wartości zwracane nie mogą być równe False. Jeśli są to zamieniaj or and i and or :)
for oraz map # tradycyjnie def mycalc(): l = [] for i in (2, 5, 19, 44): l.append( (2**i)//2) return l # i z użyciem map mycalc = map(lambda x: (2**x) // 2, (2, 5, 19, 44) )
while i postać funkcyjna czyli rekurencyjna # tradycyjnie x = 27 while x > 0: print x if x > 30: break else: x -= 1 # postać funkcyjna x = 27 def wblock(): global x print x x -= 1 return False if x > 31 else True wfp = lambda: ( x > 0 and \ wblock()) and wfp() wfp() # No racja, w praktyce # wybrał bym implementację # tradycyjną :)
Zamiast sprawdzania w pętli, filter # tradycyjnie def czypierwsza(n): d = 2 while 2 < ( n // 2): if n % d == 0: return False d += 1 return True # z użyciem filter i any czypierwsza = lambda n: \ any( filter( lambda d: n % d == 0, range( 2, n // 2 ) ) ) == False # lub z użyciem generatorowej # postaci listy czypierwsza = lambda n: \ True not in [ n % d == 0 for d \ in range(2, n // 2 ) ]
Pakiet operator Jeśli operacja wykonywana w miejsce funkcji lambda jest prosta, stosuj funkcje z pakietu operator. Funkcje z tego pakietu ułatwiają programowanie funkcyjne suma = map( lambda x: x + 2, range(10) ) # równoważne suma = [ x+2 for x in range(10) ] # równoważne import operator suma = map( operator.add(x, 2), range(10) )
Pakiet itertools Pokrótce:... Iteratory cykliczne (generują nieskończony ciąg) Zwracające kombinacje z podanej kolekcji iterowanej Zliczające ilość wystąpień Filtrujące dane wg warunków Zwracające permutacje Opakowanie kolekcji do iteracji
Pakiet functools Pokrótce: Uzupełnianie funkcji o argumenty Ulepszanie dekoratora Redukcja danych
Co jeszcze? Pakiet functional który jest dostępny poprzez PyPi. Wspiera wiele koncepcji programowania funkcyjnego. Jest dobrze przemyślanym kodem. Ważne... ciągle żywy projekt :-)
Jak się w to zanurzyć... Metodą gotowania żaby? :-) Python ma elementy programowania funkcyjnego i nie rości sobie pretensji to czystej funkcyjności. Jeśli nawet nie będziesz programował funkcyjnie, poznasz zaawansowane mechanizmy języka :-) Coż, jeśli spodoba Ci się programowanie funkcyjne to... Lisp, Scheme, Ocaml czeka :-)
W podsumowaniu Warto mieć w skrzynce narzędziowej również programowanie funkcyjne Warto wiedzieć jakie ma zalety i jakie wady (dla Ciebie) Zdrowa zasada (moja i nie twierdzę że u Ciebie zadziała): Nie rozumiem nie wybieram Nie rozumiem nie twierdzę że złe :-) Rozumiem nie zachłystuję się Rozumiem co oznacza że wiem gdzie nie działa :-)
Dziękuję za twoją uwagę! Jeśli masz pytania: Co do treści i tematu prezentacji, Tematów następnych spotkań, Sugestie co do zaproszonych gości, Wszelkie uwagi... To jest dobry moment :) tomasz.jasiukiewicz@osec.pl