Funkcje w Pythonie

Nic tak nie cieszy jak jeszcze mniej pracy – i po to właśnie wymyślono w językach programowania funkcje:)

Funkcja to fragment kodu zajmujący się (wedle najlepszych praktyk) jednym, konkretnym zadaniem. Najlepiej opisanym nazwą funkcji – tak jak na przykład print() drukuje tekst na ekran a range() zwraca określoną zakresem sekwencję liczb. Dzięki funkcjom nie trzeba wielokrotnie pisać tego samego kodu, można napisać raz i wywołać kiedy potrzeba. Dodatkowo – jeżeli mamy większy projekt, nad którym pracuje kilka osób – każdy może być odpowiedzialny za pojedyncze funkcje, a inni mogą ich używać nie interesując się co jest w środku. Takie czarne skrzynki. Tak samo jak wspomniany wyżej print() – tak na prawdę nie interesuje nas co jest w środku. Wiemy, że podajemy parametry i drukuje nam tekst na ekran.

Z czego składa się funkcja w Pythonie?

Jest tutaj całkiem podobnie jak w innych językach programowania. Mamy:

  • nazwę funkcji oraz nawiasy () (umieszcza się w nich parametry przyjmowane przez funkcję – nawet jeżeli nie ma żadnych parametrów – zostawiamy same nawiasy)
  • (opcjonalnie) parametry
  • (opcjonalnie) specjalny komentarz z opisem działania funkcji, tzw. docstring (napiszę osobny artykuł na ten temat w przyszłości)
  • ciało funkcji
  • (opcjonalnie) return – czyli zwrócenie wartości przez funkcję.
  • funkcja kończy się tam, gdzie kończy się jej wcięcie.

Przykładowa funkcja, która wyświetli nam komunikat:

def wyswietl_komunikat():
    print("Ultra ważny komunikat!")

wyswietl_komunikat()
Ultra ważny komunikat!

Ok, ale samo wyświetlanie komunikatów takie raczej mało przydatne – chociaż z drugiej strony – jeżeli w kodzie pojawia nam się wyświetlenie jakiegoś komunikatu 20 razy… I pojawia się potrzeba zmiany jego brzmienia… To chyba mimo wszystko lepiej musieć poprawić jedną funkcję zamiast 20 osobnych printów w kodzie, prawda?

Parametry funkcji

Nie samymi jednak komunikatami człowiek żyje, czasami chciałoby się coś więcej zautomatyzować, uprościć, policzyć czy policzyć. I tutaj wchodzą parametry funkcji całe na biało!

def wiek_osoby(imie, wiek):
    print("Towarzysz " + imie + " ma " + str(wiek) + " lat.")

wiek_osoby("Gerwazy", 69)
wiek_osoby("Dżesika", 15)
wiek_osoby("Mirek", 44)
Towarzysz Gerwazy ma 69 lat.
Towarzysz Dżesika ma 15 lat.
Towarzysz Mirek ma 44 lat.

A co się stanie jak ktoś nie poda wieku?

def wiek_osoby(imie, wiek):
    print("Towarzysz " + imie + " ma " + str(wiek) + " lat.")

wiek_osoby("Gerwazy", 69)
wiek_osoby("Dżesika", 15)
wiek_osoby("Mirek", 44)
wiek_osoby("Vanesa")
Towarzysz Gerwazy ma 69 lat.
Towarzysz Dżesika ma 15 lat.
Towarzysz Mirek ma 44 lat.
Traceback (most recent call last):
  File "funkcje.py", line 7, in <module>
    wiek_osoby("Vanesa")
TypeError: wiek_osoby() missing 1 required positional argument: 'wiek'

Błąd. James Błąd. Ale możemy się przed tym zabezpieczyć…

Wartości domyślne argumentów funkcji

…podając domyślną wartość parametru, która zostanie zastosowana w przypadku „zapomnienia” kolejnego parametru;) Po prostu w nawiasach po nazwie funkcji, przy nazwie parametru dodajemy =domyślna wartość. Nie pisałem o tym wcześniej – ogólnie dobra praktyka jest taka, że wokół „=” dajemy po obu stronach spacje – jest czytelniej. Z wyjątkiem wartości domyślnych dla argumentów funkcji. Napiszę o tym więcej w innym odcinku. Wracając do przykładu:

