CCIE.pl

site 4 CCIE wannabies
Dzisiaj jest 19 paź 2017, 05:36

Strefa czasowa UTC+02:00




Nowy temat  Odpowiedz w temacie  [ Posty: 8 ] 
Autor Wiadomość
Post #1 : 08 mar 2017, 14:00 
Offline
wannabe
wannabe

Rejestracja: 18 kwie 2016, 21:04
Posty: 70
Lokalizacja: CCIE
Czesc tak sobie pomyslalem ze podziele sie jak functional programming moze ulatwic prace ze strukturami danych

Na poczatku jedno zdanie czym jest functional programming. To podejscie do programowania i pisania kodu ktory w zasadzie
nie powinien modyfikowac danych wejsciowych (pure functions), byc odporny na bugi, zapobiegac DRY(Don't repeat yourself)
i byc jak najkrotszy.

Kilka przykladow:

zakladamy ze mamy prosta strukture danych jak ponizej, gdzie interfaces to tablica/lista zawierajaca slowniki
gdzie kazdy slownik odpowiada wartoscia(danym) z danego interfejsu
Kod:
 interfaces = [{"type":"GitabitEthernet", "status":"up", "rx":2000, "tx":3000, "id":1},
		    {"type":"GigabitEthernet", "status":"up", "rx":2100, "tx":3309, "id":2},
		    {"type":"GigabitEthernet", "status":"down", "rx":200, "tx":5000, "id":3},
		    {"type":"GigabitEthernet", "status":"up", "rx":1000, "tx":2000, "id":4}]
Zadanie nr 1.

Zwrocic interfejsy ktore sa w stanie up.

Mozna to zrobic na dwa trzy sposoby.

a) Tradycyjny: petla for sprawdzenie warunku i wrzuceniu do nowej listy
interfejsy spelniajace warunek.
Kod:
>>> def traditionalFunc(status,interfaces):
...     statusInterfaces = []
...     for x in interfaces:
...             if x.get('status') == status:
...                     statusInterfaces.append(x)
...     return statusInterfaces
... 
>>> traditionalFunc('up')
[{'type': 'GitabitEthernet', 'id': 1, 'status': 'up', 'tx': 3000, 'rx': 2000}, {'type': 'GigabitEthernet', 'id': 2, 'status': 'up', 'tx': 3309, 'rx': 2100}, {'type': 'GigabitEthernet', 'id': 4, 'status': 'up', 'tx': 2000, 'rx': 1000}]
Ble.. ile kodu!! na prosta operacje, zobaczmy jak poradzi sobie list comprehension


b) List comprehension
Kod:
>>> def comprehensionFunc(status,interfaces):
...     return  [x for x in interfaces if x.get('status') == status]
... 
>>> 
>>> comprehensionFunc('up',interfaces)
[{'type': 'GitabitEthernet', 'id': 1, 'status': 'up', 'tx': 3000, 'rx': 2000}, {'type': 'GigabitEthernet', 'id': 2, 'status': 'up', 'tx': 3309, 'rx': 2100}, {'type': 'GigabitEthernet', 'id': 4, 'status': 'up', 'tx': 2000, 'rx': 1000}]
>>> 
Znacznie lepiej prawda :) No ale to jeszcze nie jest to co bysmy chcieli. Zobaczmy jak mozna to zrobic metoda filter

c) Metoda filter
Kod:
>>> interfacesStatus = list(filter(lambda x: x.get('status')=='up', interfaces))
>>> 
>>> interfacesStatus
[{'type': 'GitabitEthernet', 'id': 1, 'status': 'up', 'tx': 3000, 'rx': 2000}, {'type': 'GigabitEthernet', 'id': 2, 'status': 'up', 'tx': 3309, 'rx': 2100}, {'type': 'GigabitEthernet', 'id': 4, 'status': 'up', 'tx': 2000, 'rx': 1000}]
Dobra zgodze sie metoda filter jest znacznie bardziej magiczna, ale to tylko pierwsze wrazenie. Na pewno lambda moze spowodowac ze niektorzy zwatpia
w funkcyjne programowanie ale nie taki diabel straszny jak go maluja !. Lambda to nic innego jak nie nazwana funkcja ktora moze przyjac dowolna ilosc argumentow (wszystko przed :) a nastepnie poslugujac sie tymi argumentami wykonac okreslona operacje na strukturze ktora jest drugim argumentem do funkcji filter. Sam filter zwraca nam obiekt wiec musimy zamienic to na strukturke metoda list ktora zwroci nam liste.

