course

Funkcje są kluczową częścią języka Python: mogłeś już spotkać i używać wielu świetnych funkcji wbudowanych w język Python lub dostarczanych przez jego ekosystem bibliotek. Jednak jako data scientist będziesz stale pisać własne funkcje, by rozwiązywać problemy, które stawia przed tobą twoje dane.
Ten samouczek używa składni Pythona 3. Wszystkie przykłady działają w Pythonie 3.10+ i zostały zaktualizowane do nowoczesnych konwencji (f-stringi, podpowiedzi typów, parametry tylko pozycyjne i tylko słowne). Obecne stabilne wydanie to Python 3.14.
Aby łatwo uruchomić u siebie cały kod z przykładów w tym samouczku, możesz za darmo utworzyć zeszyt w DataLab z preinstalowanym Pythonem i wszystkimi próbkami kodu. Jeśli chcesz poćwiczyć pisanie funkcji w Pythonie, zajrzyj do tego praktycznego ćwiczenia DataCamp albo wypróbuj nasz kurs Python Data Science Toolbox!
Funkcje w Pythonie
W programowaniu używasz funkcji, aby zgrupować zestaw instrukcji, których chcesz używać wielokrotnie lub które z uwagi na swoją złożoność lepiej zamknąć w podprogramie i wywoływać w razie potrzeby. Oznacza to, że funkcja to fragment kodu napisany w celu wykonania określonego zadania. Do wykonania tego zadania funkcja może potrzebować wielu danych wejściowych lub nie. Po zakończeniu zadania funkcja może zwracać jedną lub więcej wartości albo nie zwracać żadnej.
W Pythonie są trzy typy funkcji:
-
Funkcje wbudowane, takie jak
help()do proszenia o pomoc,min()do pobierania wartości minimalnej,print()do wypisywania obiektu w terminalu,… Przegląd większej liczby takich funkcji znajdziesz tutaj. -
Funkcje definiowane przez użytkownika (UDF), czyli funkcje tworzone przez użytkowników, aby sobie pomóc; oraz
-
Funkcje anonimowe, nazywane też funkcjami lambda, ponieważ nie są deklarowane standardowym słowem kluczowym
def.
Funkcje a metody
Metoda to funkcja będąca częścią klasy. Uzyskujesz do niej dostęp przez instancję lub obiekt tej klasy. Funkcja nie ma tego ograniczenia: odnosi się po prostu do samodzielnej funkcji. To znaczy, że wszystkie metody są funkcjami, ale nie wszystkie funkcje są metodami.
Rozważ ten przykład, w którym najpierw definiujesz funkcję plus(), a potem klasę Summation z metodą sum():
Jeśli teraz chcesz wywołać metodę sum() będącą częścią klasy Summation, najpierw musisz zdefiniować instancję lub obiekt tej klasy. Zdefiniujmy więc taki obiekt:
Pamiętaj, że to tworzenie instancji nie jest potrzebne, gdy chcesz wywołać funkcję plus()! Bez problemu wykonasz plus(1,2) w bloku kodu DataCamp Light!
Parametry a argumenty
Parametry to nazwy używane przy definiowaniu funkcji lub metody, do których zostaną odwzorowane argumenty. Innymi słowy, argumenty to rzeczy przekazywane przy każdym wywołaniu funkcji lub metody, podczas gdy kod funkcji lub metody odnosi się do argumentów poprzez ich nazwy parametrów.
Rozważ poniższy przykład i wróć do powyższego bloku DataCamp Light: przekazujesz dwa argumenty do metody sum() klasy Summation, mimo że wcześniej zdefiniowałeś trzy parametry, mianowicie self, a i b.
Co stało się z self?
Pierwszy argument każdej metody klasy to zawsze odwołanie do bieżącej instancji klasy, która w tym przypadku to Summation. Zwyczajowo ten argument nazywa się self.
To wszystko oznacza, że w tym przypadku nie przekazujesz odwołania do self, ponieważ self jest nazwą parametru dla niejawnie przekazywanego argumentu, który odnosi się do instancji, przez którą wywoływana jest metoda. Jest on wstawiany niejawnie do listy argumentów.
Jak zdefiniować funkcję: funkcje użytkownika (UDF)
Cztery kroki definiowania funkcji w Pythonie są następujące:
-
Użyj słowa kluczowego
def, aby zadeklarować funkcję, a następnie podaj jej nazwę. -
Dodaj parametry do funkcji: powinny znajdować się w nawiasach funkcji. Zakończ linię dwukropkiem.
-
Dodaj instrukcje, które funkcja ma wykonać.
-
Zakończ funkcję instrukcją return, jeśli funkcja ma coś zwracać. Bez instrukcji return twoja funkcja zwróci obiekt
None.
Oczywiście twoje funkcje będą z czasem bardziej złożone: możesz dodawać pętle for, sterowanie przepływem,… i więcej, aby je dopracować:
def hello():
name = input("Enter your name: ")
if name:
print(f"Hello {name}")
else:
print("Hello World")
hello()
W powyższej funkcji prosisz użytkownika o podanie imienia. Jeśli imię nie zostanie podane, funkcja wydrukuje „Hello World”. W przeciwnym razie użytkownik otrzyma spersonalizowane „Hello”.
Pamiętaj też, że możesz zdefiniować jeden lub więcej parametrów funkcji dla swojej UDF. Dowiesz się o tym więcej w sekcji o argumentach funkcji. Dodatkowo możesz zwracać jedną lub wiele wartości, albo nie zwracać nic.
Instrukcja return
Zauważ, że skoro w twojej UDF hello() coś wypisujesz, tak naprawdę nie musisz tego zwracać. Nie będzie różnicy między powyższą funkcją a tą:
Jednak jeśli chcesz dalej pracować z wynikiem swojej funkcji i wypróbować na nim jakieś operacje, musisz użyć instrukcji return, by faktycznie zwrócić wartość, np. string, liczbę całkowitą, …. Rozważ poniższy scenariusz, w którym hello() zwraca łańcuch "hello", podczas gdy funkcja hello_noreturn() zwraca None:
Druga funkcja zwraca błąd, ponieważ nie możesz wykonywać operacji na None. Otrzymasz TypeError mówiący, że nie można wykonać operacji mnożenia dla NoneType (czyli None zwróconego przez hello_noreturn()) i int (2).
Wskazówka funkcje natychmiast kończą działanie, gdy napotkają instrukcję return, nawet jeśli oznacza to, że nie zwrócą żadnej wartości:
Warto też wspomnieć, że korzystając z instrukcji return, możesz zwrócić wiele wartości. Aby to zrobić, użyj krotek.
Pamiętaj, że ta struktura danych jest bardzo podobna do listy: może zawierać wiele wartości. Jednak krotki są niemodyfikowalne, co oznacza, że nie możesz zmieniać żadnych wartości w nich przechowywanych! Tworzysz je za pomocą podwójnych nawiasów (). Możesz rozpakować krotki do wielu zmiennych przy pomocy przecinka i operatora przypisania.
Sprawdź poniższy przykład, aby zobaczyć, jak funkcja może zwracać wiele wartości:
Uwaga, że instrukcja return return sum, a da ten sam rezultat co return (sum, a): w tym pierwszym przypadku sum i a są pod spodem pakowane w krotkę!
Jak wywołać funkcję
W poprzednich sekcjach widziałeś już wiele przykładów tego, jak można wywołać funkcję. Wywołanie funkcji oznacza wykonanie zdefiniowanej funkcji — bezpośrednio z konsoli Pythona lub z innej funkcji (co zobaczysz w sekcji „Funkcje zagnieżdżone”).
Wywołaj nowo zdefiniowaną funkcję hello(), po prostu wykonując hello(), tak jak w poniższym bloku DataCamp Light:
Jak dodać docstringi do funkcji w Pythonie
Kolejny istotny aspekt pisania funkcji w Pythonie: docstringi. Docstringi opisują, co robi twoja funkcja, np. jakie wykonuje obliczenia lub jakie zwraca wartości. Te opisy służą jako dokumentacja funkcji, dzięki czemu każdy, kto czyta docstring, rozumie, co funkcja robi, bez śledzenia całego kodu w definicji funkcji.
Docstring funkcji umieszczasz w pierwszej linii po nagłówku funkcji i zamykasz go w potrójnych cudzysłowach. Odpowiedni docstring dla twojej funkcji hello() to „Prints "Hello World"”.
def hello() -> None:
"""Prints "Hello World"."""
print("Hello World")
Uwaga, że docstringi mogą być dłuższe niż ten podany tutaj jako przykład. Jeśli chcesz zgłębić docstringi bardziej, najlepiej zajrzyj do repozytoriów na Githubie bibliotek Pythona, takich jak scikit-learn czy pandas, gdzie znajdziesz mnóstwo przykładów!
Podpowiedzi typów
Blisko spokrewnione z docstringami — i niemal równie powszechne we współczesnym kodzie Pythona — są podpowiedzi typów. Od Pythona 3.5 możesz adnotować parametry funkcji i wartość zwracaną typami, jakich się oczekuje. Oto najprostszy możliwy przykład:
def plus(a: int, b: int) -> int:
return a + b
Zapis : int po każdym parametrze mówi „to powinien być integer”, a -> int po nawiasach mówi „ta funkcja zwraca integer”. Sam Python nie egzekwuje tych adnotacji w czasie działania — wciąż możesz przekazać string do plus() i Python nie zaprotestuje, dopóki coś się nie zepsuje. Ale narzędzia takie jak mypy, pyright oraz wbudowane w edytory (np. VS Code i PyCharm) sprawdzacze typów używają tych podpowiedzi, by wyłapywać błędy, zanim w ogóle uruchomisz kod.
Dla bardziej złożonych typów możesz używać bezpośrednio wbudowanych generyków (Python 3.9+) lub importować z modułu typing:
def greet(names: list[str]) -> None:
for name in names:
print(f"Hello {name}")
def find_user(user_id: int) -> dict | None:
# returns the user dict, or None if not found
...
Argumenty funkcji w Pythonie
Wcześniej poznałeś różnicę między parametrami a argumentami. W skrócie, argumenty to rzeczy przekazywane do wywołania funkcji lub metody, a kod funkcji lub metody odnosi się do argumentów poprzez nazwy parametrów. Istnieją cztery rodzaje argumentów, które mogą przyjmować funkcje UDF w Pythonie:
- Argumenty domyślne
- Argumenty wymagane
- Argumenty słowne (keyword)
- Zmienna liczba argumentów
Argumenty domyślne
Argumenty domyślne to te, które przyjmują wartość domyślną, jeśli podczas wywołania funkcji nie zostanie przekazana żadna wartość argumentu. Możesz przypisać tę wartość domyślną operatorem =, tak jak w poniższym przykładzie:
Argumenty wymagane
Jak sama nazwa wskazuje, wymagane argumenty UDF to te, które muszą się znaleźć. Należy je przekazać podczas wywołania funkcji i w dokładnie właściwej kolejności, tak jak w poniższym przykładzie:
Potrzebujesz argumentów odwzorowujących się na parametry a oraz b, aby wywołać funkcję bez błędów. Jeśli zamienisz miejscami a i b, wynik nie będzie inny, ale może się zmienić, jeśli zmienisz plus() na następujące:
Argumenty słowne (keyword)
Jeśli chcesz mieć pewność, że wywołujesz wszystkie parametry we właściwej kolejności, możesz użyć w wywołaniu funkcji argumentów słownych. Używasz ich, aby zidentyfikować argumenty po nazwie parametru. Weźmy przykład z góry, by to lepiej zobrazować:
Zauważ, że używając argumentów słownych, możesz też zamienić kolejność parametrów i nadal otrzymasz ten sam wynik przy wykonaniu funkcji:
Zmienna liczba argumentów
Gdy nie znasz dokładnej liczby argumentów, które chcesz przekazać do funkcji, możesz użyć poniższej składni z *args:
Gwiazdka (*) jest umieszczona przed nazwą zmiennej, która przechowuje wartości wszystkich niesłownych argumentów zmiennej długości. Zauważ, że równie dobrze mogłeś przekazać *varint, *var_int_args lub inną nazwę do funkcji plus().
Wskazówka: spróbuj zastąpić *args inną nazwą z gwiazdką. Zobaczysz, że powyższy kod nadal działa!
Widzisz, że powyższa funkcja używa wbudowanej funkcji Pythona sum() do zsumowania wszystkich argumentów przekazanych do plus().
Zmienne globalne a lokalne
Ogólnie rzecz biorąc, zmienne zdefiniowane wewnątrz ciała funkcji mają zasięg lokalny, a te zdefiniowane na zewnątrz — zasięg globalny. Oznacza to, że zmienne lokalne są zdefiniowane w bloku funkcji i można się do nich odwołać tylko wewnątrz tej funkcji, podczas gdy zmienne globalne są dostępne dla wszystkich funkcji w twoim skrypcie:
Zobaczysz, że otrzymasz NameError mówiący, że name 'total' is not defined, gdy spróbujesz wypisać zmienną lokalną total zdefiniowaną wewnątrz ciała funkcji. Zmienna init natomiast może zostać wypisana bez problemów.
Parametry tylko pozycyjne i tylko słowne
Od Pythona 3.8 możesz lepiej kontrolować sposób przekazywania argumentów, używając dwóch specjalnych znaczników w sygnaturze funkcji: / i *. Wszystko przed / może być przekazywane wyłącznie pozycyjnie; wszystko po * może być przekazywane wyłącznie słownie (przez keyword).
def greet(name, /, greeting="Hello", *, punctuation="!"):
print(f"{greeting} {name}{punctuation}")
Oto jak to wygląda przy wywołaniu:
greet("Alice") # działa
greet("Alice", greeting="Hi") # działa
greet("Alice", "Hi", punctuation="?") # działa
greet(name="Alice") # TypeError: name is positional-only
greet("Alice", "Hi", "?") # TypeError: punctuation is keyword-only
Po co ci to? Z dwóch głównych powodów.
Po pierwsze, parametry tylko pozycyjne pozwalają ci później zmienić ich nazwy bez psucia niczyjego kodu — ponieważ nikt nie może używać nazwy parametru jako słowa kluczowego, możesz ją swobodnie zmienić.
Po drugie, parametry tylko słowne zmuszają wywołujących do bycia jednoznacznymi w tym, co przekazują, co zwiększa czytelność wywołań, gdy masz kilka opcjonalnych flag lub ustawień.
Krótko mówiąc, to czysty sposób na egzekwowanie intencji.
Funkcje anonimowe w Pythonie
Funkcje anonimowe w Pythonie nazywa się też funkcjami lambda, ponieważ zamiast deklarować je standardowym słowem kluczowym def, używasz słowa lambda.
W powyższym bloku DataCamp Light lambda x: x*2 to funkcja anonimowa, czyli lambda. x to argument, a x*2 to wyrażenie lub instrukcja, która jest obliczana i zwracana. Cechą szczególną tej funkcji jest to, że nie ma nazwy, w przeciwieństwie do przykładów z pierwszej części tego samouczka. Gdybyś miał zapisać powyższą funkcję jako UDF, rezultat byłby następujący:
def double(x):
return x*2
Rozważmy jeszcze przykład funkcji lambda z dwoma argumentami:
Używasz funkcji anonimowych, gdy potrzebujesz bezimiennej funkcji na krótko, tworzonej w czasie wykonywania. Konteksty, w których jest to przydatne, to praca z filter(), map() i reduce():
Funkcja filter() filtruje, jak sama nazwa wskazuje, oryginalną listę wejściową my_list na podstawie kryterium >10. Z kolei map() stosuje funkcję do wszystkich elementów listy my_list. W tym przypadku mnożysz wszystkie elementy przez 2.
Zauważ, że funkcja reduce() jest częścią biblioteki functools. Używasz jej kumulacyjnie do elementów listy my_list, od lewej do prawej, i redukujesz sekwencję do pojedynczej wartości, w tym przypadku 55.
Używanie main() jako funkcji w Pythonie
Jeśli masz doświadczenie z innymi językami programowania, takimi jak Java, wiesz, że funkcja main jest wymagana do wykonywania funkcji. Jak widziałeś w powyższych przykładach, w Pythonie nie jest to konieczne. Jednak uwzględnienie funkcji main() w twoim programie w Pythonie może pomóc logicznie uporządkować kod — wszystkie najważniejsze elementy zawierasz w tej funkcji main().
Możesz łatwo zdefiniować funkcję main() i wywołać ją tak samo, jak inne funkcje powyżej:
Jednak w obecnej postaci kod twojej funkcji main() zostanie wywołany, gdy zaimportujesz go jako moduł. Aby mieć pewność, że tak się nie stanie, wywołujesz funkcję main(), gdy __name__ == '__main__'.
Oznacza to, że kod z powyższego bloku staje się:
Uwaga, że oprócz funkcji __main__ masz też funkcję __init__, która inicjalizuje instancję klasy lub obiekt. Mówiąc prościej, działa jak konstruktor lub inicjalizator i jest automatycznie wywoływana, gdy tworzysz nową instancję klasy. Dzięki tej funkcji nowo utworzony obiekt jest przypisany do parametru self, który widziałeś wcześniej w tym samouczku. Spójrz na poniższy przykład:
class Dog:
"""A simple Dog class.
Args:
legs: Number of legs so that the dog can walk.
color: The color of the fur.
"""
def __init__(self, legs: int, color: str) -> None:
self.legs = legs
self.color = color
def bark(self) -> str:
return "bark" * 2
if __name__ == "__main__":
dog = Dog(4, "brown")
print(dog.bark())
Ćwicz dalej funkcje w Pythonie
Gratulacje! Udało ci się przejść przez ten krótki samouczek o funkcjach w Pythonie. Jeśli chcesz powtórzyć inne podstawy programowania w Pythonie, nie przegap kursu Data Types for Data Science, w którym utrwalisz i poćwiczysz wiedzę o listach, słownikach, krotkach, zbiorach i datach i czasie.
Najczęściej zadawane pytania o funkcje w Pythonie
Czym jest funkcja w Pythonie?
Funkcja to wielokrotnego użytku blok kodu wykonujący określone zadanie. Może przyjmować dane wejściowe, przetwarzać je i zwracać wyniki.
Jak zdefiniować funkcję w Pythonie?
Aby zdefiniować funkcję w Pythonie, użyj słowa kluczowego def, nadaj funkcji nazwę, opcjonalnie dodaj parametry w nawiasach, wpisz kod i opcjonalnie return wartość.
Jaka jest różnica między funkcjami a metodami w Pythonie?
Funkcje są samodzielne, a metody należą do klas. Wszystkie metody są funkcjami, ale nie wszystkie funkcje są metodami.
Jakie są typy funkcji w Pythonie?
Python ma funkcje wbudowane (np. print()), funkcje definiowane przez użytkownika (twoje własne) i funkcje anonimowe (krótkotrwałe funkcje lambda).
Jaka jest różnica między parametrami a argumentami?
Parametry to pola w definicji funkcji, a argumenty to rzeczywiste wartości przekazywane przy jej wywołaniu.
Czym jest funkcja lambda?
Funkcja lambda to jednowierszowa, bezimienna funkcja do szybkich zadań.
Po co używać funkcji __main__?
Funkcja __main__ pomaga uporządkować kod i zapewnia, że określone części uruchomią się tylko wtedy, gdy skrypt jest wykonywany bezpośrednio, a nie przy imporcie.
Jaka jest różnica między zmiennymi globalnymi a lokalnymi?
Zmienne globalne działają wszędzie, a lokalne żyją tylko wewnątrz swojej funkcji.