Funkcje, które zwracają wartości

Większość funkcji wymaga podania argumentów, pewnych wartości, które kontrolują jak funkcja wykonuje swoje zadania. Przykładowo, jeżeli chciałbyś obliczyć wartość bezwzględną jakiejś liczby, musisz podać do funkcji właśnie tę liczbę. Python posiada wbudowaną funkcję do obliczania wartości bezwzględnych:




(ch04_4)

W tym przykładzie, argumentami podanymi do funkcji abs są 5 i -5.

Niektóre funkcje pobierają więcej niż jeden argument. Przykładowo moduł math zawiera funkcję o nazwie pow, która oczekuje dwóch argumentów, podstawy oraz wykładnika.




(ch04_5)

Informacja

Widzielismy już oczywiście, że potęgowanie można wykonać za pomocą operatora **

Inną funkcją wbudowaną w język Python, która przyjmuje więcej niż jeden argument, jest funkcja max.




(ch04_6)

Do funkcji max możemy podać dowolną ilość argumentów odddzielonych przecinkami, a ona zwróci nam największą wartość, jaką przekazaliśmy do funkcji. Argumentami mogą być po prostu liczby, ale i mogą być i wyrażenia. Wynikiem ostatniego wywołania jest 503, ponieważ większe jest zarówno od 33, 125 jak i 1. Proszę zauważyć, że max działa też z listami.

Co więcej, funkcje takie jak range, int czy abs zwracają wielkości, które mogą być później wykorzystane do budowy nieco bardziej skomplikowanych wyrażeń.

Tak więc najbardziej istotną różnicą pomiędzy tymi funkcjami, a takimi jak draw_square jest to, że draw_square wywołujemy nie po, to by obliczyć jakąś wartość, ale ponieważ chcemy, by wykonała sekwencję kroków, które spowodują narysowanie jakiegoś kształtu za pomocą żółwia.

Funkcje zwracające wartości nazywane są czasem fruitful functions (funkcjami owocnymi). W wielu językach programowania jeżeli dana cześć kodu nie zwraca wartości nazywana jest procedurą, ale tutaj będziemy podążać za nomenklaturą Pythona i tego typu wielkości również nazywać będziemy funkcjami, lub, jeżeli będziemy chcieli taką własność podkreślić, funkcjami bezowocnymi (non-fruitful).

Funkcje, zwracające wartości pozwalają użytkownikowi na dostarczenie do nich pewnej informacji (w postaci argumentów). Ale pojawia się dodatkowa informacja (jakieś dane), którą zwraca funkcja.

../_images/blackboxfun.png

Jak zbudować swoją własną funkcję zwracającą wartość? Zaczniemy od bardzo prostej funkcji matematycznej, którą nazwiemy square (kwadrat). Będzie ona pobierać jedną liczbę jako parametr i zwracać jej kwadrat. Tak będą wyglądać diagram oraz kod funkcji.

../_images/squarefun.png



(ch04_square)

Po słowie return widzimy wyrażenie, które będzie ewaluowane. Rezultat zwrócony będzie przez funkcję w miejscu wywołania. Ponieważ za słowem return możemy wstawić dowolne poprawne wyrażenie języka Python moglibyśmy ominąć tworzenie tymczasowej zmiennej y i napisać po prostu return x*x. Spróbuj zmodyfikować powyższą funkcję tak, by przekonać się, że wynik jej działania będzie taki sam. Z drugiej strony użycie owej zmiennej tymczasowej y w kodzie programu ułatwia debugowanie. Takie zmienne tymczasowe nazywamy zmiennymi lokalnymi.

