Existe um problema de desempenho ou manutenção de código ao usar
assert
como parte do código padrão em vez de usá-lo apenas para fins de depuração?É
assert x >= 0, 'x is less than zero'
melhor ou pior que
if x < 0: raise Exception, 'x is less than zero'
Além disso, existe alguma maneira de definir uma regra de negócios como
if x < 0 raise error
essa sempre verificada semtry/except/finally
isso, se a qualquer momento em todo o códigox
for menor que 0 um erro for gerado, como se você definisseassert x < 0
no início de uma função, em qualquer lugar da função ondex
se torna menor que 0, uma exceção é gerada?
483
assert
.Respostas:
Ser capaz de gerar um erro automaticamente quando x se tornar menor que zero em toda a função. Você pode usar descritores de classe . Aqui está um exemplo:
fonte
As declarações devem ser usadas para testar condições que nunca devem acontecer . O objetivo é travar no início no caso de um estado de programa corrompido.
Exceções devem ser usadas para erros que possam acontecer, e você quase sempre deve criar suas próprias classes de exceção .
Por exemplo, se você estiver escrevendo uma função para ler de um arquivo de configuração em um arquivo
dict
, a formatação incorreta no arquivo deve gerar aConfigurationSyntaxError
, enquanto você podeassert
não estar prestes a retornarNone
.No seu exemplo, se
x
for um valor definido por meio de uma interface com o usuário ou de uma fonte externa, uma exceção é a melhor.Se
x
for definido apenas pelo seu próprio código no mesmo programa, vá com uma asserção.fonte
assert
contém uma implícitaif __debug__
e pode ser otimizada de distância - como resposta de John Mee estadosAs instruções "assert" são removidas quando a compilação é otimizada . Então, sim, existem diferenças de desempenho e funcionais.
Se você costuma
assert
implementar a funcionalidade do aplicativo e otimizar a implantação na produção, será flagelado por defeitos "mas-funciona-no-dev".Veja PITONOTIMIZAR e -O -OO
fonte
raise
um emException
vez disso. Oh - Acabei de descobrir um nome apropriadoSuspiciousOperation
Exception
com subclasses emDjango
! Perfeito!bandit
seu código, ele avisará disso.Os quatro propósitos de
assert
Suponha que você trabalhe em 200.000 linhas de código com quatro colegas Alice, Bernd, Carl e Daphne. Eles chamam seu código, você chama o código deles.
Depois,
assert
tem quatro funções :Informe Alice, Bernd, Carl e Daphne o que seu código espera.
Suponha que você tenha um método que processa uma lista de tuplas e a lógica do programa pode ser quebrada se essas tuplas não forem imutáveis:
Isso é mais confiável do que informações equivalentes na documentação e muito mais fácil de manter.
Informe ao computador o que seu código espera.
assert
impõe o comportamento adequado dos chamadores do seu código. Se o seu código ligar para o código de Alices e Bernd, ligar para o seu, então sem oassert
, se o programa travar no código de Alices, Bernd pode assumir que foi culpa de Alice, Alice investiga e pode assumir que foi sua culpa, você investiga e diz a Bernd que era de fato seu. Muito trabalho perdido.Com afirmações, quem quer que receba uma ligação errada, será capaz de perceber rapidamente que a culpa foi deles, não sua. Alice, Bernd, e todos vocês se beneficiam. Economiza imenso tempo.
Informe os leitores do seu código (incluindo você mesmo) o que seu código alcançou em algum momento.
Suponha que você tenha uma lista de entradas e cada uma delas possa estar limpa (o que é bom) ou pode ser smorsh, trale, gullup ou twinkled (que não são aceitáveis). Se for torcido, deve ser firme; se for verdade, deve ser ignorado; se for gullup, deve ser trotado (e possivelmente passeado também); se estiver brilhando, deve voltar a brilhar, exceto às quintas-feiras. Você entende: são coisas complicadas. Mas o resultado final é (ou deveria ser) que todas as entradas estejam limpas. A coisa certa a fazer é resumir o efeito do seu ciclo de limpeza como
Essas declarações evitam uma dor de cabeça para todos que tentam entender exatamente o que o ciclo maravilhoso está alcançando. E a mais frequente dessas pessoas provavelmente será você mesma.
Informe ao computador o que seu código alcançou em algum momento.
Se você esquecer um ritmo de uma entrada que precisa dela após trotar,
assert
isso salvará seu dia e evitará que seu código quebre o querido Daphne muito mais tarde.Na minha opinião,
assert
os dois propósitos da documentação (1 e 3) e da proteção (2 e 4) são igualmente valiosos.Informar as pessoas pode até ser mais valioso do que informar o computador, pois pode evitar os mesmos erros que os
assert
objetivos visam detectar (no caso 1) e muitos erros subsequentes em qualquer caso.fonte
Além das outras respostas, as próprias declarações lançam exceções, mas apenas AssertionErrors. Do ponto de vista utilitarista, as asserções não são adequadas para quando você precisa de um controle fino sobre quais exceções você captura.
fonte
AssertionErrors
, quando você estiver bem com a granulação grossa. Na realidade, você não deveria estar pegando eles.A única coisa realmente errada com essa abordagem é que é difícil criar uma exceção muito descritiva usando declarações assert. Se você está procurando a sintaxe mais simples, lembre-se de que também pode fazer algo assim:
Outro problema é que o uso de assert para verificação de condição normal é dificultar a desabilitação das declarações de depuração usando o sinalizador -O.
fonte
A palavra em inglês aqui afirmada é usada no sentido de jurar , afirmar , declarar . Não significa "cheque" ou "deveria ser" . Isso significa que você, como codificador, está fazendo uma declaração juramentada aqui:
Se o código estiver correto, exceto distúrbios de evento único , falhas de hardware e outras, nenhuma declaração jamais falhará . É por isso que o comportamento do programa para um usuário final não deve ser afetado. Especialmente, uma afirmação não pode falhar, mesmo sob condições programáticas excepcionais . Isso simplesmente nunca acontece. Se isso acontecer, o programador deve ser acionado.
fonte
Como já foi dito anteriormente, asserções devem ser usadas quando seu código NÃO deve chegar a um ponto, o que significa que existe um erro. Provavelmente, a razão mais útil que vejo para usar uma asserção é uma invariável / pré / pós-condição. Isso é algo que deve ser verdadeiro no início ou no final de cada iteração de um loop ou de uma função.
Por exemplo, uma função recursiva (2 funções separadas para que 1 lide com entrada incorreta e a outra lida com código incorreto, pois é difícil distinguir com recursão). Isso tornaria óbvio se eu esquecesse de escrever a declaração if, o que havia dado errado.
Esses invariantes de loop geralmente podem ser representados com uma asserção.
fonte
#precondition: n >= 0
e uma declaração, ele pode apenas escrever@precondition(lambda n: n >= 0)
__doc__
atributo dando uma cadeia adicionalExiste um problema de desempenho?
Lembre-se de "fazê-lo funcionar primeiro antes de fazê-lo funcionar rapidamente" .
Muito poucos por cento de qualquer programa geralmente são relevantes para sua velocidade. Você sempre pode lançar ou simplificar um
assert
caso se mostre um problema de desempenho - e a maioria deles nunca será.Seja pragmático :
suponha que você tenha um método que processe uma lista não vazia de tuplas e a lógica do programa será interrompida se essas tuplas não forem imutáveis. Você deve escrever:
Provavelmente, isso é bom se suas listas tendem a ter dez entradas, mas pode se tornar um problema se tiverem um milhão de entradas. Mas, em vez de descartar completamente esse valioso cheque, você pode simplesmente fazer o downgrade para
que é barato, mas provavelmente captura a maioria dos erros reais do programa.
fonte
assert(len(listOfTuples)==0 or type(listOfTyples[0])==tuple)
.Bem, essa é uma pergunta em aberto e tenho dois aspectos nos quais quero abordar: quando adicionar asserções e como escrever as mensagens de erro.
Objetivo
Para explicar isso para um iniciante - asserções são declarações que podem gerar erros, mas você não as pegará. E eles normalmente não devem ser criados, mas na vida real às vezes são criados de qualquer maneira. E essa é uma situação séria, da qual o código não pode se recuperar, do que chamamos de 'erro fatal'.
Em seguida, é para 'fins de depuração', que, embora corretos, parece muito desdenhoso. Gosto mais da formulação 'declarar invariantes, que nunca deve ser violada', embora funcione de maneira diferente em iniciantes diferentes ... Alguns 'apenas entendem', e outros não encontram utilidade ou substituem exceções normais, ou mesmo controlar o fluxo com ele.
Estilo
Em Python,
assert
é uma declaração, não uma função! (lembre-assert(False, 'is true')
se que não aumentará. Mas, tendo isso fora do caminho:Quando e como escrever a 'mensagem de erro' opcional?
Isso se aplica de fato a estruturas de teste de unidade, que geralmente têm muitos métodos dedicados para fazer asserções (
assertTrue(condition)
,assertFalse(condition), assertEqual(actual, expected)
etc.). Eles geralmente também fornecem uma maneira de comentar a afirmação.No código descartável, você pode ficar sem as mensagens de erro.
Em alguns casos, não há nada a acrescentar à asserção:
def dump (algo): assert isinstance (algo, Dumpable) # ...
Além disso, uma mensagem é útil para comunicação com outros programadores (que às vezes são usuários interativos do seu código, por exemplo, no Ipython / Jupyter etc.).
Forneça informações, não apenas vaze detalhes de implementação interna.
ao invés de:
Escreva:
ou talvez até:
Eu sei, eu sei - esse não é um caso de afirmação estática, mas quero apontar para o valor informativo da mensagem.
Mensagem negativa ou positiva?
Isso pode ser absurdo, mas me dói ler coisas como:
estas são duas coisas contraditórias escritas próximas uma da outra. Portanto, sempre que influencio a base de código, insisto em especificar o que queremos, usando verbos extras como 'must' e 'should', sem dizer o que não queremos.
afirme a == b, 'a deve ser igual a b'
Então, get
AssertionError: a must be equal to b
também é legível e a instrução parece lógica no código. Além disso, você pode obter algo sem ler o traceback (que às vezes nem pode estar disponível).fonte
Tanto o uso
assert
como o levantamento de exceções são sobre comunicação.Asserções são declarações sobre a exatidão do código endereçado aos desenvolvedores : Uma asserção no código informa os leitores do código sobre as condições que devem ser cumpridas para que o código esteja correto. Uma asserção que falha no tempo de execução informa aos desenvolvedores que há um defeito no código que precisa ser corrigido.
Exceções são indicações sobre situações não típicas que podem ocorrer em tempo de execução, mas não podem ser resolvidas pelo código em questão, endereçado no código de chamada a ser tratado lá. A ocorrência de uma exceção não indica que há um erro no código.
Portanto, se você considerar a ocorrência de uma situação específica em tempo de execução como um bug sobre o qual gostaria de informar os desenvolvedores ("Olá desenvolvedor, essa condição indica que há um bug em algum lugar, corrija o código"). vá para uma afirmação. Se a asserção verificar os argumentos de entrada do seu código, você deverá adicionar à documentação que seu código tem "comportamento indefinido" quando os argumentos de entrada violarem essas condições.
Se, em vez disso, a ocorrência dessa mesma situação não é uma indicação de um erro em seus olhos, mas uma situação (talvez rara, mas possível) que você acha que deveria ser tratada pelo código do cliente, crie uma exceção. As situações em que a exceção é gerada devem fazer parte da documentação do respectivo código.
A avaliação das afirmações leva algum tempo. Eles podem ser eliminados no momento da compilação. Isso tem algumas consequências, no entanto, veja abaixo.
Normalmente, as asserções melhoram a capacidade de manutenção do código, pois melhoram a legibilidade, tornando explícitas as suposições e durante o tempo de execução, verificando regularmente essas suposições. Isso também ajudará a capturar regressões. Há um problema, no entanto, que precisa ser lembrado: as expressões usadas nas asserções não devem ter efeitos colaterais. Como mencionado acima, as asserções podem ser eliminadas em tempo de compilação - o que significa que também os possíveis efeitos colaterais desapareceriam. Isso pode - sem querer - alterar o comportamento do código.
fonte
Uma afirmação é verificar:
1. a condição válida,
2. a declaração válida,
3. verdadeira lógica;
do código fonte. Em vez de falhar em todo o projeto, é emitido um alarme de que algo não é apropriado no seu arquivo de origem.
No exemplo 1, como a variável 'str' não é nula. Portanto, nenhuma afirmação ou exceção é levantada.
Exemplo 1:
No exemplo 2, var 'str' é nulo. Portanto, estamos a poupar o usuário de ir à frente do programa defeituoso por assert comunicado.
Exemplo 2:
No momento em que não queremos depuração, percebemos o problema de afirmação no código-fonte. Desativar o sinalizador de otimização
python -O assertStatement.py
nada será impresso
fonte
Em IDEs como PTVS, PyCharm, as
assert isinstance()
instruções Wing podem ser usadas para permitir a conclusão do código para alguns objetos pouco claros.fonte
typing.cast
.Pelo que vale a pena, se você estiver lidando com um código que depende
assert
para funcionar corretamente, a adição do código a seguir garantirá que as declarações sejam ativadas:fonte