Kolejny przyklad mam nadzieje pokaze wiecej prawdziwej mocy drzemiacej w programowaniu funkcyjnym.

Zadanie 2.

Zwrocic sume wszystkich RX :) Jako zadanko mozna sprobwoac metody tradycyjnej i list comprehension, ja natomiast chce pokazac jak zrobic to za pomoca pure funkcji
o nazwie map + sum.
Kod:
>>> rxSum = sum(list(map(lambda x: x.get('rx'), interfaces)))
>>> rxSum
5300
Sweet, jedna linia kodu a jaka operacja :)

Teraz.. nikt nei zabroni nam laczyc metod do bardziej wymyslonych warunkow. Zrobmy teraz tak, dodajmy tylko TX interfejsow ktore sa w stanie UP, nie inetresuja nas interfejsy ktore sa down tym razem
Kod:
>>> txSum = sum(list(map(lambda x: x.get('status') == 'up' and x.get('tx'), interfaces)))
>>>  
>>> txSum
8309
Bam ! jedna linia kodu !! Mam nadzieje ze zacheci to was do chociaz przemyslenia programowania funkcyjnego jako metody pracy ze strukturami. Przy dluzszym obcowaniu
i wprawie obiecuje wam ze nie bedziecie chcieli juz pisac tradycyjnych petli.

Jak ktos dokladnie chce wiedziec jak dziala list comprehension to zapraszam do mnie na bloga http://horac.pl

Pozdr


Na górę
Post #2 : 08 mar 2017, 15:05 
Offline
wannabe
wannabe

Rejestracja: 27 wrz 2007, 01:13
Posty: 503
naginasz troche rzeczywistosc bo jesli chcesz pokazac ze mozesz uzyc onelinera (btw to nie perl gdzie sie zawody w onelinerach robilo )
to czemu poprostu nie zorbisz interfacesStatus = [x for x in interfaces if x.get('status') == "up"] tylko tworzysz funkcje ? ;)

to samo z liczeniem rx
listcomprehension
Kod:
sum([x.get('rx',0) for x in interfaces])
jest krotsze niz
Kod:
sum(list(map(lambda x: x.get('rx'), interfaces)))
pozatym twoja lambda sie wysypie jesli ktorys z interfejsow nie bedzie bedzie mial klucza rx ;) list comprehension ktory podalem bedzie dzialal (ale to juz wina braku default value w funkcji get a nie samem lambdy;)

Tak wiec moje osobiste zdanie jest takie :
list comprehension jak najbardziej ! uzywam czesto i jest super
lambda not so much (chociaz czasami sie przydaje nie powiem ale unikalbym uzywania na sile) - ze wzgledu na redability wole rozpisac na named function dodac komentarze do tego ladniej wyglada w tracebacku gdy sie cos sypnie :)


Na górę
Post #3 : 08 mar 2017, 15:19 
Offline
wannabe
wannabe

Rejestracja: 18 kwie 2016, 21:04
Posty: 70
Lokalizacja: CCIE
Funkcja jest po to żebyś sobie status wrzucił jaki cię interesuje pod argumentem. To są banalne przykłady a lambda się przydaje gdy więcej argumentów podajesz. np wyciągając dane z różnych struktur i robiąc na nich operacje. Zastosowanie nie jest do konkursów tylko, zobacz na puree funkcje JavaScript tam to dopiero się kod kroi w postaci spread array i object operatora

A po to użyłem get żeby się nie wysypało bo get obsługuje wyjątek braku klucza w słowniku z automatu