def wiek_osoby(imie, wiek=-1):
    print("Towarzysz " + imie + " ma " + str(wiek) + " lat.")

wiek_osoby("Gerwazy", 69)
wiek_osoby("Dżesika", 15)
wiek_osoby("Mirek", 44)
wiek_osoby("Vanesa")

I od razu widać, że o czymś zapomnieliśmy:

Towarzysz Gerwazy ma 69 lat.
Towarzysz Dżesika ma 15 lat.
Towarzysz Mirek ma 44 lat.
Towarzysz Vanesa ma -1 lat.

Ok, mamy to załatwione. Ale można to załatwić lepiej – możemy sprawdzać wartość argumentu przed użyciem:

def wiek_osoby(imie, wiek=-1):
    if imie != '' and wiek != -1:
        print("Towarzysz " + imie + " ma " + str(wiek) + " lat.")
    else:
        print("Podano złe dane")

wiek_osoby("Gerwazy", 69)
wiek_osoby("", 15)
wiek_osoby("Mirek", 44)
wiek_osoby("Vanesa")
Towarzysz Gerwazy ma 69 lat.
Podano złe dane
Towarzysz Mirek ma 44 lat.
Podano złe dane

Przekazywanie argumentów funkcji

Bardzo ważna rzecz do zapamiętania – argumenty są przekazywane funkcji przez wartość. Co to znaczy?

Popatrzmy na poniższy przykład:

def powieksz_liczbe(x):
    x += 5
    print("x wewnątrz funkcji: " + str(x))

x = 20
print("x przed wywołaniem funkcji: " + str(x))
powieksz_liczbe(x)
print("x na zewnątrz funkcji, po jej wywołaniu: " + str(x))
x przed wywołaniem funkcji: 20
x wewnątrz funkcji: 25
x na zewnątrz funkcji, po jej wywołaniu: 20

Jak widać funkcji została przekazana wyłącznie wartość przekazanego do niej argumentu. Funkcja ma wewnątrz swój własny x.

Co też tutaj się najlepszego wydarzyło? Czas na wprowadzenie nowych pojęć:)

Zmienne globalne i lokalne

Najprościej mówiąc chodzi o zakres widoczności – zmienna globalna, to zmienna widoczna w całym skrypcie (zakres globalny), a zmienna lokalna (zakres lokalny) jest widoczna tylko w zakresie, w którym została zadeklarowana. W powyższym przykładzie ktoś nie znający tych zasad mógłby pomyśleć, że x po wyjściu z funkcji pozostanie zmieniony, ale tak nie będzie. W obrębie funkcji pierwszeństwo będzie miał x lokalny i to on zostanie zmieniony, a nie ten globalny, zadeklarowany poza funkcją.

Dlatego warto nazywać zmienne w przemyślany i niejednoznaczny sposób:)

Zwracanie wartości przez funkcję – return

Skoro te funkcje są takie fajne i mają ułatwiać pracę – fajnie by było gdyby jednak mogły coś przekazać z powrotem, prawda? Do tego służy instrukcja return. Użyjemy tutaj przerobionej funkcji powieksz_liczbe(x). Wywołamy ją 3 razy, za każdym razem aktualizując zmienną x – przy okazji wewnątrz funkcji zmienną nazwę tym razem y, żeby nie było wątpliwości;)

def powieksz_liczbe(y):
    y += 5
    return y

x = 20

x = powieksz_liczbe(x)
print(x)
x = powieksz_liczbe(x)
print(x)
x = powieksz_liczbe(x)
print(x)
25
30
35

I na koniec – return możemy wywołać także bez żadnego parametru – program po prostu opuści wtedy funkcję i wróci do miejsca, z którego został wywołany bez zwracania czegokolwiek. I to tyle odnośnie funkcji na początek.

Nie bądź lama, udostępnij;)