Desativar asserções em Python

Respostas:

80

Como desativo asserções em Python?

Existem várias abordagens que afetam um único processo, o ambiente ou uma única linha de código.

Eu demonstro cada um.

Para todo o processo

Usar o -Osinalizador (maiúsculo) desativa todas as instruções assert em um processo.

Por exemplo:

$ python -Oc "assert False"

$ python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError

Observe que por desativar quero dizer que também não executa a expressão que o segue:

$ python -Oc "assert 1/0"

$ python -c "assert 1/0"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

Para o meio ambiente

Você também pode usar uma variável de ambiente para definir esse sinalizador.

Isso afetará todos os processos que usam ou herdam o ambiente.

Por exemplo, no Windows, configurar e limpar a variável de ambiente:

C:\>python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError
C:\>SET PYTHONOPTIMIZE=TRUE

C:\>python -c "assert False"

C:\>SET PYTHONOPTIMIZE=

C:\>python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError

Mesmo no Unix (usando definir e não definir para a respectiva funcionalidade)

Ponto único no código

Você continua sua pergunta:

se uma afirmação falhar, não quero que ela lance um AssertionError, mas continue.

Se você quiser que o código não seja executado, você pode garantir que o fluxo de controle não alcance a asserção, por exemplo:

if False:
    assert False, "we know this fails, but we don't get here"

ou você pode detectar o erro de asserção:

try:
    assert False, "this code runs, fails, and the exception is caught"
except AssertionError as e:
    print(repr(e))

que imprime:

AssertionError('this code runs, fails, and the exception is caught')

e você continuará a partir do ponto em que manipulou o AssertionError.

Referências

A partir da assertdocumentação :

Uma declaração assert como esta:

assert expression #, optional_message

É equivalente a

if __debug__:
    if not expression: raise AssertionError #(optional_message)

E,

a variável embutida __debug__está Trueem circunstâncias normais, Falsequando a otimização é solicitada (opção de linha de comando -O).

e mais

As atribuições a __debug__são ilegais. O valor da variável embutida é determinado quando o interpretador é iniciado.

Dos documentos de uso:

-O

Ative as otimizações básicas. Isso muda a extensão do nome do arquivo para arquivos compilados (bytecode) de .pyc para .pyo. Veja também PYTHONOPTIMIZE.

e

PITONOTIMIZAR

Se for definido como uma string não vazia, é equivalente a especificar a -Oopção. Se definido como um inteiro, é equivalente a especificar -Ovárias vezes.

Aaron Hall
fonte
seria possível ignorar o código que falha no caso de 'Ponto único no código'? Tentei definir __debug__como False, mas isso não é permitido.
Matthijs
1
@Matthijs você pode garantir que o fluxo de controle não o alcance (por exemplo if False: assert False) ou pode capturar o erro de declaração. Essas são suas escolhas. Atualizada a resposta para responder à sua pergunta.
Aaron Hall
Obrigado pela resposta, mas ainda não completamente no que eu estava pensando. Gostaria de desativar afirma dentro de uma função durante o tempo de execução, de preferência com algum tipo de gerente de contexto: afirmação é avaliado: foo()e afirmações de comutação off: with skip_assertion(): foo(). A vantagem disso é que não preciso adicionar outro sinalizador na função
Matthijs
2
Você pode reescrever o bytecode da função, reescrever o AST ou reescrever a própria função. (manualmente ou programaticamente, para qualquer um). Reescrever o AST provavelmente seria a abordagem mais confiável ("simplesmente" substituir Assertobjetos por Passobjetos). Um gerenciador de contexto não funcionaria diretamente para isso, mas você poderia ter algum tipo de mecanismo que usasse funções decoradas dessa maneira. Apesar de tudo, não o recomendo. Suspeito que você queira fazer isso por estar chamando um código que não controla e obtendo AssertionErrors. Em caso afirmativo, você provavelmente precisará encontrar uma solução diferente.
Aaron Hall
60

Chame Python com a sinalização -O:

test.py:

assert(False)
print 'Done'

Resultado:

C:\temp\py>C:\Python26\python.exe test.py
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    assert(False)
AssertionError

C:\temp\py>C:\Python26\python.exe -O test.py
Done
Mark Rushakoff
fonte
9
Assert não é uma função, então os parênteses são supérfluos.
Aaron Hall
15

Ambas as respostas já fornecidas são válidas (chame Python com -Oou -OOna linha de comando).

Aqui está a diferença entre eles:

  • -OAtive as otimizações básicas. Isso muda a extensão do nome do arquivo para arquivos compilados (bytecode) de .pyc para .pyo.

  • -OODescarte docstrings além das -Ootimizações.

(Da documentação do Python )

Michael Currie
fonte
7

Use python -O:

$ python -O
>>> assert False
>>> 
John Millikin
fonte
3

Você NÃO deve desabilitar (a maioria) asserções. Eles detectam erros imprevistos quando a atenção está em outro lugar. Consulte a Regra 5 em "A potência de dez" .

Em vez disso, guarde algumas verificações de afirmações caras por algo como:

import logging
logger = logging.getLogger(__name__)

if logger.getEffectiveLevel() < logging.DEBUG:
    ok = check_expensive_property()
    assert ok, 'Run !'

Uma maneira de manter afirmações importantes e permitir que as assertafirmações sejam otimizadas é levantando-as em uma instrução de seleção:

if foo_is_broken():
    raise AssertionError('Foo is broken!')
Ioannis Filippidis
fonte
1
//, O problema é, porém, que a instrução ainda aumenta a complexidade ciclomática e o tratamento de erros deve cuidar do resto?
Nathan Basanese
1
As afirmações que seriam protegidas como acima são chamadas caras que reduzem significativamente a execução. Para alguns algoritmos, verificações desse tipo podem levar ordens de magnitude mais longas do que todo o programa. Pense em executar uma implementação ingênua, mas mais simples (menos provável de conter erros) do mesmo algoritmo para verificar a exatidão. Ou uma verificação por enumeração exaustiva de algo que está fora de questão para operação normal.
Ioannis Filippidis
Não vejo muitos problemas com a legibilidade, porque tal instrução não adiciona aninhamento ao código. Extraí-lo como uma chamada de função pode tirá-lo do caminho, se isso for um problema (e espero que tal refatoração reduza a complexidade ciclomática). Em qualquer caso, a complexidade ciclomática não deve reger as verificações de segurança.
Ioannis Filippidis
2

Executar no modo otimizado deve resolver:

python -OO module.py
FogleBird
fonte