Funções sobrecarregadas em Python

93

É possível ter funções sobrecarregadas em Python?

Em C # eu faria algo como

void myfunction (int first, string second)
{
    // Some code
}

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

E então, quando chamo a função, ela diferencia as duas com base no número de argumentos. É possível fazer algo semelhante em Python?

Trcx
fonte
Esta parece ser uma possível postagem duplicada. Além disso, não sinalize como C #, pois a pergunta não tem a ver com C #. função-sobrecarga-em-python-ausente
Jethro
possível duplicata de sobrecarga
Li0liQ
possível duplicata da sobrecarga da função Python
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respostas:

104

EDITAR Para as novas funções genéricas de despacho único no Python 3.4, consulte http://www.python.org/dev/peps/pep-0443/

Em geral, você não precisa sobrecarregar funções em Python. Python é tipado dinamicamente e suporta argumentos opcionais para funções.

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
agf
fonte
3
Mas observe que chamar funções diferentes com base no tipo de argumento é muito mais difícil (embora não impossível).
Andrew Jaffe,
9
Bem, há uma diferença entre sobrecarga / polimorfismo e condicionais. Você quer dizer que não precisamos do polimorfismo, uma vez que temos os condicionais?
Val
1
@Val Estou dizendo, basicamente, que em uma linguagem digitada dinamicamente você não precisa ser sobrecarregado como um recurso de linguagem porque pode emulá-lo trivialmente no código e, portanto, obter polimorfismo dessa forma.
agf
1
@Val Estou dizendo que entre os argumentos opcionais e os tipos dinâmicos da maneira como você os tem no Python, você não precisa da sobrecarga do método do estilo Java para atingir o polimorfismo.
agf
3
@navidoo Eu diria que não é uma boa ideia - uma função não deve retornar tipos de coisas completamente diferentes. No entanto, você sempre pode definir uma função do gerador local dentro da função principal, chamá-la e retornar o gerador resultante - do lado de fora, será o mesmo como se a função principal fosse um gerador. Exemplo aqui.
agf
51

em python normal, você não pode fazer o que quiser. existem duas aproximações:

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

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

no entanto, se você realmente quiser fazer isso, certamente poderá fazê-lo funcionar (correndo o risco de ofender os tradicionalistas; o). em resumo, você escreveria uma wrapper(*args)função que verifica o número de argumentos e delegados conforme apropriado. esse tipo de "hack" geralmente é feito por meio de decoradores. neste caso, você poderia conseguir algo como:

from typing import overload

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

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

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

e você implementaria isso fazendo a overload(first_fn) função (ou construtor) retornar um objeto que pode ser chamado, onde o __call__(*args) método faz a delegação explicada acima e o overload(another_fn) método adiciona funções extras que podem ser delegadas.

você pode ver um exemplo de algo semelhante aqui http://acooke.org/pytyp/pytyp.spec.dispatch.html, mas isso está sobrecarregando os métodos por tipo. é uma abordagem muito semelhante ...

ATUALIZAÇÃO: e algo semelhante (usando tipos de argumento) está sendo adicionado ao python 3 - http://www.python.org/dev/peps/pep-0443/

Andrew Cooke
fonte
O rangebuiltin usa sobrecarga, então é realmente um hack? github.com/python/typeshed/blob/master/stdlib/2and3/…
CptJero
9

Sim é possivel. Escrevi o código abaixo no Python 3.2.1:

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

Uso:

myfunction=overload(no_arg_func, one_arg_func, two_arg_func)

Observe que o lambda retornado pelas overloadfunções escolhe a função a ser chamada dependendo do número de argumentos não nomeados .

A solução não é perfeita, mas no momento não consigo escrever nada melhor.

GingerPlusPlus
fonte
1

Não é possível diretamente. Você pode usar verificações explícitas de tipo nos argumentos fornecidos, embora isso seja geralmente desaprovado.

Python é dinâmico. Se você não tiver certeza do que um objeto pode fazer, tente: e chame um método nele, exceto: erros.

Se você não precisa sobrecarregar com base em tipos, mas apenas em número de argumentos, use argumentos de palavra-chave.

Jürgen Strobel
fonte
3
Eu não acho que ele sabia sobre argumentos opcionais.
agf
0

sobrecarregar métodos é complicado em python. No entanto, pode haver uso de passagem de variáveis ​​dict, list ou primitivas.

Eu tentei algo para meus casos de uso, isso pode ajudar aqui a entender as pessoas a sobrecarregar os métodos.

Vamos dar o exemplo de uso em um dos encadeamentos stackoverflow:

um método de sobrecarga de classe com a chamada de métodos de classes diferentes.

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

passe os argumentos da classe remota:

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

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

Portanto, o manuseio está sendo alcançado para lista, dicionário ou variáveis ​​primitivas de sobrecarga de método.

experimente para seus códigos

shashankS
fonte