Funkcje - poziom wyżej

Funkcje nie różnią się bardzo od zmiennych. Możemy naszą funkcję przypisać do jakiejś zmiennej (nie wywołując jej) w ten oto sposób, a następnie korzystać z niej w normalny sposób.
 

def f(x=0):
    return (2 * (x**3))/8.51
 
funkcja = f
 
print f()
print funkcja()

Nie jest to szczególnie przydatne ale prowadzi nas do pewnego odkrycia: skoro funkcji można użyć jako zmiennej to można też przekazać ją jako argument! A to rozwiązanie znajdzie całkiem sporo ciekawych zastosowań. Zobaczmy zatem jak to działa

def wyswietl(napis):
    print napis
 
def wez_napis_i_cos_z_nim_zrob(napis, zrob):
    zrob(napis)
 
wez_napis_i_cos_z_nim_zrob("Jakis napis", wyswietl)

To daje nam ciekawe możliwości, więc napiszmy kalkulator działający w ten sposób, który może zrobić coś z 2 liczbami. Od razu zauważ, że dzięki takiemu podjeściu będziemy mogli do naszego kalkulatora łatwo dodawać nowe funkcjonalności zupełnie nie zmieniając kodu, który napisaliśmy wcześniej.

def policz(jak, liczba1, liczba2):
    return jak(liczba1, liczba2)
 
def dodaj(x, y):
    return x+y
 
def podnies_do_potegi(x, y):
    return x**y
 
def pomnoz(x, y):
    return x*y
 
def podziel(x, y):
    #tutaj zamieniamy jedna z liczb
    #na zmiennoprzecinkowa na 
    #potrzeby Pyhona2
    return (x*1.0)/y

Możesz teraz dopisać samodzielnie funkcję, która odejmuje zupełnie nie zmieniając naszego kodu! To może być naprawdę użyteczne.

Kolejną (i już ostatnią w tym samouczku) ciekawą rzeczą dotyczącą funkcji jest rekurencja. Jest to mechanizm pozwalający na to, że funkcja może wywoałać samą siebie. Tak, to może wydać się na początku dziwne i nieintuicyjne ale zauważmy, że w matematyce jest to bardzo standardowa metoda opisu funkcji. Jako przykład pokażmy standardowo liczenie silni.

Jeśli nie wiesz co to silnia: zapisujemy ją za pomocą "!" a oznacza to mnożenie kolejnych liczb od 1 do podanej liczby. Czyli

\(5! = 1 * 2 * 3 * 4 * 5 = 120\)

(Warto nadmienić, że silnia z zera to 1)

Funkcja rekurencyjna w Pythonie wyglądać będzie tak:

def silnia(x):
    if x==1 or x==0:
        return 1
    else:
        return x*silnia(x-1)

Przeanalizujmy zatem co stanie się po wpisaniu silnia(3)

  1. Warunek wyjścia nie jest na początku spełniony, więc zostanie zwrócona 3 pomnożona przez silnię z liczby o jeden mniejszej (bo 3! to to samo co 3*2!)
  2. Zostanie więc wywołana funkcja silnia(2), warunek wyjścia znów nie zostanie spełniony, czli zostanie zwrócona 2 pomnożona przez silnię z 1
  3. Zostanie wywołana silnia(1), warunek x==1 zostanie spełniony, więc zostanie zwrócona jedynka
  4. Teraz "wracając" do wywołania silnia(2) ta jedynka jest mnożona przez 2 dzięki czemu uzyskujemy wynik silni dla 2
  5. Co za tym idzie ten wynik jest mnożony przez 3 aby uzyskać wynik silni dla 3
  6. Otrzymujemy nasz wynik, czyli 3*(2*(1)), a więc 6 :)

Na początku może wydawać się to trochę skomplikowane, więc dobrze jest to sobie samemu rozpisać lub nawet rozrysować na kartce.

Kiedy już zrozumiesz jak działa rekurencja musisz uświadomić sobie, że pisanie funckji rekurencyjnych wiąże się ze pewnym ryzykiem. Jeśli na przykład zapomnielibyśmy odejmować 1 od x, to funkcja wywoływała by się w nieskończoność! Na szczęście interpreter na to niepozwoli i zwróci nam błąd nadmiernego zagnieżdżenia pętli, ale  zawsze trzeba pamiętać, by rozważyć, czy funkcja jest skonstruowana tak, że wywołania kiedyś się zakończą.