Python: `if key in dict` vs.` try / except` – ¿cuál es el lenguaje más legible?

Tengo una pregunta sobre los modismos y la legibilidad, y parece que hay un choque de filosofías de Python para este caso en particular:

Quiero comstackr el diccionario A del diccionario B. Si no existe una clave específica en B, no haga nada y continúe.

¿Qué camino es mejor?

try: A["blah"] = B["blah"] except KeyError: pass 

o

 if "blah" in B: A["blah"] = B["blah"] 

“Hacer y pedir perdón” frente a “simplicidad y explicación”.

    ¿Cuál es mejor y por qué?

    Las excepciones no son condicionales.

    La versión condicional es más clara. Eso es natural: esto es un control de flujo directo, que es para lo que se diseñan los condicionales, no las excepciones.

    La versión de excepción se usa principalmente como una optimización cuando se realizan estas búsquedas en un bucle: para algunos algoritmos permite eliminar 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ás haciendo muchos de estos, probablemente deberías tener una función move_key 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 recomendación fuerte para preferir una solución sobre otra.

    También hay una tercera forma que evita tanto las excepciones como la búsqueda doble, que puede ser importante si la búsqueda es costosa:

     value = B.get("blah", None) if value is None: A["blah"] = value 

    En caso de que espere que el diccionario contenga valores de None , puede usar algunas constantes esotéricas más como NotImplemented , Ellipsis o hacer una nueva:

     MyConst = object() def update_key(A, B, key): value = B.get(key, MyConst) if value is not MyConst: A[key] = value 

    De todos modos, usar update() es la opción más legible para mí:

     a.update((k, b[k]) for k in ("foo", "bar", "blah") if k in b) 

    Por lo que entiendo, usted quiere actualizar el dict A con la clave, los pares de valores del dict B

    update es una mejor opción.

     A.update(B) 

    Ejemplo:

     >>> A = {'a':1, 'b': 2, 'c':3} >>> B = {'d': 2, 'b':5, 'c': 4} >>> A.update(B) >>> A {'a': 1, 'c': 4, 'b': 5, 'd': 2} >>> 

    Cita directa de la wiki de rendimiento de Python:

    Excepto por la primera vez, cada vez que se ve una palabra, la prueba de la afirmación if falla. Si está contando un gran número de palabras, es probable que muchas aparezcan varias veces. En una situación en la que la inicialización de un valor solo se producirá una vez y el aumento de ese valor se producirá muchas veces, es más barato utilizar una instrucción try.

    Así que parece que ambas opciones son viables dependiendo de la situación. Para obtener más información, puede consultar este enlace: Probar excepto el rendimiento

    Creo que la regla general aquí es que A["blah"] normalmente existirá, si es así que try-except es bueno si no, entonces se usa if "blah" in b:

    Creo que “intentar” es barato en el tiempo pero “excepto” es más caro.

    Creo que el segundo ejemplo es a lo que deberías ir a menos que este código tenga sentido:

     try: A["foo"] = B["foo"] A["bar"] = B["bar"] A["baz"] = B["baz"] except KeyError: pass 

    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 te dicen que uses la update son correctas. Si está utilizando una versión de Python que admite la comprensión de diccionarios, preferiría este código:

     updateset = {'foo', 'bar', 'baz'} A.update({k: B[k] for k in updateset if k in B}) 

    La regla en otros idiomas es reservar excepciones para condiciones excepcionales, es decir, errores que no ocurren en el uso regular. No sé cómo se aplica esa regla a Python, ya que StopIteration no debería existir por esa regla.

    Personalmente, me inclino por el segundo método (pero con has_key ):

     if B.has_key("blah"): A["blah"] = B["blah"] 

    De esa manera, cada operación de asignación es solo de dos líneas (en lugar de 4 con try / except), y cualquier excepción que se produzca será un error real o algo que haya perdido (en lugar de solo intentar acceder a teclas que no están allí) .

    Resulta que (ver los comentarios sobre tu pregunta), has_key está en desuso, así que supongo que está mejor escrito como

     if "blah" in B: A["blah"] = B["blah"] 

    ¿Por qué no hacer esto?

     def try_except(x,col): try: return x[col] except: return None list(map(lambda x: try_except(x,'blah'),A))