Funkcje w Pythonie

def powiedz_czesc(imie: str) -> str:
    """Zwraca powitanie dla podanego imienia."""
    return f"Cześć, {imie}!"

Funkcje w Pythonie – jedna z najważniejszych rzeczy, których możesz się dzisiaj nauczyć. Spójrz, chociażby na powyższy przykład. To pięknie napisana, idealna w swojej prostocie, funkcja.

Ma słowo kluczowe def, nazwę funkcji napisaną snake_casem (czyli małe litery i podkreślniki), posiada typowany parametr, adnotację typu zwracanego, docstringa i f-string (czyli że string tworzony przez wstrzyknięcia, a nie konkatenacje).

Niby mała rzecz, a tyle rzeczy dało się upchnąć! Ach! Gdybym miała się przyczepić, powiedziałabym, że być może docstring to trochę przerost formy nad treścią (bo przecież to oczywiste, co robi ta funkcja). Albo że nazwa funkcji nie do końca czytelna. Ale cóż… czepiam się.

Jeśli chcesz, żeby Twój kod był czysty, czytelny i tak piękny, że będą go pokazywać w tutorialach do nauki Pythona – stosuj zasady opisane poniżej.

Co to funkcja w Pythonie

Funkcja to nazwany (lub anonimowy) fragment kodu, który wykonuje konkretne zadanie i można go wywołać wielokrotnie, przekazując różne dane.

W Pythonie funkcje są obiektami pierwszej klasy. To znaczy, że można je przekazywać do innych funkcji, przypisywać do zmiennych i przechowywać w strukturach danych.

Funkcje mogą istnieć “luzem” – nie muszą być wewnątrz klasy.

Budowa funkcji

budowa funkcji w pythonie

Funkcja w Pythonie ma kilka obowiązkowych i kilka opcjonalnych elementów. Poniżej opiszemy je wszystkie pokrótce:

def

Słowo kluczowe dev wskazuje, że zaczynamy definiować funkcję. 

Nazwa funkcji

Nazwa funkcji – albo raczej nazwa_funkcji to sposób, w jaki identyfikujemy funkcję i jak później będziemy ją wywoływać. Jest kilka zasad pisania nazw funkcji, dzięki którym od razu widać, że to funkcja (a nie na przykład nazwa klasy). Plus jest taki, że dokładnie te same zasady dotyczą też zmiennych (bo funkcję w Pythonie można traktować jak zmienną).

  • Nazwa funkcji może zawierać małe i wielkie litery, cyfry i podkreślniki. 
  • Nazwa funkcji musi zaczynać się od małej lub wielkiej litery lub podkreślnika _.
  • Nazwa funkcji nie może zaczynać się od cyfry.
  • ZALECANE: Używaj tylko snake_case (małe litery i podkreślniki).
  • ZALECANE: Funkcje powinny zawierać w nazwie czasownik, bo  „coś robią”.
  • ZALECANE: Unikaj krótkich i nieczytelnych nazw (np. x(), f1()).

Parametr funkcji

  • To zmienna lub zmienne, które będą przechowywały wartości przekazane do funkcji podczas jej wywołania.
  • Parametr funkcji jest opcjonalny (choć zalecany).
  • Dodajemy go w w nawiasach okrągłych.

Typ zwracany

  • Kolejny element opcjonalny.
  • Zalecany, jeśli coś zwracasz (wg mnie używanie go, kiedy nic nie zwracasz tylko po to, by dodać „-> None” to przerost formy nad treścią!)
  • Domyślnie to None.
  • Poprzedzamy go strzałką ->.

Dwukropek

Dwukropek wskazuje, że po nim zaczyna się ciało funkcji (ang. body).

Docstringi

  • OPCJONALNE.
  • Docstringi czyli specjalny rodzaj komentarza, który służy do dokumentowania modułów, klas, funkcji i metod.
  • Zwykle są zawarte w potrójnych cudzysłowach. 
  • Opisują, co robi funkcja, jakie przyjmuje parametry i co zwraca.
  • Docstringi są automatycznie przechowywane w atrybucie __doc__ obiektu i można je później wywołać lub stworzyć na ich podstawie dokumentację.

Ciało funkcji

  • Ciało funkcji zaczyna się za dwukropkiem.
  • Musi być wcięte o 4 spacje w stosunku do słowa kluczowego dev.
  • Zawiera sekwencję poleceń, które funkcja ma wykonać.
  • Może (ale nie musi) zawierać słowo kluczowe return, które umożliwia funkcji zwrot wartości.

