CCIE.pl

site 4 CCIE wannabies
It is currently 24 Apr 2017, 19:04

All times are UTC+02:00




Post new topic  Reply to topic  [ 8 posts ] 
Author Message
Post #1 Posted: 08 Mar 2017, 14:00 
Offline
wannabe
wannabe

Joined: 18 Apr 2016, 21:04
Posts: 51
Location: 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

Code:
 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.

Code:
>>> 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

Code:
>>> 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

Code:
>>> 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.

Code:
>>> 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

Code:
>>> 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


Top
   
Post #2 Posted: 08 Mar 2017, 15:05 
Offline
wannabe
wannabe

Joined: 27 Sep 2007, 01:13
Posts: 404
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
Code:
sum([x.get('rx',0) for x in interfaces])

jest krotsze niz
Code:
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 :)


Top
   
Post #3 Posted: 08 Mar 2017, 15:19 
Offline
wannabe
wannabe

Joined: 18 Apr 2016, 21:04
Posts: 51
Location: 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


Last edited by horac on 08 Mar 2017, 16:32, edited 2 times in total.

Top
   
Post #4 Posted: 08 Mar 2017, 15:28 
Offline
wannabe
wannabe

Joined: 27 Sep 2007, 01:13
Posts: 404
horac wrote:
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
Code:
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
Quote:
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


Top
   
Post #5 Posted: 08 Mar 2017, 16:10 
Offline
wannabe
wannabe

Joined: 18 Apr 2016, 21:04
Posts: 51
Location: 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

freel4ncer wrote:
Aha i zwraca NoneType sproboj to zsumowac :D


Code:
>>> 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


Top
   
Post #6 Posted: 08 Mar 2017, 16:47 
Offline
wannabe
wannabe

Joined: 27 Sep 2007, 01:13
Posts: 404
a tak nie ladniej?

Code:
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 ;)


Top
   
Post #7 Posted: 08 Mar 2017, 17:00 
Offline
wannabe
wannabe

Joined: 18 Apr 2016, 21:04
Posts: 51
Location: 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;]


Top
   
Post #8 Posted: 08 Mar 2017, 17:06 
Offline
wannabe
wannabe

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


Top
   
Display posts from previous:  Sort by  
Post new topic  Reply to topic  [ 8 posts ] 

All times are UTC+02:00


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
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.



Powered by phpBB® Forum Software © phpBB Limited