2010-01-22 11 views
9

Opción 1:¿qué estilo es el preferido?

def f1(c): 
    d = { 
    "USA": "N.Y.", 
    "China": "Shanghai" 
    } 

    if c in d: 
    return d[c] 

    return "N/A" 

Opción 2:

def f2(c): 
    d = { 
    "USA": "N.Y.", 
    "China": "Shanghai" 
    } 

    try: 
    return d[c] 
    except: 
    return "N/A" 

Así que entonces puedo llamar:

for c in ("China", "Japan"): 
    for f in (f1, f2): 
    print "%s => %s" % (c, f(c)) 

Las opciones son o bien determinar si la clave está en el directorio de antemano (f1), o simplemente recurrir a la excepción (f2). ¿Cuál es el preferido? ¿Por qué?

+8

excepto: es mal karma. Sea siempre específico acerca de lo que le interesa capturar, en este caso KeyError – richo

+2

Escogió un mal ejemplo. La respuesta obvia no implica ni estilo. – Omnifarious

Respuesta

9

Por lo general, las excepciones conllevan algunos gastos generales, y están pensadas para casos realmente "excepcionales". En este caso, esto suena como una parte normal de la ejecución, no como un estado "excepcional" o "error".

En general, creo que su código se beneficiará al utilizar la convención "si/no", y guardará las excepciones solo cuando realmente sean necesarias.

+2

que me recuerdan "codificar como crees", "las cosas funcionan mejor para lo que fueron diseñadas". así que lo marco como la respuesta. –

+0

Es posible que tenga razón cuando dice Excepciones vienen con una sobrecarga, pero el estilo de pitón es 'Es mejor pedir perdón que permiso'. Eso significa que no verifica si hay algo allí o no. Usted 'intenta' y lo hace y luego pide perdón. Si fuera yo, me hubiera ido con un 'try/except' –

+2

Ese es un buen punto jeffjose. En Python es inteligente probar cosas y ver qué funciona. Sin embargo, usar una cláusula try/except en este caso cuando no esperamos algo excepcional no es una buena idea. Como dijo Richo: "mal karma".:-) –

21

Ni, me gustaría ir a

def f2(c): 
    d = { 
    "USA": "N.Y.", 
    "China": "Shanghai" 
    } 

    return d.get(c, "N/A") 

De esta manera es más corta y "obtener" está diseñado para el trabajo.

También una excepción sin una excepción explícita es mala práctica, así que use except KeyError: no solo excepto.

Las excepciones no tienen demasiada sobrecarga en python. En general, es mejor usarlos si no hay mejores alternativas o, a veces, incluso cuando guarda una búsqueda de atributos (para usar en lugar de hasattr).

Editar: para aclarar el punto general sobre las excepciones.

paxdiablo es correcto en el punto general. Python está diseñado principalmente para "es más fácil pedir permiso y luego permiso", es decir, intentar ver qué falla (excepciones), luego "mirar antes de saltar", ver qué hay allí y luego aplicar. Esto se debe a que la búsqueda de atributos en python puede ser costosa, por lo que llamar a las mismas cosas de nuevo (para comprobar límites) es una pérdida de recursos. Sin embargo, las cosas internas en python normalmente tienen mejores ayudas, así que es mejor usarlas.

+0

la pregunta no es específica para dict, es principalmente para exhibición. lo que quiero saber es verificar los límites antes de la mano o retirarme a la excepción. –

+1

@Dyno: entonces deberías haber preguntado * que *. Una buena regla empírica es "mejor pedir perdón que permiso", pero agregaré que si el caso común va a resultar en pedir mucho perdón, primero debe pedir perdón. –

+0

te refieres a "solo hazlo". si sale mal, ¿luego lidiar con eso? –

7

Ninguno.

return d.get(c, 'N/A') 
11

En términos generales (no necesariamente de Python), que tienden a preferir el método "probar-entonces-decir-me-si-que-fue-malo" (excepciones) en todo menos en los casos más simples. Esto se debe a que, en entornos con subprocesos o durante el acceso a la base de datos, los datos subyacentes pueden cambiar entre la verificación de clave y la extracción de valor.

Si no está cambiando la matriz asociativa fuera del subproceso actual, puede hacer el método "check-first-then-extract".

Pero eso es para el caso general. Aquí, en concreto, puede utilizar el método get que le permite especificar un valor predeterminado si no existe la clave:

return d.get (c, "N/A") 

Voy a aclarar lo que dije en el primer párrafo.En situaciones donde los datos subyacentes pueden cambiar entre verificación y uso, debe siempre usar una operación de tipo excepción (a menos que tenga una operación que no cause un problema, como d.get(), mencionado anteriormente). Considere, por ejemplo, las siguientes dos hilos líneas de tiempo:

+------------------------------+--------------------+ 
| Thread1      | Thread2   | 
+------------------------------+--------------------+ 
| Check is NY exists as a key. |     | 
|        | Delete NY key/val. | 
| Extract value for NY.  |     | 
+------------------------------+--------------------+ 

Al hilo 1 intenta extraer el valor, se obtendrá una excepción de todos modos, por lo que puede código así sólo por la posibilidad y quite la marca inicial.

El comentario sobre las bases de datos también es relevante ya que esa es otra situación donde los datos subyacentes pueden cambiar. Es por eso que tiendo a preferir el SQL atómico (cuando sea posible) en lugar de obtener una lista de claves y luego procesarlas con declaraciones individuales.

+0

Siempre los llamé. Es más fácil pedir perdón y luego permiso "y" mirar antes de saltar ", respectivamente. Pero estoy de acuerdo en que Python es el perdón. –

+0

tiendo a marcar tanto esta como la de jweede como respuesta, pero parece que esto no es factible. –

4

estoy con David en este caso:

def f2(c): 
    d = { 
     "USA": "N.Y.", 
     "China": "Shanghai" 
     } 

    return d.get(c, "N/A") 

... es exactamente lo que me gustaría escribir.

Para hacer frente a sus otras opciones:

En 'f1()', no hay nada malo con esto, de por sí, pero los diccionarios tienen un método get() para más o menos este caso de uso exacto: "obtener esta información de el dict, y si no está allí, devuelve esta otra cosa en su lugar ". Eso es todo lo que dice tu código, usar get() es más conciso.

En 'f2()', usar 'except' solo así es desaprobado y, además, no hace nada útil en respuesta a la excepción: en su caso, el código de llamada nunca sé que hubo una excepción. Entonces, ¿por qué usar el constructo si no agrega valor a su función o al código que lo llama?

1

Veo personas que usan "obtener", que recomiendo. Sin embargo, si usted se encuentra en una situación similar en el futuro, detectar la excepción decir:

try: 
    return d[k] 
except KeyError: 
    return "N/A" 

De esta manera, otras excepciones (incluyendo KeyboardInterrupt) no queden atrapados. Casi nunca desea atrapar KeyboardInterrupt.

0

Acepto que en este caso, dict.get es la mejor solución.

En general, creo que su elección dependerá de la probabilidad de las excepciones. Si espera que las búsquedas de claves pasen principalmente, entonces el try/catch es una mejor opción de IMO. De manera similar, si fallarán a menudo, una declaración if es mejor.

El rendimiento de las búsquedas de excepciones frente a las de atributos no es tan diferente en Python, por lo que me preocupa más la lógica de usar excepciones/mirar antes que saltar que sobre los aspectos de rendimiento.

Cuestiones relacionadas