Przeciążone funkcje w Pythonie?


91

Czy w Pythonie można mieć przeciążone funkcje? W C # zrobiłbym coś takiego

void myfunction (int first, string second)
{
//some code
}
void myfunction (int first, string second , float third)
{
//some different code
}

a potem, gdy wywołuję funkcję, rozróżnia te dwie na podstawie liczby argumentów. Czy można zrobić coś podobnego w Pythonie?


Wygląda na to, że może to być zduplikowany post. Nie należy również oznaczać jako C #, ponieważ pytanie nie ma związku z C #. function-overloading-in-python-missing
Jethro


Odpowiedzi:


103

EDYCJA Aby zapoznać się z nowymi funkcjami ogólnymi do pojedynczego wysyłania w Pythonie 3.4, zobacz http://www.python.org/dev/peps/pep-0443/

Zwykle nie ma potrzeby przeciążania funkcji w Pythonie. Python jest typowany dynamicznie i obsługuje opcjonalne argumenty funkcji.

def myfunction(first, second, third = None):
    if third is None:
        #just use first and second
    else:
        #use all three

myfunction(1, 2) # third will be None, so enter the 'if' clause
myfunction(3, 4, 5) # third isn't None, it's 5, so enter the 'else' clause

3
Należy jednak pamiętać, że wywoływanie różnych funkcji na podstawie typu argumentów jest znacznie trudniejsze (choć nie niemożliwe).
Andrew Jaffe,

9
Cóż, istnieje różnica między przeciążeniem / polimorfizmem a warunkami. Czy masz na myśli, że nie potrzebujemy polimorfizmu, ponieważ mamy warunki warunkowe?
Val

1
@Val Mówię w zasadzie, że w języku dynamicznie wpisywanym nie potrzebujesz przeciążania jako funkcji języka, ponieważ możesz trywialnie emulować to w kodzie, a więc można uzyskać w ten sposób polimorfizm.
agf

1
@Val Mówię, że pomiędzy opcjonalnymi argumentami i typami dynamicznymi, tak jak je masz w Pythonie, nie potrzebujesz przeciążania metod w stylu Java, aby osiągnąć polimorfizm.
agf

3
@navidoo Twierdziłbym, że to nie jest dobry pomysł - funkcja nie powinna zwracać zupełnie innych typów rzeczy. Jednak zawsze możesz zdefiniować lokalną funkcję generatora wewnątrz funkcji main, wywołać ją i zwrócić wynikowy generator - z zewnątrz będzie taki sam, jak gdyby główną funkcją był generator. Przykład tutaj.
agf

50

w normalnym Pythonie nie możesz robić tego, co chcesz. istnieją dwa bliskie przybliżenia:

def myfunction(first, second, *args):
    # args is a tuple of extra arguments

def myfunction(first, second, third=None):
    # third is optional

jeśli jednak naprawdę chcesz to zrobić, z pewnością możesz sprawić, że zadziała (ryzykując urazę tradycjonalistów; o). w skrócie, można napisać wrapper(*args)funkcję, która sprawdza odpowiednio liczbę argumentów i delegatów. ten rodzaj „hakowania” jest zwykle wykonywany za pomocą dekoratorów. w tym przypadku możesz osiągnąć coś takiego:

from typing import overload

@overload
def myfunction(first):
    ....

@myfunction.overload
def myfunction(first, second):
    ....

@myfunction.overload
def myfunction(first, second, third):
    ....

i zaimplementowałbyś to, sprawiając, że overload(first_fn) funkcja (lub konstruktor) zwraca wywoływalny obiekt, w którym __call__(*args) metoda wykonuje delegację wyjaśnioną powyżej, a overload(another_fn) metoda dodaje dodatkowe funkcje, które mogą być delegowane.

możesz zobaczyć przykład czegoś podobnego tutaj http://acooke.org/pytyp/pytyp.spec.dispatch.html, ale jest to przeciążanie metod według typu. to bardzo podobne podejście ...

UPDATE: i coś podobnego (używając typów argumentów) jest dodawane do Pythona 3 - http://www.python.org/dev/peps/pep-0443/


rangeWbudowane wykorzystuje przeciążenie, więc jest to naprawdę hack? github.com/python/typeshed/blob/master/stdlib/2and3/…
CptJero

9

Tak, to możliwe. Poniżej napisałem kod w Pythonie 3.2.1:

def overload(*functions):
    return lambda *args, **kwargs: functions[len(args)](*args, **kwargs)

Stosowanie:

myfunction=overload(no_arg_func, one_arg_func, two_arg_func)

Zwróć uwagę, że lambda zwracane przez overloadfunkcje wybierają funkcję do wywołania w zależności od liczby nienazwanych argumentów.

Rozwiązanie nie jest idealne, ale w tej chwili nie mogę napisać nic lepszego.


1

Niemożliwe bezpośrednio. Możesz jednak użyć jawnego sprawdzenia typu dla podanych argumentów, chociaż generalnie jest to mile widziane.

Python jest dynamiczny. Jeśli nie jesteś pewien, co może zrobić obiekt, po prostu spróbuj: i wywołaj na nim metodę, a następnie z wyjątkiem: błędów.

Jeśli nie musisz przeciążać na podstawie typów, ale tylko na podstawie liczby argumentów, użyj argumentów słów kluczowych.


3
Nie sądzę, żeby wiedział o opcjonalnych argumentach.
agf

0

przeciążanie metod jest trudne w Pythonie. Jednak może być użycie przekazywania dyktowania, listy lub zmiennych pierwotnych.

Próbowałem czegoś dla moich przypadków użycia, może to pomóc w zrozumieniu ludzi, którzy przeciążają metody.

Weźmy przykład użycia w jednym z wątków stackoverflow:

metoda przeciążania klasy z wywołaniem metod z innej klasy.

def add_bullet(sprite=None, start=None, headto=None, spead=None, acceleration=None):

przekazać argumenty ze zdalnej klasy:

add_bullet(sprite = 'test', start=Yes,headto={'lat':10.6666,'long':10.6666},accelaration=10.6}

LUB add_bullet(sprite = 'test', start=Yes,headto={'lat':10.6666,'long':10.6666},speed=['10','20,'30']}

Tak więc obsługa zmiennych list, słownikowych lub prymitywnych jest uzyskiwana w wyniku przeciążenia metod.

wypróbuj to dla swoich kodów

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.