¿Hay una razón para decidir cuál de try
oif
construcciones a su uso, cuando se prueba variable tenga un valor?
Por ejemplo, hay una función que devuelve una lista o no devuelve un valor. Quiero verificar el resultado antes de procesarlo. ¿Cuál de los siguientes sería más preferible y por qué?
result = function();
if (result):
for r in result:
#process items
o
result = function();
try:
for r in result:
#process items
except TypeError:
pass;
Respuestas:
A menudo escuchas que Python alienta el estilo EAFP ("es más fácil pedir perdón que permiso") que el estilo LBYL ("mira antes de saltar"). Para mí, es una cuestión de eficiencia y legibilidad.
En su ejemplo (digamos que en lugar de devolver una lista o una cadena vacía, la función era devolver una lista o
None
), si espera que el 99% del tiemporesult
realmente contenga algo iterable, usaría eltry/except
enfoque. Será más rápido si las excepciones son realmente excepcionales. Siresult
esNone
más del 50% del tiempo, entonces usandoif
probablemente sea mejor .Para apoyar esto con algunas medidas:
Entonces, mientras que una
if
declaración siempre le cuesta, es casi gratis configurar untry/except
bloque. Pero cuandoException
ocurre realmente, el costo es mucho mayor.Moral:
try/except
para el control de flujo,Exception
s son realmente excepcionales.De los documentos de Python:
fuente
try/except
fue un 25% más rápido queif key in d:
en los casos en que la clave estaba en el diccionario. Era mucho más lento cuando la clave no estaba en el diccionario, como se esperaba, y era consistente con esta respuesta.1/1
con timeit no es una gran opción, ya que se optimizarán (veadis.dis('1/1')
y tenga en cuenta que no ocurre división).Su función no debe devolver tipos mixtos (es decir, lista o cadena vacía). Debería devolver una lista de valores o simplemente una lista vacía. Entonces no necesitaría probar nada, es decir, su código se colapsa para:
fuente
Ignore mi solución si el código que proporciono no es obvio a primera vista y tiene que leer la explicación después del ejemplo de código.
¿Puedo suponer que "sin valor devuelto" significa que el valor devuelto es Ninguno? En caso afirmativo, o si el "sin valor" es falso booleano, puede hacer lo siguiente, ya que su código esencialmente trata "sin valor" como "no iterar":
Si
function()
devuelve algo que no es Verdadero, itera sobre la tupla vacía, es decir, no ejecuta ninguna iteración. Esto es esencialmente LBYL.fuente
Su segundo ejemplo está roto: el código nunca arrojará una excepción TypeError ya que puede iterar a través de cadenas y listas. Iterar a través de una cadena o lista vacía también es válido: ejecutará el cuerpo del bucle cero veces.
fuente
Mirar antes de saltar es preferible en este caso. Con el enfoque de excepción, un TypeError podría ocurrir en cualquier parte del cuerpo del bucle y quedaría atrapado y desechado, lo que no es lo que desea y dificultará la depuración.
(Sin embargo, estoy de acuerdo con Brandon Corfman: devolver None por 'no hay elementos' en lugar de una lista vacía está roto. Es un hábito desagradable de los codificadores Java que no deberían verse en Python. O Java).
fuente
En general, la impresión que tengo es que las excepciones deben reservarse para circunstancias excepcionales. Si
result
se espera que el nunca esté vacío (pero podría estarlo, si, por ejemplo, un disco falla, etc.), el segundo enfoque tiene sentido. Si, por otro lado, un vacíoresult
es perfectamente razonable en condiciones normales, probarlo con unaif
declaración tiene más sentido.Tenía en mente el escenario (más común):
en lugar del equivalente:
fuente
++
no funciona en python, úsela en su+= 1
lugar.Bobince señala sabiamente que envolver el segundo caso también puede atrapar TypeErrors en el bucle, que no es lo que desea. Sin embargo, si realmente desea probar, puede probar si es iterable antes del ciclo
Como puede ver, es bastante feo. No lo sugiero, pero debe mencionarse por completo.
fuente
None
, siempre verifique el resultado conis None
ois not None
. Por otro lado, también es un mal estilo generar Excepciones para obtener resultados legítimos. Las excepciones son para las cosas inesperadas. Ejemplo:str.find()
devuelve -1 si no se encuentra nada, porque la búsqueda en sí misma se completó sin errores.En lo que respecta al rendimiento, usar el bloque try para el código que normalmente no genera excepciones es más rápido que usar la instrucción if cada vez. Entonces, la decisión depende de la probabilidad de casos excepcionales.
fuente
Como regla general, nunca debe usar try / catch ni ninguna excepción para controlar el flujo. Aunque la iteración detrás de escena se controla mediante el aumento de
StopIteration
excepciones, aún debe preferir su primer fragmento de código al segundo.fuente