Pusta funkcja w Pythonie

Jeśli planujesz napisać funkcję, ale chcesz ją wcześniej wywołać w innej funkcji, możesz postawić tzw. placeholder funkcji, czyli funkcję, która jeszcze nic nie zawiera i nic nie robi, tylko czeka, aż ją dokończysz.

def funkcja():
    pass  # jeszcze nie wiem, co tu będzie

Słowo funkcyjne pass mówi Pythonowi, że ten blok kodu jest ok. Dzięki temu nie dostaniesz SyntaxError po uruchomieniu kodu.

Zakres funkcji w programie

Uwaga! W Pythonie nie ma klasycznych modyfikatorów dostępu, ale istnieją konwencje i techniki, które pełnią podobna rolę.

  • Każda funkcja, która nie zaczyna się od podkreślenia, jest publiczna.
  • Jeśli funkcja zaczyna się od pojedynczego podkreślenia, uznaje się ją za chronioną (ang. protected). Jest to tylko konwencja, więc jeśli chcesz ją wywołać z zewnątrz, Python tego nie blokuje.
  • Jeśli Twoja funkcja zaczyna się od podwójnego podkreślenia, jest to funkcja prywatna i Python ukrywa ją za pomocą tzw. name mangling. Dlatego nie można ich użyć bezpośrednio pod tą nazwą (dostaniesz AttributeError).
  • Najbardziej znaną funkcją zaczynającą się od podwójnego podkreślenia jest oczywiście konstruktor. Funkcja __init__ nie jest jednak metodą prywatną, a metodą specjalną (ang. magic method) i jest wywoływana automatycznie podczas generowania instancji klasy.

Rodzaje parametrów i ich kolejność

Parametry funkcji w Pythonie to prawdziwy kosmos! Mają swoją własną składnię, konkretną kolejność i sposób wywoływania.

Jeśli chcesz tylko nauczyć się, jak pisać najprostsze funkcje, stosuj poniższy zapis (domyślny dla Pythona). Taka funkcja praktycznie ma mniejsze szanse na wywoływanie SyntaxError.

def some_function(parameter_a, parameter_b=1):
    print(parameter_a, parameter_b)

#wywołanie funkcji:
some_function(10)                  # ✅ parameter_a=10, 
                                        parameter_b=1
some_function(10, 20)              # ✅ parameter_a=10, 
                                        parameter_b=20
some_function(parameter_a=10, parameter_b=20)
                                   # ✅ OK – można używać nazw

I proste, jasne zasady – nazwa snake_casem, parametry mogą być nazwane lub nie, parametr domyślny na końcu – wszystko gra.

Ale jeśli chcesz pracować z Pythonem, musisz przynajmniej umieć odczytać wszystkie opcje parametrów funkcji i prawidłowo je przekazywać.

SekcjaPrzykładCo przyjmujeNotatki
Positional-onlydef f(a, b, /)a i bZnak / oznacza, że nazwy trzeba pominąć podczas wywołania.
Positional-or-keyworddef f(a, b=1)a lub a i bDomyślny sposób przekazywania argumentów w Pythonie.
Variadic positionaldef f(*args)wszystkoZero lub dowolna liczba argumentów pozycyjnych – nie podawaj nazwy. 
Keyword-onlydef f(*, c, d=0)c lub c i dWszystkie parametry po znaku funkcyjnym * muszą być nazwane.
Variadic keyworddef f(**kw)**kwZero lub dowolna liczba nazwanych argumentów.

Positional-only

  • pierwsze w kolejności przekazywania 
  • nie można podać nazwy
  • wprowadzone w Pythonie 3.8 (PEP 570).
def some_function(param_a, param_b, /):
    print(param_a, param_b)

#wywołanie
some_function(1, 2)              # ✅ działa
some_function(a=1, b=2)          # ❌ TypeError
                                      Nie można użyć nazw!

Positional-or-keyword 

  • drugie w kolejności przekazywania
  • domyślne zachowanie w Pythonie
  • można nazywać, nie trzeba nazywać.
def some_function(param_a, param_b=1):
    print(param_a, param_b)

#wywołanie funkcji:
some_function(10)                  # ✅ parameter_a=10, 
                                        parameter_b=1
some_function(10, 20)              # ✅ parameter_a=10, 
                                        parameter_b=20
some_function(parameter_a=10, parameter_b=20)
                                   # ✅ OK – można używać nazw