Trzeba zauważyć tu jedną istotną rzecz. Nazwa zmiennej, którą podajemy do funkcji jako argument — to_square` — nie ma nic wspólnego z nazwą parametru formalnego — x. Należy pamiętać, że w momencie wywołania funkcji square wykonuje się przypisanie x = to_square. Nie ma żadnego znaczenia jak nazwano zmienną w momencie wywołania. W bloku funkcji square jej nazwa to x. Jasno widać to w narzędziu codelens, gdzie zmienne globalne oraz zmienne lokalne dla funkcji square widzimy w oddzielnych tabelkach.

(ch04_clsquare)

Ważną rzeczą jest zwrócenie uwagi na ruch czerwonej i zielonej strzałki, kiedy krok po kroku będziesz przechodził przez ten kod w codelens. Narzędzie to używa strzałek, aby pokazać w którym miejscu aktualnie się znajdujemy. Strzałka czerwona wskazuje na linię kodu, która ma być wykonana jako następna. Zielona natomiast wskazuje na linijkę właśnie wykonaną.

Gdy uruchomimy codelens po raz pierwszy widzimy tylko czerwoną strzałkę, wskazującą na pierwszą linię. Oznacza to, że linia numer 1 będzie wykonana właśnie jako pierwsza oraz że nie ma żadnej linijki wykonanej wcześniej.

Naciskając przycisk Forward (w przód) można zauważyć, że czerwona strzałka przeskakuje na linię numer 5, pomijając linie 2 i 3, zawierające ciało funkcji, a w tym samym czasie zielona strzałka pojawia się na linijce nr 1. Dlaczego tak się to dzieje? Spowodowane jest to faktem, że definicja funkcji to nie to samo co wywołanie funkcji. Linie druga i trzecia nie będą wykonane dopóki funkcja nie zostanie wywołana w linii nr 6. Linia nr 1 definiuje funkcję, wtedy też nazwa square dodana będzie do zmiennych globalnych, ale z drugiej strony to jest wszystko, co w tym miejscu powoduje wykonanie polecenia def. Ciało funkcji będzie wykonane później. Naciskając ponownie przycisk Forward zobaczysz jak tok programu powoduje przeskok od linii, zawierającej wywołanie funkcji do ciała funkcji i po tym jak funkcja zwróciła obliczoną wartość (która następnie została przypisana do zmiennej square_result) wraca do linii nr 7.

Jest jeszcze jeden aspekt zwracania wartości przez funkcję, który powinniśmy omówić. Jeżeli przy słowie return nie stoi żadne wyrażenie inne niż None lub funkcja nie zawiera słowa kluczowego return to w języku Python funkcja zawsze zwraca wartość None. Zerknij na poniższy kod, który popełniany jest przez większość początkujących programistów języka Python. Przechodząc w codelens przez ów przykład krok po kroku, zwróć szczególną uwagę na wielkość zwracaną przez funkcję w tabelce, zawierającej zmienne lokalne, a późnej zerknij na to, co jest drukowane przez print w ostatniej linii.

(ch04_clsquare_bad)

Kłopot z tą funkcją jest taki, że pomimo, że drukuje ona wartość kwadratu podanej liczby na standardowe wyjście to wartość ta nie będzie zwrócona w miejscu wywołania funkcji. Jako, że w linii 6 następuje przypisanie wartości zwracanej z funkcji square, interpreter przypisze oczywiście None, czyli to co zwraca funkcja. W tym przyapdku zmienna square_result będzie trzymać właśnie tę wartość i z tego powodu wydruk, który robimy w kolejnej linii nie będzie miał większego sensu. Zazwyczaj funkcje konstruuje się w taki sposób, aby zwracały wartości, które mogą być bądź wydrukowane, bądź wykorzystane w miejscu, gdzie je wołamy.

Sprawdź swoją wiedzę

func-2-1: Co jest nie tak z poniższą definicją funkcji?

def add_em(x, y, z):
    return x + y + z
    print('wynikiem jest', x + y + z)





func-2-2: Co zwróci poniższa funkcja?

def add_em(x, y, z):
    print(x + y + z)




Następna część - Zmienne i parametry są lokalne