.. _funkcje: Funkcje -------------------------------------- .. admonition:: W skrócie :class: def *Funkcja to autonomiczny fragment programu, wydzielony do późniejszego wielokrotnego wykorzystania.* Funkcje w programowaniu przypominają te znane z matematyki: najczęściej przyjmują argumenty i zwracają jakąś wartość. Funkcję wywołujemy wpisując po prostu jej nazwę, a argumenty wymieniamy w nawiasach. Dokładnie w ten sposób, w jaki korzystasz z funkcji ``print()``. Tu dla przykładu pokażmy Pythonową funkcję sinus: .. raw:: html
.. admonition:: Ćwiczenie 1 zmodyfikuj skrypt tak, aby obliczyć ``cos(2.4)`` Raz zadeklarowane funkcje, np. trygonometryczne mogą być wielokrotnie wykorzystywane bez konieczności ich ponownego deklarowania, np. jak w poniższym programie, który obraca wektor w przestrzeni trójwymiarowej wokół osi Z (współrzędna z pozostaje bez zmian podczas tego obrotu): .. raw:: html
Biblioteka języka Python, dostarczona wraz z interpreterem, udostępnia szeroki wachlarz funkcji na różne okazje, m.in. funkcje matematyczne. Trzeba je tylko znaleźć (patrz dokumentacja online) i zaimportować na początku programu odpowiedni moduł. A jak możemy stworzyć własne funkcje? .. _deklarowanie_funkcji: Deklarowanie funkcji """""""""""""""""""""""""""""""""" Nową funkcję deklarujemy następująco: .. raw:: html
Należy wykorzystać słowo kluczowe ``def``, po którym następuje nazwa funkcji i lista argumentów (w nawiasach). Tu funkcja ma tylko jeden argument - ``x``. Jak zwykle w Pythonie, tu też panuje :ref:`zasada wcięcia ` : w funkcji są te instrukcje, które są odpowiednio przesunięte (linie 3 i 4) względem tu nagłówka funkcji (linia 1). Szególnie ważna jest linia 4, która odpowiada za to, że funkcja zwraca wartość, korzystająca ze słowa kluczowego ``return``. Wynikiem powyższego programu będzie oczywiście liczba **25**. .. _domyślne: Funkcje wieloargumentowe i parametry domyślne """"""""""""""""""""""""""""""""""""""""""""""""""""""" Funkcja może przyjmować więcej niż jeden argument: .. raw:: html
.. admonition:: Ćwiczenie 2 zmodyfikuj skrypt tak, aby funkcja obliczała wartość :math:`y = a x^3 + b x^2 + c x + d`. Wywołując funkcję musimy podać wartości *wszystkich parametrów*, oddzielając je przecinkami, nawet jeżeli ich nie potrzebujemy. W powyższym przykładzie ``funkcja_kwadratowa`` oblicza wartość wyrażenia :math:`y = a x^2 + b x + c`. Jeżeli potrzebujemy tylko :math:`y = x^2`, musimy przekazać wartości ``a``, ``b`` i ``c`` odpowiednio ``1``, ``0``, ``0``. Gdyby wyrażenie :math:`y = x^2` było tym, którego potrzebujemy najczęściej, wpisywanie tych zer i jedynki zaczęło by już nas męczyć. I tu z pomocą przychodzą wartości domyślne parametrów: .. raw:: html
Linijki 6 i 7 są w tym przykładzie równoważne. Co ciekawe, ani przyjmowanie argumentów ani zwracanie wartości nie jest obowiązkowe! W tym pierwszym przypadku lista argumentów funkcji jest pusta, w drugim zaś w definicji funkcji nie ma instrukcji ``return``, np. .. raw:: html
.. _zwracanie_tupli: .. rubric:: Zwracanie wielu wyników Pewnym ograniczeniem jest jednak to, że funkcja może zwrócić tylko jedną wartość. Co robić, kiedy musimy zwrócić np. dwie liczby? Wykorzystujemy w tym celu struktury danych; najbardziej nadają się do tego celu :ref:`tuple (krotki)`. Poniższy kod zamienia współrzędne radialne punktu na kartezjańskie a wynik zwraca jako dwu-krotkę (w linii 8): .. raw:: html
Zauważ, że w linii 13 następuje *rozpakowanie* tupli. Program wygląda dzięki temu tak, jakby funkcja ``radial_to_cartesian()`` naprawdę zwracała dwie wartości a nie jedną! Powyższa funkcja zakłada, że środek układu współrzędnych, w którym zmierzono kąt, leży w ``(0,0)``. Czasem chcielibyśmy to zmienić. Przyda się zatem funkcja, która dodatkowo przyjmuje również współrzędne środka. Ponieważ jednak nie będzie to często wykorzystywana opcja, pozostawiamy wartość domyślną na ``(0,0)`` .. raw:: html
Widać tu główną zaletę stosowania argumentów funkcji z wartościamy domyślnymi: nowa funkcja ``radial_to_cartesian()`` wywołana *po staremu*, a więc bez podawania współrzędnych środka, działa dokładnie tak jak działała do tej pory. Rekurencja """"""""""""""""""""""""""""""""""""""""""""""""""""""" W programie losującym procenty funkcja ``losuj_procenty()`` wywołuje funkcję ``random()``. Ciąg wywołań może być znacznie dłuższy: funkcja może wywoływać funkcję, która wywołuje funkcję która wywołuje ... itd. Czy jednak funkcja może wywoływać samą siebie? .. admonition:: Uwaga :class: def Wywoływanie funkcji przez samą siebie nazywamy **rekurencją**. Wykorzystując rekurencję w swoich programach należy uważać, aby program nie działał w nieskończoność. W poniższym przykładzie funkcja ``silnia(n)`` oblicza :math:`n!` .. raw:: html
**Zalety rekurencji** - zastosowanie rekurencji często bardzo upraszcza i skraca kod - skomplikowany problem może być rekurencyjnie podzielony na prostsze - doskonale pasuje do niektórych algorytmów, np przechodzenia grafu albo drzewa; zastosowanie iteracji jest znacznie bardziej skomplikowane **Rekurencja ma też wady** - wywołania rekurencyjne są bardziej kosztowne obliczeniowo - łatwo popełnić błąd w którym program działa w nieskończoność, co skutkuje przepełnieniem stosu (ang. *stack overflow*) - kod rekurencyjny trudniej prześledzić .. _zmienne_lokalne_i_globalne: Zmienne lokalne i globalne """""""""""""""""""""""""""" W programie często wykorzystujemy zmienne. Zmienne możemy też tworzyć wewnątrz funkcji. Co się stanie, kiedy nazwy zmiennych będą się powtarzać? .. raw:: html
Powyższy przykład pokazuje, że zmienne stworzone wewnątrz i na zewnątrz funkcji to dwie zupełnie różne sprawy. Mamy tu bowiem **dwie różne** zmienne o nazwie ``s``. Jedna jest widziana w programie głównym, druga zaś - tylko w funkcji. I tu pojawia się pytanie, czy w funkcji można zapisać coś do zmiennej globalnej? Otóż można, trzeba tylko skorzystać ze słowa kluczowego ``global``, jak w programie poniżej: .. raw:: html
Jakie są losy zmiennej ``global_x``? Na samym początku programu jest tworzona z wartością początkową ``0``. Następnie wywoływana jest funkcja ``ustaw_globalna()``, która zmienia jej wartość na ``1``. Funkcja ``drukuj_globalna2()`` tworzy jednak własną *lokalną* zmienną o tej samej nazwie, *przesłaniając* tym samym zmienną globalną. Wartość zmiennej globalnej pozostanie niezmieniona, mimo że na ekranie wydrukowana zostanie wartość ``4``. Więcej o funkcjach """""""""""""""""""""""""""" Funkcja w Pythonie jest pewnym obiektem, przypisanym do jego nazwy, np. ``radial_to_cartesian()`` zdefiniowana w jednym z powyższych przykładów. Funkcja zatem, zupełnie jak inne obiekty, może być *argumentem funkcji*! Do czego to może się przydać? Możesz na przykład zaimplementować całkowanie numeryczne funkcji metodą trapezów: .. raw:: html
Funkcję podcałkową można oczywiście wpisać wewnątrz funkcji ``trapezoidal()``, takie rozwiązanie byłoby mało ogólne. Jak zatem umożliwić całkowanie *dowolnej* funkcji? Należy przekazać ją jako argument funkcji ``trapezoidal()``, jak w powyższym przykładzie.