Tengo una pregunta sobre modismos y legibilidad, y parece haber un choque de filosofías de Python para este caso particular:
Quiero crear el diccionario A a partir del diccionario B. Si una clave específica no existe en B, no haga nada y continúe.
¿Cuál es mejor?
try:
A["blah"] = B["blah"]
except KeyError:
pass
o
if "blah" in B:
A["blah"] = B["blah"]
"Hacer y pedir perdón" versus "sencillez y explicidad".
¿Cuál es mejor y por qué?
python
idioms
readability
defaultdict
code-readability
LeeMobile
fuente
fuente
if "blah" in B.keys()
, oif B.has_key("blah")
.A.update(B)
no funcionar para usted?has_key
se ha desaprobado a favor dein
y la verificaciónB.keys()
cambia una operación O (1) a una O (n)..has_key
está en desuso ykeys
crea una lista innecesaria en py2k, y es redundante en py3kA = dict((k, v) for (k, v) in B if we_want_to_include(k))
.Respuestas:
Las excepciones no son condicionales.
La versión condicional es más clara. Eso es natural: este es un control de flujo sencillo, para lo que están diseñados los condicionales, no las excepciones.
La versión de excepción se utiliza principalmente como optimización cuando se realizan estas búsquedas en un bucle: para algunos algoritmos, permite eliminar las pruebas de los bucles internos. No tiene ese beneficio aquí. Tiene la pequeña ventaja de que evita tener que decir
"blah"
dos veces, pero si está haciendo muchas de estas, probablemente debería tener unamove_key
función de ayuda de todos modos.En general, recomiendo encarecidamente seguir con la versión condicional de forma predeterminada a menos que tenga una razón específica para no hacerlo. Los condicionales son la forma obvia de hacer esto, que suele ser una fuerte recomendación para preferir una solución sobre otra.
fuente
"blah"
más frecuencia, lo que conduce a una situación más propensa a errores.También hay una tercera forma que evita tanto las excepciones como la doble búsqueda, que puede ser importante si la búsqueda es costosa:
En caso de que espere que el diccionario contenga
None
valores, puede usar algunas constantes más esotéricas comoNotImplemented
,Ellipsis
o hacer una nueva:De todos modos, usar
update()
es la opción más legible para mí:fuente
Por lo que tengo entendido, desea actualizar el dictado A con pares clave, valor del dictado B
update
es una mejor opción.Ejemplo:
fuente
A.update({k: v for k, v in B.iteritems() if k in specificset})
Cita directa de la wiki de rendimiento de Python:
Entonces parece que ambas opciones son viables dependiendo de la situación. Para obtener más detalles, es posible que desee consultar este enlace: Try-except-performance
fuente
Creo que la regla general aquí es que
A["blah"]
normalmente existirá, si es así, intente, excepto que es bueno si no, entonces useif "blah" in b:
Creo que "probar" es barato en el tiempo, pero "excepto" es más caro.
fuente
Creo que el segundo ejemplo es lo que debería buscar a menos que este código tenga sentido:
Tenga en cuenta que el código se cancelará tan pronto como haya una clave que no esté en
B
. Si este código tiene sentido, entonces debe usar el método de excepción; de lo contrario, use el método de prueba. En mi opinión, debido a que es más corto y expresa claramente la intención, es mucho más fácil de leer que el método de excepción.Por supuesto, las personas que le dicen que use
update
son correctas. Si está utilizando una versión de Python que admita la comprensión del diccionario, preferiría mucho este código:fuente
for key in ["foo", "bar", "baz"]: try: A[key] = B[key]
La regla en otros idiomas es reservar excepciones para condiciones excepcionales, es decir, errores que no ocurren con el uso regular. No sé cómo se aplica esa regla a Python, ya que StopIteration no debería existir según esa regla.
fuente
Personalmente, me inclino por el segundo método (pero usando
has_key
):De esa manera, cada operación de asignación consta de solo dos líneas (en lugar de 4 con try / except), y cualquier excepción que se produzca será un error real o cosas que se haya perdido (en lugar de simplemente intentar acceder a las claves que no están allí) .
Resulta que (vea los comentarios sobre su pregunta),
has_key
está en desuso, así que supongo que está mejor escrito comofuente
A partir
Python 3.8
y la introducción de las expresiones de asignación (PEP 572) (:=
operador), podemos capturar el valor de la condicióndictB.get('hello', None)
en una variablevalue
para comprobar si no lo esNone
(comodict.get('hello', None)
devuelve el valor asociado oNone
) y luego usarlo dentro del cuerpo de la condición:fuente
Aunque el énfasis de la respuesta aceptada en el principio de "mirar antes de saltar" podría aplicarse a la mayoría de los lenguajes, el primer enfoque podría ser más pitónico, basado en los principios de python. Sin mencionar que es un estilo de codificación legítimo en Python. Lo importante es asegurarse de que está utilizando el bloque try except en el contexto correcto y sigue las mejores prácticas. P.ej. haciendo demasiadas cosas en un bloque de prueba, detectando una excepción muy amplia, o peor, la cláusula de excepción, etc.
Vea la referencia de documentos de Python aquí .
Además, este blog de Brett, uno de los desarrolladores principales, aborda la mayor parte de esto en breve.
Vea otra discusión de SO aquí :
fuente