Pregunta

Hace poco me enseñé Python y descubrí los modismos LBYL / EAFP con respecto a la verificación de errores antes de la ejecución del código. En Python, parece que el estilo aceptado es EAFP, y parece funcionar bien con el lenguaje.

LBYL ( L ook B antes de S ou L eap ):

def safe_divide_1(x, y):
    if y == 0:
        print "Divide-by-0 attempt detected"
        return None
    else:
        return x/y

EAFP ( es E más fácil de A sk F más que P ermission ):

def safe_divide_2(x, y):
    try:
        return x/y
    except ZeroDivisionError:  
        print "Divide-by-0 attempt detected"
        return None

Mi pregunta es la siguiente: nunca había oído hablar del uso de EAFP como la construcción principal de validación de datos, proveniente de un entorno Java y C ++. ¿Es EAFP algo que es sabio usar en Java? ¿O hay demasiada sobrecarga de las excepciones? Sé que solo hay una sobrecarga cuando realmente se lanza una excepción, así que no estoy seguro de por qué no se usa el método más simple de EAFP. ¿Es solo preferencia?

¿Fue útil?

Solución

Personalmente, y creo que esto está respaldado por una convención, EAFP nunca es una buena manera de hacerlo. Puede verlo como un equivalente a lo siguiente:

if (o != null)
    o.doSomething();
else
    // handle

a diferencia de:

try {
    o.doSomething()
}
catch (NullPointerException npe) { 
    // handle
}

Además, considera lo siguiente:

if (a != null)
    if (b != null)
        if (c != null)
            a.getB().getC().doSomething();
        else
            // handle c null
    else
        // handle b null
else
    // handle a null

Esto puede parecer mucho menos elegante (y sí, este es un ejemplo tosco, ten paciencia), pero te da mucha más granularidad en el manejo del error, en lugar de envolverlo todo en un intento de captura para conseguirlo. NullPointerException , y luego intente averiguar dónde y por qué lo obtuvo.

Tal como lo veo, no se debe utilizar EAFP, excepto en situaciones raras. Además, ya que planteó el problema: sí, el bloque try-catch incurre en algunos gastos generales incluso si no se lanza la excepción.

Otros consejos

Si está accediendo a archivos, EAFP es más confiable que LBYL, ya que las operaciones involucradas en LBYL no son atómicas, y el sistema de archivos puede cambiar entre el momento en que mira y el que salta. En realidad, el nombre estándar es TOCTOU: tiempo de verificación, tiempo de uso; los errores causados ??por una comprobación incorrecta son errores TOCTOU.

Considere crear un archivo temporal que debe tener un nombre único. La mejor manera de averiguar si el nombre del archivo elegido aún es intentar crearlo, asegurándose de que utiliza las opciones para asegurarse de que su operación falle si el archivo ya existe (en términos de POSIX / Unix, el indicador O_EXCL para abrir () ). Si intenta probar si el archivo ya existe (probablemente usando access () ), entonces entre el momento en que dice " No " y cuando intenta crear el archivo, es posible que alguien o alguna otra persona haya creado el archivo.

A la inversa, suponga que intenta leer un archivo existente. Tu cheque de que el archivo existe (LBYL) puede decir " está ahí " ;, pero cuando realmente lo abres, encuentras " no está allí " ;.

En ambos casos, debe verificar la operación final, y el LBYL no ayudó automáticamente.

(Si está jugando con los programas SUID o SGID, access () hace una pregunta diferente; puede ser relevante para LBYL, pero el código aún debe tener en cuenta la posibilidad de falla. )

Además del costo relativo de las excepciones en Python y Java, tenga en cuenta que existe una diferencia de filosofía / actitud entre ellas. Java intenta ser muy estricto con respecto a los tipos (y todo lo demás), requiriendo declaraciones explícitas y detalladas de firmas de clase / método. Supone que debe saber, en cualquier momento, exactamente qué tipo de objeto está usando y qué es capaz de hacer. En contraste, la palabra "pato" de Python " significa que no está seguro (y no debería importarle) cuál es el tipo manifiesto de un objeto, solo tiene que preocuparse de que grabe cuando lo pida. En este tipo de ambiente permisivo, la única actitud sensata es suponer que las cosas funcionarán, pero prepárate para enfrentar las consecuencias si no lo hacen. La restricción natural de Java no encaja bien con un enfoque tan informal. (Esto no pretende desacreditar ni el enfoque ni el lenguaje, sino más bien decir que estas actitudes son parte del lenguaje de cada idioma, y ??la copia de los idiomas entre diferentes idiomas a menudo puede llevar a la torpeza y la mala comunicación ...)

Las excepciones se manejan de manera más eficiente en Python que en Java, que es al menos en parte por la que se ve esa construcción en Python. En Java, es más ineficiente (en términos de rendimiento) usar excepciones de esa manera.

Considere estos fragmentos de código:

def int_or_default(x, default=0):
    if x.isdigit():
        return int(x)
    else:
        return default

def int_or_default(x, default=0):
    try:
        return int(x)
    except ValueError:
        return default

Ambos se ven bien, ¿verdad? Pero uno de ellos no lo es.

El primero, usando LBYL, falla debido a una distinción sutil entre isdigit y isdecimal ; cuando se llama con la cadena " ?²³??5 " ;, producirá un error en lugar de devolver correctamente el valor predeterminado.

Lo último, utilizando EAFTP, resulta en un manejo correcto, por definición. No hay margen para una falta de coincidencia de comportamiento, porque el código que necesita el requisito es el código que afirma ese requisito.

Usar LBYL significa tomar lógica interna y copiarla en cada sitio de llamadas. En lugar de tener una codificación canónica de sus requisitos, tiene la posibilidad de desordenar cada vez que llama a la función.

Vale la pena señalar que EAFTP no es acerca de las excepciones, y el código Java, especialmente, no debe usar excepciones de forma generalizada. Se trata de dar el trabajo correcto al bloque de código correcto. Como ejemplo, el uso de los valores de retorno de Opcional es una forma perfectamente válida de escribir el código EAFTP, y es mucho más eficaz para asegurar la corrección que LBYL.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top