Supongo que se trata menos de la naturaleza de la tipificación de patos y más acerca de mantenerse pitónico.
En primer lugar, cuando se trata de dictados, en particular cuando la estructura del dict es bastante predecible y una clave dada generalmente no está presente, pero a veces lo está, primero pienso en dos enfoques:
if myKey in dict:
do_some_work(dict[myKey])
else:
pass
Y, por supuesto, el enfoque de 'perdón versus permiso' de Ye Olde.
try:
do_some_work(dict[myKey])
except KeyError:
pass
Como jornalero de Python, siento que veo que este último prefiere mucho, lo que solo se siente extraño, supongo porque en los documentos de Python try/excepts
parece preferirse cuando hay un error real, en lugar de una, um ... ¿ ausencia de éxito?
Si el dict ocasional no tiene clave en myDict, y se sabe que no siempre tendrá esa clave, ¿ es un try / except contextualmente engañoso? Esto no es un error de programación, es solo un hecho de los datos, este dict simplemente no tenía esa clave en particular.
Esto parece particularmente importante cuando observa la sintaxis try / except / else, que parece ser realmente útil cuando se trata de asegurarse de que try no detecte demasiados errores. Eres capaz de hacer algo como:
try:
foo += bar
except TypeError:
pass
else:
return some_more_work(foo)
¿No conducirá eso a tragar todo tipo de errores extraños que probablemente sean el resultado de algún código incorrecto? El código anterior podría estar evitando que vea que está tratando de agregar 2 + {}
y es posible que nunca se dé cuenta de que una parte de su código ha salido terriblemente mal. No sugiero que debamos verificar todos los tipos, es por eso que es Python y no JavaScript, pero nuevamente con el contexto de try / except, parece que se supone que debe atrapar al programa haciendo algo que no debería estar haciendo, en su lugar de permitirle continuar.
Me doy cuenta de que el ejemplo anterior es una especie de argumento de hombre de paja, y de hecho es intencionalmente malo. Pero dado el credo pitónico de better to ask forgiveness than permission
No puedo evitar sentir que plantea la pregunta de dónde está realmente la línea en la arena entre la aplicación correcta de if / else vs try / except es, en particular cuando sabes qué esperar de los datos con los que estás trabajando.
Ni siquiera estoy hablando de preocupaciones de velocidad o mejores prácticas aquí, estoy un poco confundido por el diagrama de Venn percibido de casos en los que parece que podría ir de cualquier manera, pero la gente se equivoca al lado de un intento / excepto porque 'alguien en alguna parte dijo que era Pythonic'. ¿He sacado conclusiones erróneas sobre la aplicación de esta sintaxis?
Respuestas:
Utilice el método get en su lugar:
... donde
default_value
se devuelve el valor sithe_key
no está ensome_dict
. Si omitedefault_value
,None
se devuelve si falta la clave.En general, en Python, las personas tienden a preferir probar / excepto a comprobar primero algo; consulte la entrada de EAFP en el glosario . Tenga en cuenta que muchas funciones de "prueba de membresía" usan excepciones detrás de escena.
fuente
dict
y haciendo un trabajo basado en lo que se encuentra, parece másif myDict.get(a_key) is not None: do_work(myDict[a_key])
vergonzoso y otro ejemplo de mirar implícitamente antes de saltar, además es un poco menos legible en mi humilde opinión. Quizás no estoy entendiendodict.get(a_key, a_default)
en el contexto correcto, pero parece que es un precursor para escribir 'no-un-cambio-declaración si / elses' o valores mágicos. Sin embargo, me gusta lo que hace este método, lo investigaré más a fondo.data = myDict.get(a_key, default)
ydo_work
harás lo correcto cuando se te dédefault
(p. Ej.None
) O lo harásif data: do_work(data)
. Solo se necesita una búsqueda en cualquier caso. (Puede serif data is not None: ...
, en cualquier caso, todavía es solo una búsqueda y luego su propia lógica puede hacerse cargo)try/except/else
basura de aspecto terrible y en general ha mejorado en mi humilde opinión la legibilidad de mi código. Aprendí una valiosa lección que había escuchado antes, pero me las arreglé para no tomar en serio: "Si sientes que estás escribiendo demasiado código, detente y mira las características del lenguaje". ¡¡Gracias!!¿La clave faltante es una regla o una excepción ?
Desde un punto de vista pragmático, lanzar / atrapar es mucho más lento que verificar si la clave está en la tabla. Si la clave faltante es una ocurrencia común, debe usar la condición.
Otra cosa a favor de la condición es una cláusula else : es mucho más fácil de entender cuando cualquiera de los bloques se ejecuta, tenga en cuenta que incluso la misma clase de excepción se puede lanzar desde varias declaraciones en el bloque try.
El código en la cláusula excepto no debe ser parte de la falla normal (por ejemplo, si la clave no está allí, agréguela), debe estar manejando el error.
fuente
try
/catch
más rápido.En el espíritu de ser "pitón" y, específicamente, de escribir pato, el try / except me parece casi frágil.
Todo lo que realmente quiere es algo con acceso tipo dict, pero
__getitem__
puede ser anulado para hacer algo que no es exactamente lo que espera. Por ejemplo, usandodefaultdict
de la biblioteca estándar:Debido a que el valor de retorno predeterminado es Falsy, la comprobación de acceso así funcionará la mayoría de las veces bien. Parece que el código también es más simple, por lo que mis compañeros de trabajo y yo lo hemos hecho durante meses.
Desafortunadamente, unos meses más tarde, estas claves adicionales terminaron causando problemas y errores difíciles de rastrear, porque se
0
convirtieron en un valor válido. Y a veces nos gustaría utilizarin
para comprobar si existía una llave, por lo que el código de hacer las cosas diferentes, cuando debería haber sido idénticos.La razón por la que sugiero que se ve roto es porque, en el espíritu de escritura de pato de Python, todo lo que debe desear es algo parecido a un dict, y se
defaultdict
ajusta perfectamente a ese requisito, como lo haría cualquier objeto del que pueda crear que herededict
. No puede garantizar que la persona que llama no vaya a cambiar su implementación más adelante, por lo que debe hacer lo que tenga menos efectos secundarios.Use la primera versión
if myKey in mydict
,.Además, tenga en cuenta que esto se trata específicamente del ejemplo en la pregunta. El credo de Python de "Es mejor pedir perdón que permiso" tiene como objetivo principal garantizar que realmente actúes correctamente cuando no obtienes lo que quieres. Por ejemplo, verificar si existe un archivo y luego intentar leerlo: al menos 3 cosas que se me ocurren pueden salir mal:
En el primero puede intentar "pedir permiso", pero por la naturaleza de las condiciones de una carrera, no siempre funcionará necesariamente; el segundo es demasiado fácil de olvidar para verificar; y el tercero no puede verificarse sin intentar leer el archivo. En cualquier caso, lo que hagas después de fallar seguramente será el mismo, así que en este ejemplo, es mejor "pedir perdón" usando un try / except.
fuente