Respostas:
A assert
declaração existe em quase todas as linguagens de programação. Ajuda a detectar problemas no início do seu programa, onde a causa é clara, e não mais tarde, como efeito colateral de alguma outra operação.
Quando você faz...
assert condition
... você está dizendo ao programa para testar essa condição e acionar imediatamente um erro se a condição for falsa.
No Python, é aproximadamente equivalente a isso:
if not condition:
raise AssertionError()
Experimente no shell Python:
>>> assert True # nothing happens
>>> assert False
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
As asserções podem incluir uma mensagem opcional e você pode desabilitá-las ao executar o intérprete.
Para imprimir uma mensagem se a asserção falhar:
assert False, "Oh no! This assertion failed!"
Você não usar parêntesis para chamar assert
como uma função. É uma afirmação. Se você o fizer, assert(condition, message)
estará executando o assert
com uma (condition, message)
tupla como primeiro parâmetro.
Quanto à desativação deles, quando executados python
no modo otimizado, onde __debug__
estão False
, as declarações de asserção serão ignoradas. Apenas passe a -O
bandeira:
python -O script.py
Veja aqui a documentação relevante.
if not condition: raise AssertError()
, por que devo usar assert? Existem condições sob as quais a afirmação é melhor do que apenas ser uma forma mais curta de if not condition
afirmação?
if
). Leia os documentos para obter mais informações :)
assert
, mas depois de ler todas as respostas, não tenho absolutamente nada que eu queira!
Cuidado com os parênteses. Como foi apontado acima, no Python 3, assert
ainda é uma afirmação ; portanto, por analogia com print(..)
, pode-se extrapolar o mesmo para assert(..)
ou raise(..)
mas você não deveria.
Isso é importante porque:
assert(2 + 2 == 5, "Houston we've got a problem")
não vai funcionar, ao contrário
assert 2 + 2 == 5, "Houston we've got a problem"
A razão pela qual o primeiro não funcionará é que ele é bool( (False, "Houston we've got a problem") )
avaliado True
.
Na declaração assert(False)
, esses são apenas parênteses redundantes False
, que avaliam seu conteúdo. Mas com assert(False,)
os parênteses agora são uma tupla, e uma tupla não vazia é avaliada True
em um contexto booleano.
assert (2 + 2 = 5), "Houston we've got a problem"
deve ficar bem, sim?
assert (2 + 2 = 5), "Houston we've got a problem"
não funcionará ... mas não tem nada a ver com a declaração assert, o que é bom. Sua condição não funcionará porque não é uma condição. Faltando um segundo =
.
Como outras respostas observaram, assert
é semelhante a lançar uma exceção se uma determinada condição não for verdadeira. Uma diferença importante é que as instruções assert são ignoradas se você compilar seu código com a opção de otimização -O
. A documentação diz que assert expression
pode ser melhor descrito como sendo equivalente a
if __debug__:
if not expression: raise AssertionError
Isso pode ser útil se você quiser testar completamente seu código e liberar uma versão otimizada quando estiver feliz que nenhum dos seus casos de afirmação falhe - quando a otimização estiver ativada, a __debug__
variável se tornará False e as condições deixarão de ser avaliadas. Esse recurso também pode capturá-lo se você confiar nas declarações e não perceber que elas desapareceram.
if Not Error: raise Exception(“ this is a error”)
? Dessa forma, o programa ainda vai mostrar a origem do erro, quando o usuário executa-lo ..
assert
instrução? A suposição aqui é que, quando o programa é lançado para o usuário final, você está usando o sinalizador -O, assumindo que todos os erros foram removidos. Portanto, qualquer erro ou falha no programa deve-se à entrada no programa que é válida de acordo com o contrato, mas não pode ser tratada pelo programa. Portanto, ele deve alertar o usuário como tal.
O objetivo de uma asserção no Python é informar os desenvolvedores sobre erros irrecuperáveis em um programa.
As asserções não pretendem sinalizar as condições de erro esperadas, como “arquivo não encontrado”, em que um usuário pode executar uma ação corretiva (ou apenas tentar novamente).
Outra maneira de ver isso é dizer que as asserções são auto-verificações internas no seu código. Eles funcionam declarando algumas condições como impossíveis no seu código. Se essas condições não se mantiverem, isso significa que há um erro no programa.
Se o seu programa estiver livre de erros, essas condições nunca ocorrerão. Mas se um deles faz ocorrer o programa irá falhar com um erro de declaração dizendo exatamente qual condição “impossível” foi acionado. Isso torna muito mais fácil rastrear e corrigir erros em seus programas.
Aqui está um resumo de um tutorial sobre as afirmações de Python que escrevi:
A declaração assertiva do Python é um auxiliar de depuração, não um mecanismo para lidar com erros em tempo de execução. O objetivo do uso de asserções é permitir que os desenvolvedores encontrem a causa raiz provável de um bug mais rapidamente. Um erro de declaração nunca deve ser gerado, a menos que haja um erro no seu programa.
assert
declaração e quando usá-la. Estou tentando entender vários termos que você introduziu no artigo.
assert store.product_exists(product_id), 'Unknown product id'
não é uma boa prática, porque se a depuração for desativada, o user
mesmo se não admin
for capaz de excluir o produto. Você considera assert user.is_admin()
um unrecoverable
erro? Por que isso não é um self-check
?
assert statement
, price
também não pode ser considerada uma entrada do usuário? Por que você considera assert user.is_admin()
validação de dados, mas não assert price
?
Outros já lhe deram links para a documentação.
Você pode tentar o seguinte em um shell interativo:
>>> assert 5 > 2
>>> assert 2 > 5
Traceback (most recent call last):
File "<string>", line 1, in <fragment>
builtins.AssertionError:
A primeira declaração não faz nada, enquanto a segunda gera uma exceção. Esta é a primeira dica: asserts são úteis para verificar condições que devem ser verdadeiras em uma determinada posição do seu código (geralmente, o início (pré-condições) e o final de uma função (pós-condições)).
Afirmações são realmente altamente ligadas à programação por contrato, o que é uma prática de engenharia muito útil:
Dos documentos:
Assert statements are a convenient way to insert debugging assertions into a program
Aqui você pode ler mais: http://docs.python.org/release/2.5.2/ref/assert.html
A declaração assert possui duas formas.
A forma simples,, assert <expression>
é equivalente a
if __debug__:
if not <expression>: raise AssertionError
O formulário estendido,, assert <expression1>, <expression2>
é equivalente a
if __debug__:
if not <expression1>: raise AssertionError, <expression2>
As asserções são uma maneira sistemática de verificar se o estado interno de um programa é o esperado pelo programador, com o objetivo de detectar bugs. Veja o exemplo abaixo.
>>> number = input('Enter a positive number:')
Enter a positive number:-1
>>> assert (number > 0), 'Only positive numbers are allowed!'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: Only positive numbers are allowed!
>>>
Aqui está um exemplo simples, salve-o no arquivo (digamos b.py)
def chkassert(num):
assert type(num) == int
chkassert('a')
e o resultado quando $python b.py
Traceback (most recent call last):
File "b.py", line 5, in <module>
chkassert('a')
File "b.py", line 2, in chkassert
assert type(num) == int
AssertionError
se a declaração após a afirmação for verdadeira, o programa continuará, mas se a declaração após a afirmação for falsa, o programa emitirá um erro. Simples assim.
por exemplo:
assert 1>0 #normal execution
assert 0>1 #Traceback (most recent call last):
#File "<pyshell#11>", line 1, in <module>
#assert 0>1
#AssertionError
A assert
declaração existe em quase todas as linguagens de programação. Ajuda a detectar problemas no início do seu programa, onde a causa é clara, e não mais tarde, como efeito colateral de alguma outra operação. Eles sempre esperam uma True
condição.
Quando você faz algo como:
assert condition
Você está dizendo ao programa para testar essa condição e acionar imediatamente um erro, se for falso.
Em Python, assert
expressão é equivalente a:
if __debug__:
if not <expression>: raise AssertionError
Você pode usar a expressão estendida para passar uma mensagem opcional :
if __debug__:
if not (expression_1): raise AssertionError(expression_2)
Experimente no intérprete Python:
>>> assert True # Nothing happens because the condition returns a True value.
>>> assert False # A traceback is triggered because this evaluation did not yield an expected value.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
Existem algumas ressalvas a serem vistas antes de usá-las principalmente para aqueles que consideram alternar entre as declarações assert
e if
. O objetivo a ser usado assert
é em ocasiões em que o programa verifica uma condição e retorna um valor que deve interromper o programa imediatamente, em vez de usar uma maneira alternativa de contornar o erro:
Como você deve ter notado, a assert
declaração usa duas condições. Portanto, não use parênteses para incluí-los como um conselho óbvio. Se você faz como:
assert (condition, message)
Exemplo:
>>> assert (1==2, 1==1)
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
Você estará executando o assert
com a (condition, message)
que representa uma tupla como o primeiro parâmetro, e isso acontece porque a tupla não vazia no Python é sempreTrue
. No entanto, você pode fazer separadamente sem problemas:
assert (condition), "message"
Exemplo:
>>> assert (1==2), ("This condition returns a %s value.") % "False"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: This condition returns a False value.
Se você está se perguntando sobre quando usar a assert
declaração. Veja um exemplo usado na vida real:
* Quando seu programa tende a controlar cada parâmetro inserido pelo usuário ou qualquer outra coisa:
def loremipsum(**kwargs):
kwargs.pop('bar') # return 0 if "bar" isn't in parameter
kwargs.setdefault('foo', type(self)) # returns `type(self)` value by default
assert (len(kwargs) == 0), "unrecognized parameter passed in %s" % ', '.join(kwargs.keys())
* Outro caso é na matemática quando 0 ou não positivo como coeficiente ou constante em uma determinada equação:
def discount(item, percent):
price = int(item['price'] * (1.0 - percent))
print(price)
assert (0 <= price <= item['price']),\
"Discounted prices cannot be lower than 0 "\
"and they cannot be higher than the original price."
return price
* ou mesmo um exemplo simples de implementação booleana:
def true(a, b):
assert (a == b), "False"
return 1
def false(a, b):
assert (a != b), "True"
return 0
A maior importância é não confiar na assert
instrução para executar o processamento ou a validação de dados, pois essa instrução pode ser desativada na inicialização do Python com -O
ou -OO
flag - ou seja, valores 1, 2 e 0 (como padrão), respectivamente - ou PYTHONOPTIMIZE
variável de ambiente .
Valor 1:
* afirmações estão desativadas;
* arquivos de bytecode são gerados usando .pyo
extensão em vez de .pyc
;
* sys.flags.optimize
está definido como 1 ( True
);
* e, __debug__
está definido comoFalse
;
Valor 2: desativa mais uma coisa
* docstrings estão desabilitadas;
Portanto, o uso da assert
instrução para validar um tipo de dado esperado é extremamente perigoso, implicando até alguns problemas de segurança. Então, se você precisar validar alguma permissão, recomendo raise AuthError
. Como efetivo pré-condicional, um assert
é comumente usado por programadores em bibliotecas ou módulos que não têm um usuário para interagir diretamente.
Como resumido de forma concisa no C2 Wiki :
Uma asserção é uma expressão booleana em um ponto específico de um programa que será verdadeiro, a menos que haja um erro no programa.
Você pode usar uma assert
instrução para documentar sua compreensão do código em um ponto específico do programa. Por exemplo, você pode documentar suposições ou garantias sobre entradas (pré-condições), estado do programa (invariantes) ou saídas (pós-condições).
Se sua afirmação falhar, este é um alerta para você (ou seu sucessor) de que seu entendimento do programa estava errado quando você o escreveu e que provavelmente contém um bug.
Para obter mais informações, John Regehr tem um maravilhoso post sobre o uso de asserções , que também se aplica à assert
declaração Python .
O Python assert é basicamente um auxiliar de depuração que testa a condição de autoverificação interna do seu código. A declaração torna a depuração realmente fácil quando o seu código entra em casos extremos impossíveis. Afirme verificar esses casos impossíveis.
Digamos que haja uma função para calcular o preço do item após o desconto:
def calculate_discount(price, discount):
discounted_price = price - [discount*price]
assert 0 <= discounted_price <= price
return discounted_price
aqui, o preço com desconto nunca pode ser menor que 0 e maior que o preço real. Portanto, caso a condição acima seja violada, a declaração gera um erro de declaração, que ajuda o desenvolvedor a identificar que algo impossível aconteceu.
Espero que ajude :)
assert
é útil em um contexto de depuração, mas não deve ser invocado fora de um contexto de depuração.
Minha breve explicação é:
assert
aumenta AssertionError
se a expressão for falsa, caso contrário, apenas continua o código, e se houver uma vírgula, seja como for AssertionError: whatever after comma
, e o código é como:raise AssertionError(whatever after comma)
Um tutorial relacionado sobre isso:
https://www.tutorialspoint.com/python/assertions_in_python.htm
assert
, mas não quando usar (ou não usar) um assert
; também observando que um assert
pode ser desativado se __debug__
for False
seria útil.
No Pycharm, se você usar assert
junto com isinstance
para declarar o tipo de um objeto, ele permitirá que você acesse os métodos e atributos do objeto pai enquanto estiver codificando, ele será concluído automaticamente.
Por exemplo, digamos que self.object1.object2
seja um MyClass
objeto.
import MyClasss
def code_it(self):
testObject = self.object1.object2 # at this point, program doesn't know that testObject is a MyClass object yet
assert isinstance(testObject , MyClasss) # now the program knows testObject is a MyClass object
testObject.do_it() # from this point on, PyCharm will be able to auto-complete when you are working on testObject
Conforme escrito em outras respostas, as assert
instruções são usadas para verificar o estado do programa em um determinado momento.
Não repetirei o que foi dito sobre mensagens, parênteses ou -O
opção e __debug__
constante associados . Consulte também o documento para obter informações em primeira mão. Vou me concentrar na sua pergunta: de que serve assert
? Mais precisamente, quando (e quando não) deve-se usar assert
?
As assert
instruções são úteis para depurar um programa, mas são desencorajadas a verificar a entrada do usuário. Eu uso a seguinte regra geral: mantenha asserções para detectar uma situação que isso não deve acontecer . Uma entrada do usuário pode estar incorreta, por exemplo, uma senha muito curta, mas essa não é uma isso não deve acontecer . Se o diâmetro de um círculo não for duas vezes maior que seu raio, você está nesse caso.
O uso mais interessante, em minha opinião, assert
é inspirado na
programação por contrato, conforme descrito por B. Meyer em [Construção de software orientada a objetos] (
https://www.eiffel.org/doc/eiffel/Object-Oriented_Software_Construction% 2C_2nd_Edition
) e implementado na [linguagem de programação Eiffel] (
https://en.wikipedia.org/wiki/Eiffel_(programming_language) ). Você não pode emular completamente a programação por contrato usando a assert
declaração, mas é interessante manter a intenção.
Aqui está um exemplo. Imagine que você precise escrever uma head
função (como a [ head
função em Haskell] (
http://www.zvon.org/other/haskell/Outputprelude/head_f.html )). A especificação que você recebe é: "se a lista não estiver vazia, retorne o primeiro item de uma lista". Veja as seguintes implementações:
>>> def head1(xs): return xs[0]
E
>>> def head2(xs):
... if len(xs) > 0:
... return xs[0]
... else:
... return None
(Sim, isso pode ser escrito como return xs[0] if xs else None
, mas esse não é o ponto) .
Se a lista não estiver vazia, ambas as funções terão o mesmo resultado e este resultado está correto:
>>> head1([1, 2, 3]) == head2([1, 2, 3]) == 1
True
Portanto, ambas as implementações estão (espero) corretas. Eles diferem quando você tenta obter o item principal de uma lista vazia:
>>> head1([])
Traceback (most recent call last):
...
IndexError: list index out of range
Mas:
>>> head2([]) is None
True
Novamente, ambas as implementações estão corretas, porque ninguém deve passar uma lista vazia para essas funções (estamos fora da especificação ). Essa é uma ligação incorreta, mas se você fizer essa ligação, tudo poderá acontecer. Uma função gera uma exceção, a outra retorna um valor especial. O mais importante é: não podemos confiar nesse comportamento . Se xs
estiver vazio, isso funcionará:
print(head2(xs))
Mas isso irá travar o programa:
print(head1(xs))
Para evitar algumas surpresas, gostaria de saber quando estou passando algum argumento inesperado para uma função. Em outras palavras: eu gostaria de saber quando o comportamento observável não é confiável, porque depende da implementação, não da especificação. Obviamente, eu posso ler a especificação, mas os programadores nem sempre leem com atenção os documentos.
Imagine se eu tivesse uma maneira de inserir a especificação no código para obter o seguinte efeito: quando eu viole a especificação, por exemplo, passando uma lista vazia para head
, recebo um aviso. Isso seria uma grande ajuda para escrever um programa correto (ou seja, compatível com a especificação). E é aí que assert
entra em cena:
>>> def head1(xs):
... assert len(xs) > 0, "The list must not be empty"
... return xs[0]
E
>>> def head2(xs):
... assert len(xs) > 0, "The list must not be empty"
... if len(xs) > 0:
... return xs[0]
... else:
... return None
Agora, temos:
>>> head1([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty
E:
>>> head2([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty
Observe que head1
lança um AssertionError
, não um IndexError
. Isso é importante porque um AssertionError
não é nenhum erro de execução: ele sinaliza uma violação da especificação. Eu queria um aviso, mas recebo um erro. Felizmente, posso desativar a verificação (usando a -O
opção), mas por minha conta e risco. Vou fazê-lo um acidente é realmente caro, e espero o melhor. Imagine que meu programa está incorporado em uma nave espacial que viaja através de um buraco negro. Desabilitarei as afirmações e espero que o programa seja robusto o suficiente para não travar o maior tempo possível.
Este exemplo foi apenas sobre pré-condições, você pode usar assert
para verificar pós-condições (o valor de retorno e / ou o estado) e invariantes (estado de uma classe). Observe que a verificação de pós-condições e invariantes assert
pode ser complicada:
Você não terá algo tão sofisticado quanto o Eiffel, mas, no entanto, pode melhorar a qualidade geral de um programa.
Para resumir, a assert
declaração é uma maneira conveniente de detectar uma situação que não deve acontecer . Violações da especificação (por exemplo, passar uma lista vazia para head
) são de primeira classe; isso não deve ocorrer em situações. Portanto, embora a assert
declaração possa ser usada para detectar qualquer situação inesperada, é uma maneira privilegiada de garantir que a especificação seja cumprida. Depois de inserir assert
instruções no código para representar a especificação, podemos esperar que você tenha melhorado a qualidade do programa, porque argumentos incorretos, valores de retorno incorretos, estados incorretos de uma classe ... serão relatados.
formato: assert Expression [, argumentos] Quando assert encontra uma instrução, o Python avalia a expressão.Se a instrução não for verdadeira, uma exceção será gerada (assertionError). Se a asserção falhar, o Python usará ArgumentExpression como argumento para o AssertionError. As exceções AssertionError podem ser capturadas e manipuladas como qualquer outra exceção usando a instrução try-except, mas se não forem tratadas, elas encerrarão o programa e produzirão um retorno. Exemplo:
def KelvinToFahrenheit(Temperature):
assert (Temperature >= 0),"Colder than absolute zero!"
return ((Temperature-273)*1.8)+32
print KelvinToFahrenheit(273)
print int(KelvinToFahrenheit(505.78))
print KelvinToFahrenheit(-5)
Quando o código acima é executado, ele produz o seguinte resultado:
32.0
451
Traceback (most recent call last):
File "test.py", line 9, in <module>
print KelvinToFahrenheit(-5)
File "test.py", line 4, in KelvinToFahrenheit
assert (Temperature >= 0),"Colder than absolute zero!"
AssertionError: Colder than absolute zero!
def getUser(self, id, Email):
user_key = id and id or Email
assert user_key
Pode ser usado para garantir que os parâmetros sejam passados na chamada de função.
if not user_key: raise ValueError()
check últimos 2 parágrafos aqui: wiki.python.org/moin/UsingAssertionsEffectively
assert
não deve ser usado para validação de entrada porque a validação será removida, se __debug__
estiver False
. Também usar asserções para fins de não depuração pode fazer com que as pessoas capturem os AssertionError
s resultantes , o que pode dificultar a depuração em vez de menos.
>>>this_is_very_complex_function_result = 9
>>>c = this_is_very_complex_function_result
>>>test_us = (c < 4)
>>> #first we try without assert
>>>if test_us == True:
print("YES! I am right!")
else:
print("I am Wrong, but the program still RUNS!")
I am Wrong, but the program still RUNS!
>>> #now we try with assert
>>> assert test_us
Traceback (most recent call last):
File "<pyshell#52>", line 1, in <module>
assert test_us
AssertionError
>>>
Basicamente, o significado da palavra-chave assert é que, se a condição não for verdadeira, ela será processada através de um erro de asserção, caso contrário, continuará, por exemplo, em python.
código-1
a=5
b=6
assert a==b
RESULTADO:
assert a==b
AssertionError
código-2
a=5
b=5
assert a==b
RESULTADO:
Process finished with exit code 0
assert
, mas não responde quando usar (ou não usar) um assert
.