Zrozumienie przeciążania funkcji w Pythonie
Przeciążanie funkcji to funkcja w niektórych językach programowania, która pozwala definiować warianty tej samej funkcji. Każdy wariant ma tę samą nazwę, ale różne implementacje, z unikalnymi sygnaturami funkcji.
Metoda ta umożliwia wykonywanie różnych działań zależnych od charakteru i ilości parametrów przekazywanych do funkcji, co pozwala na większą elastyczność w programowaniu.
Python różni się od języków programowania takich jak C\+\+ i Java tym, że nie obsługuje przeciążania funkcji. Można jednak emulować tę funkcjonalność za pomocą alternatywnych środków.
Jak Python radzi sobie z przeciążaniem funkcji?
W Pythonie funkcja może być zdefiniowana wiele razy z różnymi specyfikacjami parametrów i/lub typami danych. Niemniej jednak, podczas wywoływania funkcji, Python rozpozna wyłącznie ostatnią instancję jej definicji. Przykład został przedstawiony poniżej:
def arithmetics(a, b):
return a - b
def arithmetics(a, b, c, d):
return a \\+ b - c * d
print(arithmetics(1, 2, 3, 5)) # returns -12
print(arithmetics(1, 2)) # returns missing positional arguments error
Języki programowania obiektowego, takie jak Java, często zawierają mechanizmy przeciążania funkcji i metod. Zasadniczo metody są funkcjami, które są określone w kontekście klasy.
W powyższym fragmencie kodu interpreter Pythona rozpozna wyłącznie ostatnio zadeklarowaną definicję funkcji arithmetic() podczas próby wywołania jej w projekcie. W przypadku próby wywołania funkcji z dwoma parametrami zgodnymi z jej początkową deklaracją, zostanie zgłoszony wyjątek wskazujący, że brakuje wspomnianego argumentu (argumentów) i są one wymagane do wykonania.
Wystąpienie błędu funkcji nie następuje, gdy podczas wywołania podane są cztery parametry, co wskazuje, że funkcja została zastąpiona jej najnowszą wersją w pamięci. Nie wskazuje to jednak na przeciążenie metody i wymaga innego podejścia do rozwiązania.
Python z natury nie obsługuje przeciążania funkcji; można jednak zastosować pewne techniki w swoim kodzie, aby emulować tę funkcjonalność.
Metoda 1: Używanie opcjonalnych parametrów lub domyślnych argumentów
Przeciążanie można osiągnąć poprzez implementację funkcji z domyślnymi parametrami. Przykładowy przykład jest następujący:
def arithmetics(a, b=0, c=0):
"""
Arguments:
a: The first number.
b: The second number (optional).
c: The third number (optional).
"""
return a - b \\+ c
Podana funkcja obejmuje łącznie trzy zmienne wejściowe, ale dwie z nich mają predefiniowane wartości. W związku z tym pozwala to na wywołanie funkcji z tablicą od jednego do trzech elementów argumentów.
print(arithmetics(1)) # returns 1
print(arithmetics(2, 5)) # returns -3
print(arithmetics(10, 3, 4)) # returns 11
Chociaż metoda ta oferuje różne możliwości wywołania funkcji, ostatecznie okazuje się być niezrównoważonym rozwiązaniem ze względu na kilka nieodłącznych ograniczeń.
Przekazywany argument musi być typu całkowitoliczbowego lub zmiennoprzecinkowego.
Wydaje się, że nie ma zauważalnych różnic w funkcjonalności tej konkretnej funkcji. W związku z tym nie jest ona w stanie wykonywać takich zadań, jak obliczanie powierzchni danego kształtu lub drukowanie tekstu “Hello World”.
Metoda 2: Używanie zmiennych argumentów
Aby wykorzystać przeciążanie zmiennych argumentów w Pythonie, konieczne jest włączenie parametru “args” podczas definiowania funkcji. Atrybut ten umożliwia przekazywanie wielu argumentów pozycyjnych podczas wywoływania funkcji. Przykładową demonstrację można znaleźć poniżej:
def arithmetics(a, *args):
"""
Arguments:
a: The first number.
*args: A variable number of arguments (optional).
"""
args_sum = 0
for num in args:
args_sum *= num
return a - args_sum
print(arithmetics(1)) # returns 1
print(arithmetics(2, 5)) # returns 2
print(arithmetics(10, 3, 4, 2, 4, 6)) # returns 10
Powyższa funkcja wymaga dwóch parametrów; jednego obowiązkowego parametru oznaczonego jako “a” i opcjonalnego parametru określanego jako “args”, pozwalającego na włączenie dowolnej liczby dodatkowych argumentów w razie potrzeby.
Pomimo możliwości przyjmowania wielu danych wejściowych, ta konkretna funkcja ma ograniczoną zdolność do wykonywania operacji arytmetycznych wykraczających poza zwykłe mnożenie, ponieważ stosuje proces mnożenia wyłącznie do zmiennych reprezentowanych przez słowo kluczowe args
.
Aby wykonać serię działań w kontekście programistycznym, często konieczne jest włączenie instrukcji warunkowych do kodu. Jednak wraz ze wzrostem liczby rozważanych warunków wzrasta również złożoność zadania programistycznego.
Metoda 3: Korzystanie z dekoratora Multiple Dispatch
Dekorator Multiple Dispatch to biblioteka Pythona, która umożliwia tworzenie różnych implementacji lub instancji pojedynczej funkcji w zależności od rodzaju otrzymywanych danych wejściowych. W ten sposób można utworzyć identyczne funkcje z różnymi strukturami danych i całkowicie zmienić ich zachowanie.
Aby zastosować ozdobę wysyłania wielu metod, należy przestrzegać tych protokołów:
⭐ Zainstaluj multipledispath w swoim środowisku Pythona:
pip install multipledispatch
⭐ Udekoruj swoje funkcje dekoratorem @dispatch. Dekorator @dispatch jest dekoratorem Pythona, który pozwala na implementację wielokrotnego wysyłania. Automatycznie wyśle on odpowiednią funkcję na podstawie przekazanych argumentów. Możesz użyć dekoratora @dispatch, postępując zgodnie z następującym wzorcem:
from multipledispatch import dispatch
@dispatch(data type1, data type2, data typeX)
def your_function(a, b, c, x):
pass
# perform your operations here
Rozważmy scenariusz, w którym wykorzystujemy dekorator wielokrotnego wysyłania, aby ułatwić koncepcję przeciążania funkcji w języku programowania Python:
from multipledispatch import dispatch
@dispatch(int, int)
def add(a, b):
"""
Arguments:
a: Any integer.
b: Any integer.
"""
return a \\+ b
@dispatch(int, list)
def add(a, b):
"""
Arguments:
a: Any integer.
b: Any Python list.
"""
b.append(a)
return b
# returns 3
print(add(1, 2))
# returns [2, 3, 4, 5, 'w', 'done', 1]
print(add(1, [2, 3, 4, 5, 'w', 'done']))
Wyżej wymieniony segment kodu tworzy instancję dwóch oddzielnych wystąpień funkcji add(), z których każde przyjmuje i przetwarza różne parametry. W szczególności jedno z takich wystąpień odbiera i oblicza sumę dwóch wartości liczbowych reprezentowanych jako typy danych całkowitych, ostatecznie dając wynikową sumę w postaci wyniku operacji arytmetycznej.
Naprzemiennie, kolejna iteracja tej operacji obejmuje przyjęcie dwóch parametrów; liczby całkowitej i zbioru sekwencyjnego. Następnie wspomniany parametr jest dodawany do końca serii i zwracany jako zmieniona akumulacja.
Takie podejście do przeciążania funkcji w Pythonie zapewnia dużą elastyczność, zwłaszcza jeśli trzeba zmienić zachowanie metody. Więcej informacji można znaleźć w dokumentacji wielokrotnego wysyłania .
Najlepsze podejście do przeciążania funkcji w Pythonie
Wybór odpowiedniej metodologii przeciążania funkcjonalnego powinien być zgodny z zamierzonymi celami. W przypadkach, gdy pożądany rezultat może zostać osiągnięty poprzez wykorzystanie domyślnych lub zmiennych argumentów, zastosowanie dekoratora multi-dispatch może nie być konieczne. Niemniej jednak, w większości przypadków, ten ostatni prezentuje się jako bardziej wydajne i dokładne rozwiązanie ze względu na jego zdolność do dostosowania różnych typów argumentów przy zachowaniu optymalnej wydajności.
Dostarczony dekorator oferuje eleganckie i wszechstronne podejście do implementacji przeciążania funkcji w języku programowania Python. Umożliwia on tworzenie różnych implementacji pojedynczej funkcji, w zależności od charakterystyki jej parametrów.
Wykorzystanie tej metody pozwala na rozwój wszechstronnych funkcji zdolnych do obsługi różnych typów parametrów, eliminując wymóg skomplikowanych instrukcji warunkowych w celu osiągnięcia takiej zdolności adaptacji.