Pergunta

Recentemente eu estava me ensinando Python e descobriu os idiomas LBYL / EAFP que diz respeito à verificação de erros antes da execução do código. Em Python, parece que o estilo aceita é EAFP, e parece funcionar bem com o idioma.

LBYL ( G OOK B ntes Y ou G eap ):

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

EAFP ( a sua E asier para A sk F orgiveness de P ermission ):

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

A minha pergunta é esta: eu nunca tinha sequer ouvido falar de usar EAFP como a construção de validação de dados primários, vindo de um Java e C ++ fundo. EAFP é algo que é sábio para usar em Java? Ou há muita sobrecarga de exceções? Eu sei que há apenas sobrecarga quando uma exceção é realmente jogado, por isso estou inseguro quanto às razões pelas quais o método mais simples de EAFP não é usado. É apenas uma preferência?

Foi útil?

Solução

Pessoalmente, e acho que isso é apoiada por convenção, EAFP nunca é uma boa maneira de ir. Você pode olhar para ele como um equivalente ao seguinte:

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

ao contrário:

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

Além disso, considere o seguinte:

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

Isto pode parecer muito menos elegante (e sim, este é um exemplo grosseiro - bear with me), mas dá-lhe muito maior granularidade em lidar com o erro, ao invés de embalar tudo em um try-catch para obter esse NullPointerException, e depois tentar descobrir onde e por que você conseguiu.

A forma como eu vejo EAFP nunca deve ser usado, exceto em situações raras. Além disso, desde que você levantou a questão:. sim, o bloco try-catch incorre em alguma sobrecarga , mesmo que a exceção não é lançada

Outras dicas

Se você estiver acessando arquivos, EAFP é mais confiável do que LBYL, porque as operações envolvidas na LBYL não são atômicas, eo sistema de arquivos pode alterar entre o momento em que você olha e o tempo de pular. Na verdade, o nome padrão é TOCTOU - Tempo de Verificação, tempo de uso; erros causados ??pela verificação imprecisas são TOCTOU bugs.

Considere a criação de um arquivo temporário que deve ter um nome único. A melhor maneira de descobrir se o nome do arquivo escolhido ainda existe é tentar criá-la - certificando-se de usar as opções para garantir que sua operação falhar se o arquivo já existe (em termos POSIX / Unix, a bandeira O_EXCL para open()). Se você tentar testar se o arquivo já existe (provavelmente usando access()), em seguida, entre o momento em que diz "não" eo tempo que você tentar criar o arquivo, alguém ou alguma coisa pode ter criado o arquivo.

Por outro lado, suponha que você tenta ler um arquivo existente. Seu cheque se o arquivo existe (LBYL) pode dizer "ele está lá", mas quando você realmente abri-lo, você encontra "ele não está lá".

Em ambos os casos, você tem que verificar o funcionamento final - eo LBYL fez não automaticamente ajuda

.

(Se você está mexendo com SUID ou SGID programas, access() faz uma pergunta diferente;. Que podem ser relevantes para LBYL, mas o código ainda tem que levar em conta a possibilidade de falha)

Além do custo relativo de exceções em Python e Java, tenha em mente que há uma diferença na filosofia / atitude entre eles. Java tenta ser muito rigoroso sobre os tipos (e tudo mais), exigindo declarações explícitas e detalhada de assinaturas de classe / método. Ele assume que você deveria saber, em qualquer ponto, exatamente o tipo de objeto que você está usando eo que ele é capaz de fazer. Em contraste, os meios de Python "pato digitação" que você não sabe com certeza (e não deve se importam) que o tipo de manifesto de um objeto é, você só precisa se preocupar que grasna quando você pedir para ele. Neste tipo de ambiente permissivo, a atitude só sane é presumir que as coisas vão funcionar, mas estar pronto para lidar com as consequências se não o fizerem. restritividade natural do Java não se encaixa bem com uma abordagem tão casual. (Isto não se destina a depreciar qualquer abordagem ou linguagem, mas em vez de dizer que essas atitudes são parte da linguagem de cada idioma, e copiar expressões entre diferentes línguas podem muitas vezes levar a constrangimento e falta de comunicação ...)

As exceções são tratadas de forma mais eficiente em Python do que em Java, que é pelo menos parte porque você vê que construção em Python. Em Java, é mais ineficiente (em termos de desempenho) para usar exceções nesse sentido.

Considere estas trechos 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 olhar correto, certo? Mas um deles não é.

O primeiro, usando LBYL, falhar devido a uma distinção sutil entre isdigit e isdecimal; quando chamado com a string "?²³??5", ele irá lançar um erro em vez de retornar corretamente o valor padrão.

O mais tarde, usando EAFTP, resulta em manipulação correta, por definição. Não há espaço para uma incompatibilidade comportamental, porque o código que precisa a exigência é o código que afirma que exigência.

Usando meios LBYL tomar lógica interna e copiá-los em todas chamada local. Ao invés de ter uma codificação canônica de suas necessidades, você receber uma chance livre para mexer-se cada vez que você chamar a função.

É importante notar que EAFTP não sobre exceções e código Java especialmente não deveria estar usando exceções pervasively. É sobre dar o trabalho certo para o bloco de direita do código. Como exemplo, utilizando valores de retorno Optional é uma maneira perfeitamente válida de escrever código EAFTP, e é muito mais eficaz para garantir a exatidão do que LBYL.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top