Funkcje w Pythonie służą do tego, aby pewne instrukcje grupować w bloki, które będą wykorzystywane więcej niż jeden raz. W ten sposób wielokrotnie można wykorzystywać gotowy zbiór instrukcji, który na dodatek w razie modyfikacji wymaga zmiany tylko w jednym miejscu. Innymi słowy funkcje to procedury, które są wywoływane po nazwie. Funkcje zwracają pewien wynik, a także mogą przyjmować dane, czyli argumenty.
Funkcje i ich zastosowanie
Funkcje są tym elementem programowania, który odpowiada za strukturę programu. Dwa główne powody, dla których stosuje się funkcje to:
- ponowne wykorzystywanie kodu, co zmniejsza jego powtarzalność – „luźny” kod jest wykonywany od razu, z kolei funkcje pozwalają na to, aby odpowiednio pogrupować instrukcje, a następnie wykorzystywać ten sam kod bloku wiele razy. Dzięki temu powtarzalność kodu jest mniejsza, a jego utrzymanie łatwiejsze.
- podzielenie programu na części, jako że każda funkcja jest tak naprawdę osobnym zadaniem, to dzięki wykorzystaniu takiego podejścia w programowaniu możliwe jest podzielenie nawet skomplikowanych procesów na mniejsze działania.

