.. _Trzy_style: Programowanie funkcyjne a obiektowe ==================================================================== W tej części omówiono programowanie funkcyjne. Na zakończenie warto porównać ten paradygmat programowania. do przedstawionego w poprzedniej części programowania obiektowego. W tym celu posłużymy się zadaniem, którego celem jest znalezienie wyrazów, które najczęściej występują w książce J.R.R. Tolkiena *„Władca Pierścieni”* tom I, dostęnej jako plik tekstowy. Problem -------- Dany jest plik tekstowy ``lotr1-utf8.txt``. Należy: - odczytać tekst - podzielić go na słowa - oczyścić ze znaków interpunkcyjnych - zamienić na małe litery - odfiltrować krótkie słowa - policzyć częstość występowania - wypisać 30 najczęstszych Styl deklaratywny ------------------------------- Najbardziej bezpośrednie rozwiązanie polega na napisaniu kodu krok po kroku: .. literalinclude:: declarative.py :language: python :linenos: **Charakterystyka** - jawne pętle ``for`` - ręczne zarządzanie strukturami danych (słownik) - instrukcje warunkowe i zmiana stanu - kolejność operacji dokładnie określona **Zalety** - prostota i czytelność dla początkujących - pełna kontrola nad wykonaniem - łatwe debugowanie krok po kroku **Wady** - trudniej wydzielić logiczne etapy przetwarzania - kod mniej modularny Styl obiektowy -------------- W podejściu obiektowym organizujemy kod wokół obiektu, który przechowuje stan i udostępnia operacje: .. literalinclude:: object.py :language: python :linenos: **Charakterystyka** - dane (słownik) są ukryte wewnątrz klasy - operacje są metodami obiektu - enkapsulacja (prywatne pole ``__counts``) - interfejs: ``add()``, ``words_sorted()`` **Zalety** - dobra organizacja kodu - enkapsulacja danych - możliwość rozszerzania (np. inne metody analizy) **Wady** - dużo więcej kodu do napisania - operacje są „rozproszone” po metodach - trudniej zobaczyć cały przepływ danych Styl funkcyjny -------------- W podejściu funkcyjnym program jest budowany jako łańcuch transformacji danych. Program ten deklaruje operacje ``map()`` transformujące dane oraz filtr pomijający wyrazy zbyt krótkie. Samo zlicznie wykonuje operacja ``reduce()``. Operacje układają się w protokół: :: plik → słowa → usunięcie interpunkcji → filtr długości → lower() → zliczanie → sortowanie .. literalinclude:: functional.py :language: python :linenos: **Charakterystyka** - brak jawnych pętli (zastąpione przez ``map``, ``filter``, ``reduce``) - dane przepływają przez kolejne transformacje - funkcje są przekazywane jako argumenty **Zalety** - wyraźne oddzielenie etapów przetwarzania - kod bardziej deklaratywny („co” zamiast „jak”) - łatwe komponowanie operacji - dobre dopasowanie do przetwarzania danych **Wady** - dla początkujących mniej intuicyjny, np operacja ``reduce()`` - debugowanie kodu może być trudniejsze - nie w pełni idiomatyczny w Pythonie Podsumowanie ------------ Jak widzisz, każdy z trzech stylów reprezentuje inne podejście do programowania: - styl deklaratywny: **opis krok po kroku** - styl obiektowy: **organizacja wokół obiektów i stanu** - styl funkcyjny: **transformacje danych przez funkcje**