V programovacích jazycích se setkáváme s konceptem přetěžování funkcí, což je mechanismus umožňující definovat několik variant téže funkce. Tyto varianty sdílejí společné jméno, avšak liší se svou implementací a specifickými signaturami.
Tato technika je užitečná, protože umožňuje provádět různé akce v závislosti na typu a počtu vstupních parametrů, které jsou dané funkci předány.
Na rozdíl od jazyků jako C++ nebo Java, Python nativně přetěžování funkcí nepodporuje. Nicméně, existují různé způsoby, jak podobnou funkcionalitu v Pythonu napodobit.
Jak Python nakládá s přetížením funkcí?
V Pythonu je možné definovat funkci opakovaně, pokaždé s odlišnými parametry, datovými typy nebo kombinací obojího. Nicméně, Python si zapamatuje a používá pouze poslední definici dané funkce. Podívejme se na příklad:
def matematicke_operace(a, b):
return a - b def matematicke_operace(a, b, c, d):
return a + b - c * d print(matematicke_operace(1, 2, 3, 5)) print(matematicke_operace(1, 2))
Objektově orientované jazyky, jako je Java, běžně podporují přetěžování funkcí a metod. Metoda je v podstatě funkce definovaná uvnitř třídy.
V uvedeném kódu Python vezme v úvahu pouze druhou definici funkce `matematicke_operace()`, pokud se ji pokusíme v programu zavolat. Pokus o volání funkce se dvěma argumenty, jak byla definována jako první, vyvolá chybu „chybí požadované poziční argumenty“.
Pokud zavoláme funkci se čtyřmi argumenty, chyba se nevyskytne. To ukazuje, že Python přepsal funkci její poslední verzí. Nejedná se o skutečné chování přetěžování, proto je potřeba se s tím vypořádat jinak.
Z toho vyplývá, že Python ve své základní podobě přetěžování funkcí nepodporuje, ale existují triky, jak jeho chování napodobit v našich programech.
Metoda 1: Využití volitelných parametrů nebo výchozích argumentů
Přetížení můžeme simulovat definováním funkce s výchozími hodnotami argumentů. Zde je příklad:
def matematicke_operace(a, b=0, c=0):
"""
Argumenty:
a: První číslo.
b: Druhé číslo (volitelné).
c: Třetí číslo (volitelné).
"""
return a - b + c
Tato funkce má tři parametry, přičemž dva z nich mají nastavené výchozí hodnoty. To nám umožňuje volat ji s jedním až třemi argumenty:
print(matematicke_operace(1)) print(matematicke_operace(2, 5)) print(matematicke_operace(10, 3, 4))
I když tento postup umožňuje funkci volat různými způsoby, z dlouhodobého hlediska nemusí být příliš efektivní. Zde jsou některá z jeho omezení:
- Můžeme předávat argumenty pouze typu celá čísla nebo čísla s plovoucí desetinnou čárkou.
- Chování funkce se výrazně nemění. Například, nemůžeme měnit její chování tak, aby počítala obsah geometrického útvaru, nebo dokonce jen vypsala „Hello World“.
Metoda 2: Použití proměnlivých argumentů
Pro simulaci přetěžování funkcí pomocí proměnlivých argumentů v Pythonu, použijeme parametr `*args` při definici funkce. Parametr `*args` nám dovolí předávat libovolný počet pozičních argumentů při volání naší funkce. Ukázka:
def matematicke_operace(a, *args):
"""
Argumenty:
a: První číslo.
*args: Proměnný počet argumentů (volitelné).
"""
soucin_args = 1
for num in args:
soucin_args *= num
return a - soucin_args
print(matematicke_operace(1))
print(matematicke_operace(2, 5))
print(matematicke_operace(10, 3, 4, 2, 4, 6))
Funkce výše používá dva argumenty: povinný argument `a` a argument `*args`, který umožňuje zadat libovolný počet dalších argumentů.
Přestože tato funkce může přijmout více argumentů, umí operaci násobení provést jen s proměnlivými argumenty, tj. argumenty reprezentovanými klíčovým slovem `args`.
Pokud chceme provádět více operací, je nutné zavést do kódu podmíněné příkazy, což může rychle nabrat na složitosti.
Metoda 3: Využití dekorátoru vícenásobného odeslání
Dekorátor vícenásobného odeslání je knihovna pro Python, která umožňuje definovat různé implementace nebo instance jedné funkce na základě typu jejích argumentů. To znamená, že můžeme definovat stejnou funkci s různými datovými typy a zásadně měnit její chování.
Pro využití dekorátoru vícenásobného odeslání postupujeme takto:
pip install multipledispatch
from multipledispatch import dispatch
@dispatch(datovy_typ1, datovy_typ2, datovy_typX)
def vase_funkce(a, b, c, x):
pass
Zde je příklad, který ukazuje, jak využít dekorátor vícenásobného odeslání pro přetěžování funkcí v Pythonu:
from multipledispatch import dispatch
@dispatch(int, int)
def secti(a, b):
"""
Argumenty:
a: Libovolné celé číslo.
b: Libovolné celé číslo.
"""
return a + b
@dispatch(int, list)
def secti(a, b):
"""
Argumenty:
a: Libovolné celé číslo.
b: Libovolný seznam v Pythonu.
"""
b.append(a)
return b
print(secti(1, 2))
print(secti(1, [2, 3, 4, 5, 'w', 'hotovo']))
Uvedený kód definuje dvě instance funkce `secti()`. První instance bere jako argumenty dvě celá čísla a vrací jejich součet.
Druhá verze této funkce akceptuje celé číslo a seznam. Přidá celé číslo na konec seznamu a vrátí upravený seznam.

Tento přístup k přetěžování funkcí v Pythonu nabízí velkou flexibilitu, zvláště když potřebujeme měnit chování naší metody. Více informací najdete v dokumentaci k vícenásobnému odeslání.
Nejlepší přístup k přetížení funkcí v Pythonu
Výběr přístupu k přetěžování funkcí by měl vycházet z toho, čeho se snažíme dosáhnout. Pokud náš cíl můžeme splnit s pomocí výchozích nebo proměnlivých argumentů, použití dekorátoru vícenásobného odeslání může být zbytečně složité. Nicméně, pro efektivitu a přesnost je dekorátor vícenásobného odeslání obvykle nejlepší volbou.
Tento dekorátor poskytuje čistý a flexibilní způsob, jak implementovat přetěžování funkcí v Pythonu. Umožňuje nám definovat více implementací jedné funkce na základě typů jejich argumentů.
S tímto přístupem můžeme vytvářet flexibilní funkce, které mohou akceptovat různé typy parametrů bez nutnosti používat složité podmíněné příkazy.