Variadic positional 

  • trzecie w kolejności przekazywania.
  • można przekazać dowolną liczbę argumentów pozycyjnych
  • nie wolno ich nazywać.
  • *args albo dowolna inna zmienna z gwiazdką z przodu oznacza dokładnie “zbierz dowolną liczbę argumentów pozycyjnych jako krotkę (ang. tuple)”.
def some_function(*args):
    print(args)

#wywołanie funkcji:
some_function(1, 2, 3)           # ✅ args = (1, 2, 3)

Keyword-only

  • czwarte w kolejności przekazywania
  • musisz użyć nazwy parametru
def some_function(*, param_a, param_b=0):
    print(param_a, param_b)

#wywołanie
some_function(param_a=5)           # ✅ działa
some_function(5)                   # ❌ TypeError
                                        Trzeba użyć nazw

Variadic keyword

  • ostatnie w kolejności przekazywania
  • dwie gwiazdki i nazwa zmiennej **kwargs oznaczają dowolną liczbę nazwanych argumentów
  • **kwargs (albo zmienna o dowolnej innej nazwie) to słownik z nazwanymi argumentami
def some_function(**kwargs):
    print(kwargs)

#wywołanie
some_function(param_x=1, param_y=2)  # ✅ {'param_x': 1, 
                                           'param_y': 2}

Wyzwanie dla złośliwych

Najdziwniejsze w tym wszystkim jest to, że wszystkie pięć rodzajów parametrów można wrzucić do jednej funkcji. Ale tylko w określonej kolejności. Inaczej Python się pogubi. I dziwisz mu się? Każdy by się pogubił przy takim natłoku opcji.

Oto nasze wyzwanie:

Jeśli jesteś wyjątkowo złośliwy i chcesz być zapamiętany przez cały zespół i wszystkich (powtórzmy: WSZYSTKICH) devów, którzy kiedykolwiek będą pracować z Twoim kodem, stwórz metodę, która wykorzystuje wszystkie pięć typów parametrów. I nie dodawaj wartości domyślnych. Albo dodaj – i tak będą Cię wytykać palcami!

def funkcja_ostatecznej_nienawiści(
    a, b, /,           # 1. positional-only
    c, d,              # 2. positional-or-keyword
    *args,             # 3. variadic positional
    e, f,              # 4. keyword-only (wszystko po *)
    **kwargs           # 5. variadic keyword
):
    pass

#wywołanie
funkcja_ostatecznej_nienawiści(
    1, 2, 3, 4, 5, 6, 7, e=8, f=9, kwark_g=10, kwark_h=11
)
# 1-4 to poszczególne zmienne, 5, 6, 7 to krotka, a kwarki będą słownikiem.

UWAGA! Zauważ, że nie ma gwiazdki przed parametrami e i f – czy to znaczy, że to domyślne parametry pythonowe? Nie! Gwiazdka przed parametrem args dotyczy też wszystkich parametrów, które następują po nim! To co? Challenge accepted?

Wartości domyślne

Wartości domyślne to takie wartości, które funkcja użyje automatycznie, jeśli nie przekażesz ich podczas wywołania.

  • Wartości domyślne muszą być na końcu listy parametrów.
  • Możesz mieć wiele wartości domyślnych w jednej funkcji, ale tylko po jednej na parametr.
  • Możesz podawać nazwane argumenty przy wywołaniu.

Pamiętasz nasz kod z początku tego tutka?

def powiedz_czesc(imie: str = "Nieznajomy") -> str:
    """Zwraca powitanie dla podanego imienia."""
    return f"Cześć, {imie}!"

#wywołanie
print(powiedz_czesc("Ala"))         # 👉 Cześć, Ala!
print(powiedz_czesc())              # 👉 Cześć, Nieznajomy!

Uwaga! Argument domyślny powinien być niemutowalny (None, liczba, łańcuch, krotka).

I jeszcze jedno: wartość domyślna jest tworzona raz – w momencie definicji funkcji. Jeśli wywołujesz tę samą metodę kilkukrotnie, Python użyje tej samej (nie takiej samej – TEJ SAMEJ!) wartości domyślnej każdego wywołania.

❌ Niezalecane:
def dodaj_element(element, lista=[]):
    lista.append(element)
    return lista

#wywołanie
print(dodaj_element(1))  # 👉 [1]
print(dodaj_element(2))  # 👉 [1, 2]

✅Zalecane:
def dodaj_element_lepiej(element, lista=None):
    if lista is None:
        lista = []
    lista.append(element)
    return lista