Dobrze że nie napisałem tego w Ruby bo tam to dopiero można się czepiać różnych rozwiązań(lambda vs Proc, block itp) :) chodzi tylko o to żeby ludzie nie pisali w pythonie jak w C tylko skorzystali z możliwości jakie daje język wyższego poziomu

Po za tym na sile wyrzuciles 'rx' z jednego interfejsu zeby wywolac blad na lambda. Wiadomo ze edge case'y sie obsluguje ale nie o tym ten watek ;]

A zsumowac sie da tylko trzeba dodatkowy warunek wrzucic


Ostatnio zmieniony 08 mar 2017, 16:32 przez horac, łącznie zmieniany 2 razy.

Na górę
Post #4 : 08 mar 2017, 15:28 
Offline
wannabe
wannabe

Rejestracja: 27 wrz 2007, 01:13
Posty: 503
Cytuj:
Funkcja jest po to żebyś sobie status wrzucił jaki cię interesuje pod argumentem. To są banalne przykłady a lambda się przydaje gdy więcej argumentów podajesz. np wyciągając dane z różnych struktur i robiąc na nich operacje. Zastosowanie nie jest do konkursów tylko, zobacz na puree funkcje JavaScript tam to dopiero się kod kroi w postaci spread array i object operatora

A po to użyłem get żeby się nie wysypało bo get obsługuje wyjątek braku klucza w słowniku z automatu
Aha i zwraca NoneType sproboj to zsumowac :D
Kod:
Traceback (most recent call last):
  File "test.py", line 7, in <module>
    print sum(list(map(lambda x: x.get('rx'), interfaces)))
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
Poczytaj sobie jaki stosunek do lamdy ma tworca pythona Guido
http://www.artima.com/weblogs/viewpost.jsp?thread=98196
Cytuj:
Why drop lambda? Most Python users are unfamiliar with Lisp or Scheme, so the name is confusing; also, there is a widespread misunderstanding that lambda can do things that a nested function can't -- I still recall Laura Creighton's Aha!-erlebnis after I showed her there was no difference! Even with a better name, I think having the two choices side-by-side just requires programmers to think about making a choice that's irrelevant for their program; not having the choice streamlines the thought process



Powtorze jeszcze raz z perspektywy osoby ktora na codzien pisze w pythonie i robi review kodu polecam list comprehension , ale lambdy juz nie zabardzo (nie wykluczam uzywania tylko nie polecam sie napalac na nia ) - czyta sie i debugguje znacznie gorzej. Kod jest duzo czytelniejszy przy uzyciu funkcji. Znac oczywiscie nalezy. Moj post nie jest krytyka twojego tylko polemika , brawo za to ze chcialo ci sie przedstawic powyzsze zagadnienia ale uwazam ze nei mozna byc wobec nich bezkrytycznym . Podam przyklad ktory czesto obserwoje. Sa ludzie ktorzy pisza proceduralnei od jakiegos czasu i ktoregos dnia odkrywajja OOP od tego czasu wszedzie wciskaja objekty i klasy czesto tam gdzie nei ma to najmniejszego sensu ;) Czy OOP jest zle ? oczywiscie ze nie czy nalezy nagle porzucic proderulanosc i pisac wszystko obiektowo - not so much


Na górę
Post #5 : 08 mar 2017, 16:10 
Offline
wannabe
wannabe

Rejestracja: 18 kwie 2016, 21:04
Posty: 70
Lokalizacja: CCIE
Zgodze sie z tym ze dobiera sie metody pod wymagania i dobrze ze istnieje polemika bo swiat bylby nudny , ale widze duzo zalet programowania funkcyjnego. Niezliczona ilosc bledow trudnych do wychwycenia powstaje w tradycyjnym petleniu, off-by-one to chyba taka wisienka na torcie bugow w przypadku petli. Po za tym chodzi o to zeby pisac jak najmniej kodu a zeby robil jak najwiecej. Ok problemem moze byc debugowanie pozniejsze a czytelnosc to juz raczej zalezy od doswiadczenia i preferencji.

