2011-11-30 16 views
13

Considere esta línea:manera Pythonic para asignar valores por defecto

some_value = lst.attr[idx] 

Hay dos posibles errores aquí, el attr no podría existir, y el idx podrían estar fuera de rango.

¿Hay alguna forma elegante de reducir esta afirmación? Idealmente, a algo como esto:

some_value = lst.attr[idx] or default_value 

(.. No trate de que en su casa que sólo funciona para las expresiones adecuadamente definidos que dan como resultado algo)

seguro de que puedo hacer:

try: 
    some_value = lst.attr[idx] 
except: 
    some_value = default_value 

¿Pero y si estoy en el contexto de una tarea? Por ejemplo:

print [x.attr[idx] for x in y] 

Cuál es la forma Pythonic para controlar los errores y asignar valores por defecto en este caso?

+1

No es tarea muy común, por lo que no es (supongo) solución incorporada. Pero puede escribir su propia función getter y usarla en cualquier lugar que desee (en listas de comprensión también). – DrTyrsa

+0

¿Qué pasa con la 'excepción'? Eso ** es ** Ptónico. El "qué sucede si estoy en el contexto de una tarea" muestra una declaración impresa, no una tarea. ¿Puedes aclarar la afirmación y cuál es el posible problema que causaría 'except'? No está claro por qué el 'excepto' es inaceptable. Por favor aclara –

+0

@ S.Lott - la lista de comprensión es un ejemplo de una tarea. Piensa en la diferencia entre un bloque if-else y un operador ternario. –

Respuesta

5

Tiene que decidir lo que está tratando de lograr aquí. El uso de la palabra "error" probablemente sea engañoso.

Si realmente está tratando de manejar el caso donde se pasa el tipo incorrecto de objeto a su función, entonces no desea manejar eso y debe generar una excepción.

Si está intentando permitir que su función se use en una serie de tipos diferentes, entonces eso no es realmente un error y usar un valor predeterminado puede ser razonable.

La opción más simple es comprobar si el atributo existe primero.Por ejemplo:

if hasattr(lst, "attr"): 
    attr = lst.attr 
else: 
    attr = {} 

Asumo la lst.attr es un diccionario, en cuyo caso se puede controlar el valor por defecto de este modo:

lst.attr.get(idx, default_value) 

Nunca use una declaración try/except donde usted don' t especifica qué excepción estás atrapando. Puedes terminar enmascarando mucho más de lo que pretendías.

Con su última pieza de código, creo que no debe tratar de resolverlo en una sola línea. La legibilidad cuenta No estoy contento con el código siguiente, pero se mejoraría si se reemplazaran x, y y attr con nombres más descriptivos.

attrs = [(x.attr if hasattr(x) else {}) for x in y] 

print [attr.get(idx, default_value) for attr in attrs] 
+0

No usaría 'hasattr' - usa' try/except' debajo del capó. Simplemente reemplace la instrucción 'if' con' try: 'y' else: 'con' excepto AttributeError: '. Ciertamente en línea con la filosofía de EAFP. –

2

Incluso si existe un liner, sería realmente complicado. P.ej. éste todavía no se ocupa de un problema de índice:

some_value = getattr(lst, 'attr', {idx: default_value})[idx] 

sugeriría a escribir algún comprador para su lst.

2

Cuando hay 'attr' en el objeto

class C(object): 
    attr = "attr on class" 
lst = C() 
print lst.attr if hasattr(lst,'attr') else "default value" 

Cuando no hay ningún atributo 'attr'

class C(object): 
    #attr = "attr on class" 
    pass 
lst = C() 
print lst.attr if hasattr(lst,'attr') else "default value" 
+1

estaba a punto de publicar este – soulcheck

+0

@soulcheck llegas tarde :) –

4

What's the pythonic way to handle errors and assign default values in this case?

>>> import this 
... 
Explicit is better than implicit. 
... 
Sparse is better than dense. 
Readability counts. 
... 
Errors should never pass silently. 
Unless explicitly silenced. 
In the face of ambiguity, refuse the temptation to guess. 

tengo la sensación de que el "Pythonic manera de asignar valores predeterminados "* es a h y excepción, como ya lo mencionó en su pregunta, ya sea para escribir sus propios captadores.

3

escribir una función y que sea lo suficientemente inteligente:

def get_attr_with_index_and_default(obj, attr_name, index, default): 
    try: 
     return getattr(obj, attr_name)[index] 
    except (AttributeError, IndexError): 
     return default 

print [get_attr_with_index_and_default(x, 'attr', idx, some_default) for x in y] 

si el control de la clase de x, puede utilizar esto como un método, o adaptarlo a modo de un descriptor, pero En mi opinión esto es no vale la pena y dará lugar a un código oscuro y difícil de detectar errores.

0

No hay una solución simple y elegante a su problema. Si hay que hacerlo usando una sola línea que se puede utilizar en list-comprensiones por ejemplo, entonces se podría hacer lo siguiente:

# If lst.attr is a dict. 
some_value = getattr(lst, 'attr', {}).get(idx, default_value) 
# OR 
some_value = lst.attr.get(idx, default_value) if hasattr(lst, 'attr') else default_value 
# OR 
some_value = lst.attr[idx] if hasattr(lst, 'attr') and idx in lst.attr else default_value 

# If lst.attr is a sequence. 
some_value = lst.attr[idx] if idx < len(getattr(lst, 'attr',())) else default_value 
# OR 
some_value = lst.attr[idx] if hasattr(lst, 'attr') and idx < len(lst.attr) else default_value 
Cuestiones relacionadas