¿Funciones sobrecargadas en Python?

91

¿Es posible tener funciones sobrecargadas en Python? En C # haría algo como

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

y luego, cuando llamo a la función, diferenciaría entre los dos en función del número de argumentos. ¿Es posible hacer algo similar en Python?

Trcx
fuente
Esta parece ser una posible publicación duplicada. Además, no marque como C # ya que la pregunta no tiene que ver con C #. función-sobrecarga-en-python-missing
Jethro
posible duplicado de la sobrecarga
Li0liQ
posible duplicado de la sobrecarga de funciones
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

103

EDITAR Para las nuevas funciones genéricas de despacho único en Python 3.4, consulte http://www.python.org/dev/peps/pep-0443/

Por lo general, no es necesario sobrecargar funciones en Python. Python se escribe dinámicamente y admite argumentos opcionales para funciones.

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
fuente
3
Pero tenga en cuenta que llamar a diferentes funciones según el tipo de argumentos es mucho más difícil (aunque no imposible).
Andrew Jaffe
9
Bueno, hay una diferencia entre sobrecarga / polimorfismo y condicionales. ¿Quiere decir que no necesitamos el polimorfisma ya que tenemos los condicionales?
Val
1
@Val Estoy diciendo, básicamente, que en un lenguaje escrito dinámicamente no necesitas sobrecargar como característica del lenguaje porque puedes emularlo trivialmente en código, y así puedes obtener polimorfismo de esa manera.
2013
1
@Val Estoy diciendo que entre los argumentos opcionales y los tipos dinámicos de la forma en que los tiene en Python, no necesita la sobrecarga de métodos de estilo Java para lograr polimorfismo.
2013
3
@navidoo Yo diría que eso no es una buena idea, una función no debería devolver tipos de cosas completamente diferentes. Sin embargo, siempre puede definir una función de generador local dentro de la función principal, llamarla y devolver el generador resultante; desde el exterior será igual que si la función principal fuera un generador. Ejemplo aquí.
agf
50

en Python normal no puedes hacer lo que quieres. hay dos aproximaciones cercanas:

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

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

sin embargo, si realmente desea hacer esto, ciertamente puede hacerlo funcionar (a riesgo de ofender a los tradicionalistas; o). en resumen, escribiría una wrapper(*args)función que verifique el número de argumentos y delegados según corresponda. este tipo de "pirateo" se suele realizar mediante decoradores. en este caso podrías lograr algo como:

from typing import overload

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

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

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

e implementaría esto haciendo que la overload(first_fn) función (o constructor) devuelva un objeto invocable donde el __call__(*args) método realiza la delegación explicada anteriormente y el overload(another_fn) método agrega funciones adicionales a las que se puede delegar.

puede ver un ejemplo de algo similar aquí http://acooke.org/pytyp/pytyp.spec.dispatch.html pero eso es sobrecargar métodos por tipo. es un enfoque muy similar ...

ACTUALIZACIÓN: y se está agregando algo similar (usando tipos de argumentos) a Python 3 - http://www.python.org/dev/peps/pep-0443/

Andrew Cooke
fuente
El rangeincorporado usa sobrecarga, entonces, ¿es realmente un truco? github.com/python/typeshed/blob/master/stdlib/2and3/…
CptJero
9

Si es posible. Escribí el código a continuación en 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)

Tenga en cuenta que la lambda devuelta por las overloadfunciones elige la función para llamar dependiendo del número de argumentos sin nombre .

La solución no es perfecta, pero por el momento no puedo escribir nada mejor.

GingerPlusPlus
fuente
1

No es posible directamente. Sin embargo, puede usar comprobaciones de tipo explícitas en los argumentos dados, aunque esto generalmente está mal visto.

Python es dinámico. Si no está seguro de lo que puede hacer un objeto, simplemente intente: y llame a un método en él, luego excepto: errores.

Si no necesita sobrecargar según los tipos, sino solo el número de argumentos, utilice argumentos de palabras clave.

Jürgen Strobel
fuente
3
No creo que él supiera acerca de los argumentos opcionales.
2011
0

Los métodos de sobrecarga son complicados en Python. Sin embargo, podría usarse pasar el dict, la lista o las variables primitivas.

He intentado algo para mis casos de uso, esto podría ayudar aquí a comprender que las personas sobrecarguen los métodos.

Tomemos el ejemplo de uso en uno de los hilos de stackoverflow:

un método de sobrecarga de clase con la llamada a los métodos de una clase diferente.

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

pasar los argumentos de la clase remota:

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

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

Por lo tanto, se logra el manejo de variables de lista, diccionario o primitivas debido a la sobrecarga de métodos.

pruébalo para tus códigos

shashankS
fuente