Podstawowa składnia związana z tworzeniem funkcji:
Definiowanie funkcji:
>>> def printer():
... print('Witaj świecie')
Wywołanie funkcji:
>>> printer()
Witaj świecie
Definiowanie funkcji zwracającej wynik (tylko taka funkcja, która kończy się wyrażeniem return):
>>> def result():
... return 4+3
...
>>> result()
7
Tworzenie funkcji anonimowej lambda:
funcs = [lambda x: x+2, lambda x: x+22]
>>> funcs[1](9)
31
- Funkcje w Pythonie są definiowane za pomocą instrukcji def. Jest to instrukcja wykonywalna, która nie podlega kompilacji. Funkcja istnieje dopiero wtedy, gdy Python dotrze do jej kodu i wykona instrukcję zawarte w def. Trzeba jednak pamiętać, że zapisane funkcje są umieszczane w plikach modułu, które i tak są wykonywane wtedy, kiedy plik jest importowany po raz pierwszy w innym kodzie. Wtedy również wykonywane są funkcje zawarte w pliku.
- Instrukcja def pozwala zarówno na stworzenie obiektu, jak i przypisanie go do nazwy. Nazwa staje się referencją do obiektu funkcji, która jest używana do jej wywołania.
- Wyrażenie lambda tworzy obiekt i zwraca go jako wynik. Jest to specjalna składnia przeznaczona do stosowania w miejscach, gdzie instrukcja def nie może zostać użyta – wyrażenia lambda służą do tworzenia tak zwanych funkcji anonimowych.
- Instrukcja return służy do zwracania wyników, które są przypisywane do obiektu wywołującego. Gdy wywołuje się funkcję, sterowanie jest zawieszone na czas jej wywoływania i dopiero wtedy zwracane zwracane z powrotem do kodu wywołującego. Wartość zwracana za pomocą instrukcji return jest wynikiem wywołania funkcji. Jeśli funkcja nie ma instrukcji return lub nie ma żadnej wartości, wówczas przesyłany jest obiekt domyślny None.
Argumenty funkcji
Funkcja może przyjmować argumenty, czyli dane przesyłane podczas jej wywołania. Argumenty są przekazywane poprzez przypisanie, czyli referencje do obiektu.
- Zmiana nazwy argumentów wewnątrz funkcji nie powoduje jakichkolwiek zmian w kodzie wywołującym.
- W przypadku obiektów mutowanych może dojść do zmiany wartości, jeśli w funkcji zmieniamy obiekt mutiwalny.
- Argumenty są przekazywane według pozycji, chyba że są to argumenty słowa kluczowe lub wyrażenia rozpakowujące.
- Funkcje można umieszczać w dowolnym miejscu w kodzie, w tym zagnieżdżać w innych funkcjach lub umieszczać w instrukcji, gdy na przykład wykonanie konkretnej funkcji zależy od wyników testu.
>>> test = 3
>>> if test == 3:
... def func(): print("Test to 3")
... else:
... def func(): print("Nie jest to 3.")
...
>>> func()
Test to 3
Instrukcja def i return
Zadaniem instrukcji def jest stworzenie obiektu oraz przypisanie go do nazwy. Instrukcja składa się z wiersza nagłówka, a następnie wciętego bloku instrukcji lub po prostu krótkiej instrukcji po dwukropku, jeśli funkcja jest naprawdę prosta. Blok instrukcji staje się ciałem funkcji, który jest wykonywane za każdym razem, gdy wywołujemy funkcję. W wierszu nagłówka znajduje się nazwa funkcji oraz argumenty, nazywane również parametrami. Są one umieszczone w nawiasach. Gdy podczas wywołania funkcji przekazujemy do niej obiekty, to nazwy argumentów są do nich przypisywane.
Instrukcja return może być wywołana w dowolnym miejscu funkcji. Kończy ona wówczas jej działanie oraz odsyła wyniki do miejsca wywołującego. Return może zawierać wyrażenie, które podaje ostateczny wynik funkcji. Jeśli funkcja nie zawiera żadnej instrukcji return, wówczas zwraca obiekt typu None.
>>> def func(): print("Hello")
...
>>> print(func())
Hello
None
Funkcję można również wykonywać po przypisaniu jej do innej nazwy.
>>> def my_func(): return 40+90
...
>>> my_simple_func = my_func
>>> my_simple_func()
130
W ostatecznym rozrachunku funkcje są w końcu po prostu obiektami. Mogą być nie tylko przypisywane do innych nazw, ale również można dołączać do nich atrybuty.
Przypatrzmy się prostej funkcji, która zwraca sumę dwóch podanych liczb:
>>> def my_sum(x, y):
... return x + y
Jeżeli Python natrafi w kodzie na tę funkcję, utworzy nowy obiekt funkcji. Następnie przypisze ten obiekt do nazwy my_sum. Instrukcja def odpowiada za definiowanie funkcji, ale nie za jej wywołanie. Wywołanie odbywa się poprzez napisanie nazwy funkcji i dodanie nawiasów na końcu. Jeśli funkcja oczekuje argumentów należy je podać, chyba że są to argumenty domyślne, których wartości jest ustalona na wypadek, gdyby użytkownik nie przekazał żadnego argumentu.
>>> my_sum()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: my_sum() missing 2 required positional arguments: 'x' and 'y'
Przekazanie argumentów:
>>> my_sum(9, 4)
13
>>> my_sum('ab', 'c')
'abc'
Polimorfizm w Pythonie
Jak widać funkcja wykonała działanie zarówno dla zmiennych typu liczbowego, jak i dla łańcuchów znaków. Takie zachowanie w Pythonie jest znane również jako polimorfizm, a więc koncepcja, zgodnie z którą obiekty powinny mieć możliwość robienia czegoś wtedy, gdy ma to sens dla ich składni. Operacja jest zatem zależna od obiektów, na jakich jest wykonywana, a jako że w Pythonie jest pełno obiektów dynamicznych, często dochodzi do wykorzystania polimorfizmu. Jest oczywiście zamierzone działanie, które nadaje temu językowi jeszcze więcej elastyczności. Dzięki temu w Pythonie nie należy się też bać błędów, jako że to właśnie one poinformują nas o tym, gdy danego wyrażenia nie będzie się dało wykonać na wybranym obiekcie.
Typowanie dynamiczne
W Pythonie typu danych nie należy wcześniej deklarować, bo w zasadzie nie ma on znaczenia. Kod w Pythonie należy tworzyć myśląc o interfejsie obiektów, a nie ich poszczególnych typach. Ma to również swoje ciemne strony, jako że może prowadzić do przeprowadzenia operacji na danych, których wcale nie chcieliśmy używać. Z tego względu kod wymaga testowania. Jednak z drugiej strony zapewnia to wysoką elastyczność kodu. Dzięki temu, że typ danych, jakie są przypisywane do zmiennej, może zmienić się praktycznie z wywołania na wywołanie, to Python jest określany mianem języka, w którym występuje tzw. typowanie dynamiczne.
Przykład z dwoma różnymi typami obiektów zastosowanymi w jednej funkcji – stwórzmy funkcję, która zbiera elementy wspólne w dwóch sekwencjach:
>>> def crossing(seq1, seq2):
... res = []
... for el in seq1:
... if el in seq2:
... res.append(el)
... return res
...
>>> crossing(['ab', 9, 1099, '!'], ('ab', '!', 234))
['ab', '!']
Jako argumentów użyliśmy listy oraz krotki. Funkcja była w stanie zidentyfikować wspólne elementy, ponieważ wszystkie podane w niej instrukcje (pętle for, test przynależności in) są obsługiwane zarówno przez krotki, jak i listy, a w zasadzie przez każdy typ danych będący sekwencją. Jeśli natomiast podalibyśmy wartość, która nie obsługuje tego typu interfejsów, wówczas program zgłosi błąd.
>>> crossing(['ab', 9, 1099, '!'], 1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in crossing
TypeError: argument of type 'int' is not iterable
Zmienne funkcji, czyli zmienne 'tylko dla niej’
Co ze zmiennymi? Zmienne funkcji są dla niej lokalne, a więc widoczne tylko w jej ciele. Oznacza to, że nawet jeśli funkcja zwraca jakiś wynik, to używane przez nią zmienne znikają, a także nie są bezpośrednio dostępne w kodzie „na zewnątrz”. Oprócz zmiennych lokalnych istnieją również inne rodzaje zmiennych, chociażby tak jak globalne oraz nielokalne.
>>> def simple_func():
... a=10
...
>>> print(a)
Traceback (most recent call last):
File "<python-input-1>", line 1, in <module>
print(a)
^
NameError: name 'a' is not defined
Jak widać w powyższym przykładzie, zmienna a nie jest dostępna poza funkcją.
W następnym wpisie przyjrzymy się bliżej iteracjom oraz listom składanym.
Dodaj komentarz
Musisz się zalogować, aby móc dodać komentarz.