#wywołanie
print(dodaj_element_lepiej(1))  # 👉 [1]
print(dodaj_element_lepiej(2))  # 👉 [2]

W pierwszym przypadku przekazujemy pustą listę jako wartość domyślną parametru lista. Ta pusta lista zostanie stworzona w momencie wygenerowania metody (kiedy algorytm odczyta definicję funkcji). I tylko wtedy. Jeśli następnie wywołujemy kilkukrotnie metodę dodaj_element, Python za każdym razem bierze tę samą listę (do której najpierw dodaliśmy element 1, a później element 2).

Zdecydowanie lepiej jest przekazać None jako wartość domyślną parametru lista i stworzyć ją za pomocą instrukcji warunkowej wewnątrze funkcji, tak jak to zrobiono w drugim przypadku. Dzięki temu lista jest tworzona na nowo za każdym razem, kiedy funkcja jest wywoływana.

Adnotacje typów

Adnotacje typów (ang. type annotations) to mechanizm wprowadzony w Pythonie 3.0, który umożliwia jawne wskazanie, jakiego typu wartości oczekuje funkcja (lub zmienna) oraz co zwraca funkcja.

Choć nie są obowiązkowe i nie mają wpływu na działanie programu w czasie wykonywania, stanowią silne narzędzie dokumentacyjne i wspomagające analizę statyczną kodu.

Po co stosować adnotacje?

pomyśl o ludzkości. typuj

Oprócz najważniejszego powodu, żebyś przypadkiem nie wcisnął_ęła stringa do funkcji ustalającej współczynnik uczenia i stał_a się pośmiewiskiem całego zespołu? (To kompletnie, czysto teoretyczna, absolutnie niemożliwa sytuacja w zespole produkcyjnym. Nie mam pojęcia, skąd mi to przyszło do głowy… 😮)

Korzyści stosowania adnotacji:

  • łatwiejsze debugowanie i refaktoryzacja
  • integracja z IDE (np. VS Code, PyCharm)
  • analiza statyczna (np. mypy, pyright)

Rada! Nawet jeśli nienawidzisz typów (i ewidentnie wszystkich ludzi, którzy będą korzystać z Twojego kodu!) i nie zamierzasz stosować typów, rozważ ich stosowanie przynajmniej w tych funkcjach i metodach, które mają być publicznym API.

Podsumowanie

Jeśli myślisz, że niniejszy tutek był zbyt obszerny i teraz już wiesz absolutnie wszystko, co warto wiedzieć na temat funkcji w Pythonie, to muszę Cię zmartwić – jest jeszcze kilka drobnych i nie tak drobnych tematów, które będziemy musieli przynajmniej ugryźć, żeby naprawdę dobrze poznać funkcje i ich możliwości.

Na swoją obronę powiem, że funkcje to chyba najważniejsze (obok klas) narzędzie obiektowości, dzięki którym możesz zmienić kod-makaron w kompletny, dojrzały i porządnie napisany program.

Tymczasem poczekaj, aż mózg Ci przestanie parować, a potem wpadnij do Colaba, by przejrzeć kilka przykładów i zrobić kilka ćwiczeń. Następnie zgłoś się tu po swój medal Ultimate Python Function Master.


Co dalej?

Zapisz się do naszego newslettera, żeby nigdy nie przegapić żadnego wartościowego artykułu.

Zajrzyj do sekcji Kariera w AI, gdzie znajdziesz konkretne materiały o zmianach na rynku pracy – w Polsce i na świecie – oraz ścieżkach kariery związanych ze sztuczną inteligencją (nie tylko jako programista!).

→ A jeśli chcesz pisać modele i pracować jako Architekt AI, ale nie wiesz, od czego zacząć (lub utknąłeś gdzieś na ścieżce), odwiedź dział Nauka AI – czeka tam wiedza, ciekawostki i realne wsparcie.


! Uwaga

Niniejszy ebook ma charakter informacyjny i edukacyjny. Nie stanowi porady prawnej ani oferty pracy w rozumieniu przepisów krajowych lub unijnych.
Przy tworzeniu niniejszego artykułu korzystano ze wsparcia narzędzi opartych na sztucznej inteligencji – m.in. w zakresie porządkowania treści, analizy źródeł, przyspieszenia redakcji i wyszukiwania źródeł Jednak wszelkie decyzje dotycząca treści, interpretacji i ostatecznej formy zostały podjęte przez człowieka.

Podziel się swoją opinią

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *