2010-08-10 12 views
11

Supongamos lo siguiente:Función que devuelve una tupla o Ninguna: cómo llamar bien a esa función?

def MyFunc(a): 
    if a < 0: 
    return None 
    return (a+1, a+2, a+3) 

v1, v2, v3 = MyFunc() 
# Bad ofcourse, if the result was None 

¿Cuál es la mejor manera de definir una función que devuelve una tupla y sin embargo puede ser muy bien llamada. En la actualidad, podría hacer esto:


r = MyFunc() 
if r: 
    v1, v2, v3 = r 
else: 
    # bad!! 
    pass 

Lo que no me gusta de esto es que tengo que usar una sola variable y luego descomprimirlo.

Otra solución es que podría tener la función devuelve una tupla completa de Nones de manera que la persona que llama puede descomprimir muy bien ....

Cualquier persona puede sugerir un mejor diseño?

Respuesta

13

¿Qué le parece elevar un ArgumentError? Entonces podría llamarlo try y tratar con la excepción si el argumento es incorrecto.

Por lo tanto, algo así como:

try: 
    v1, v2, v3 = MyFunc() 
except ArgumentError: 
    #deal with it 

Además, vea katrielalex's answer para el uso de una subclase de ArgumentError.

+0

1 me ganó de mano! – katrielalex

+1

Eso es agradable, pero siempre estoy preocupado por la sobrecarga de la crianza y el manejo de excepciones –

8

Esto debería funcionar muy bien:

v1, v2, v3 = MyFunc() or (None, None, None) 

Cuando MyFunc() devuelve una tupla, será sin envasar, de lo contrario será sustituido por un 3-tupla de None.

+0

No veo cómo es mejor que devolver una tupla de 'None's. – Skilldrick

+2

@Skilldrick: ¡Es bonito! – katrielalex

+0

Si es mejor, es probablemente porque no requiere cambiar el contenido de la función. – recursive

8

recursive tiene una solución verdaderamente elegante y Pythonic. PERO: ¿por qué quieres devolver None? Python tiene una forma de tratamiento de errores, y que está levantando una excepción:

class AIsTooSmallError(ArgumentError): pass 

y luego

raise AIsTooSmallError("a must be positive.") 

La razón de que esto es mejor es que la devolución de un valor indica que se ha completado el procesamiento y están devolviendo tu respuesta. Esto está bien si ha realizado algún procesamiento, pero es una tontería si devuelve inmediatamente None.

+0

Muy por delante de ya :) Pero las grandes mentes ... – Skilldrick

+0

1: no regresan Ninguno para indicar un error. – nosklo

+0

Heh. Entonces tú eres. ¡Pero subclasé 'ArgumentError'! – katrielalex

3

Otra solución es que podría tener la función devuelve una tupla completa de Nones de manera que la persona que llama puede descomprimir muy bien ....

¿Qué hay de malo en eso? La consistencia es algo bueno.

+0

Estoy de acuerdo. De hecho, de esa manera mantiene la firma de la función de retorno. 1 – simplyharsh

+2

El mantenimiento de las firmas de retorno es tan estática;) – Skilldrick

+0

@Skilldrick: En mi experiencia, una firma retorno consistente promueve el dinamismo que permite que un no conocer detalles tontos y excepciones. Pero solo soy flojo. –

1

Si desea que los objetos v1, v2, v3 existan y se establezca un valor predeterminado en el caso de un error, devuelva los valores predeterminados usted mismo.Esto hará que el código de llamada más sencillo al no depender de la persona que llama para fijar de forma manual:

def MyFunc(a): 
    if a < 0: 
     # can't use a negative value; just return some defaults 
     return (None, None, None) 
    return (a+1, a+2, a+3) 

Por otro lado, si un retorno por defecto no es apropiado y un argumento negativo se considera un grave error, lanzar una excepción :

def MyFunc(a): 
    if a < 0: 
     # sorry, negative values are unacceptable 
     raise ValueError('cannot accept a negative value') 
    return (a+1, a+2, a+3) 

en la tercera duro, volviendo None puede ser preferible a veces cuando se devuelva un único objeto, como es el caso con los search() y match() funciones del módulo re. De alguna manera se encuentra entre los primeros dos casos, porque la falla de coincidencia es un resultado esperado, mientras que un objeto de retorno predeterminado no sería muy útil de todos modos.

1

Esto es similar a la respuesta anterior. Podría devolver una instancia de objeto o Ninguna

def MyFunc(a): 
    class MyFuncClass(object): 
     def __init__(self, **kwargs): 
      self.__dict__.update(kwargs) 
    if a < 0: 
     return None 
    return MyFuncClass(one=a+1, two=a+2, three=a+3) 

o = MyFunc(1) 
if o is not None: 
    print o.one, o.two, o.three 
Cuestiones relacionadas