I bezkrytyczny na pewno nie jestem, wszystkiego programowaniem funkcyjnym zastapiac sie nie da, ale do obrobki danych wejsciowych jest swietne, zwlaszcza gdy wyciagasz cos po API i dostajesz bloba z JSONem. OOP glownie do tworzenia relacji miedzy obiektami, ale tez nie czysty OOP bo ja jestem zwolennikiem komponent programowania z roznymi jego wersjami.

Na sile wyrzuciles klucz wartosc rx z interfejsow.. i pokazujesz blad na NoneType ale to sie da nadal zsumowac tylko z dodatkowym warunkiem
Cytuj:
Aha i zwraca NoneType sproboj to zsumowac :D
Kod:
>>> interfaces = [{'type': 'GitabitEthernet', 'id': 1, 'status': 'up', 'tx': 3000}, 
			{'type': 'GigabitEthernet', 'id': 2, 'status': 'up', 'tx': 3309, 'rx': 2100},
 			{'type': 'GigabitEthernet', 'id': 3, 'status': 'down', 'tx': 5000, 'rx': 200}, 
 			{'type': 'GigabitEthernet', 'id': 4, 'status': 'up', 'tx': 2000, 'rx': 1000}]

>>> sum(list(map(lambda x: x.get('rx') or x.get('rx') != None, interfaces)))
3300


Na górę
Post #6 : 08 mar 2017, 16:47 
Offline
wannabe
wannabe

Rejestracja: 27 wrz 2007, 01:13
Posty: 503
a tak nie ladniej?
Kod:
sum(list(map(lambda x: x.get('rx',0), interfaces)))

P.s uzylem zlego doboru slow z tym sproboj to zsumowac oczywisice ze sie da po modyfikacji lamdy chodizlo mi tylko o to ze Nonetype z int nie da rady ;)


Na górę
Post #7 : 08 mar 2017, 17:00 
Offline
wannabe
wannabe

Rejestracja: 18 kwie 2016, 21:04
Posty: 70
Lokalizacja: CCIE
co do NonType to jest cos co mnie w pythonie zawsze wkurza. Ze nigdy nie wiadomo co ci wypluje badz zwroci. Troche to jest wk w nietypowanych jezykach wlasnie.
W C dostajesz konkretnego typu dane na wejsciu, masz funkcje ktora zwraca pointer na int, to to ma zwrocic i nie ma zmiluj. W pythonie, zwlaszcza np w takim PyQt
gdzie bind jest zrobiony do C++ mozna spedzic godziny na debugowaniu;]


Na górę
Post #8 : 08 mar 2017, 17:06 
Offline
wannabe
wannabe

Rejestracja: 27 wrz 2007, 01:13
Posty: 503
ja dlatego czesto obchodze to uzywajac default value (oczywisicie nie zawsze sie da ) chociaz i tak powinnismy sie cieszyc ze NoneType ma boola False ;)


Na górę
Wyświetl posty nie starsze niż:  Sortuj wg  
Nowy temat  Odpowiedz w temacie  [ Posty: 8 ] 

Strefa czasowa UTC+02:00


Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 1 gość


Nie możesz tworzyć nowych tematów
Nie możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz dodawać załączników

Szukaj:
Przejdź do:  
cron
This Website is not sponsored by, endorsed by or affiliated with Cisco Systems, Inc. Cisco, Cisco Systems, CCDA, CCNA, CCDP, CCNP, CCIE, CCSI, CCIP, the Cisco Systems logo and the CCIE logo are trademarks or registered trademarks of Cisco Systems, Inc. in the United States and certain other countries. Używamy informacji zapisanych za pomocą cookies i podobnych technologii m.in. w celach reklamowych i statystycznych oraz w celu dostosowania naszych serwisów do indywidualnych potrzeb użytkowników. Mogą też stosować je współpracujące z nami firmy. W programie służącym do obsługi internetu można zmienić ustawienia dotyczące cookies. Korzystanie z naszych serwisów internetowych bez zmiany ustawień dotyczących cookies oznacza, że będą one zapisane w pamięci urządzenia.



Technologię dostarcza phpBB® Forum Software © phpBB Limited
Polski pakiet językowy dostarcza phpBB.pl