python assert com e sem parênteses

104

Aqui estão quatro invocações simples de assert:

>>> assert 1==2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError

>>> assert 1==2, "hi"
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError: hi

>>> assert(1==2)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError

>>> assert(1==2, "hi")

Observe que o último não gera um erro. Qual é a diferença entre chamar assert com ou sem parênteses que causa esse comportamento? Minha prática é usar parênteses, mas o que foi dito acima sugere que eu não deveria.

Gaefan
fonte
Obrigado pelas respostas úteis. A distinção entre palavras-chave e funções internas parece sutil. Aqui está uma lista de palavras-chave, para as quais presumo, os parênteses devem ser deixados de fora: docs.python.org/reference/lexical_analysis.html#keywords
gaefan
2
Uma diferença é que você pode redefinir as funções integradas, mas não pode fazer isso com palavras-chave (não que a primeira seja uma boa ideia).
gaefan
Não é distinção de função versus palavra-chave, mas sim de chamada de função versus instrução . (por exemplo - print costumava ser uma declaração e funcionava sem parênteses).
Tomasz Gandor

Respostas:

129

O último assertteria dado a você um aviso ( SyntaxWarning: assertion is always true, perhaps remove parentheses?) se você o executasse por meio de um interpretador completo, não por meio do IDLE. Por assertser uma palavra-chave e não uma função, você está, na verdade, passando uma tupla como o primeiro argumento e omitindo o segundo argumento.

Lembre-se de que tuplas não vazias avaliam como Truee, como a mensagem de asserção é opcional, você essencialmente chamou assert Truequando escreveu assert(1==2, "hi").

Mark Rushakoff
fonte
10
A razão é que isso não acontece porque os assert (1==2)parênteses em torno de uma única expressão não criarão uma tupla automaticamente; você obteria o mesmo comportamento de # 4 se o fizesse assert (1==2,). A mesma coisa aconteceria se você fizesse em print ('foo', 'bar')vez de print 'foo', 'bar'; você veria a saída da tupla
Michael Mrozek
Vale a pena enfatizar ainda que as declarações da forma assert(test, message)provavelmente estão erradas, e certamente confusas. Sem parênteses!
tcarobruce
19
Então, qual é a maneira adequada de indentar uma declaração de afirmação longa, wrt PEP8? Parece impossível.
stantonk
30

Se você colocou o parêntese aqui porque queria uma declaração de várias linhas, uma alternativa é colocar uma barra invertida no final da linha como esta:

foo = 7
assert foo == 8, \
    "derp should be 8, it is " + str(foo)

Impressões:

AssertionError: "derp should be 8, it is 7

Por que esse python assertprecisa ser diferente de tudo o mais:

Acho que a ideologia pitônica é que um programa deve se autocorrigir sem ter que se preocupar com o sinalizador especial para ativar as afirmações. A tentação de desativar afirmações é muito grande e, portanto, está sendo descontinuada.

Compartilho seu aborrecimento pelo fato de o python assertter uma sintaxe exclusiva em relação a todas as outras construções de programação do python, e essa sintaxe mais uma vez mudou de python2 para python3 e novamente de python 3.4 para 3.6. Fazer afirmações não compatíveis com versões anteriores de qualquer versão para qualquer outra versão.

É um tapinha no ombro de assertum cidadão de 3ª classe, será totalmente removido no python4 e, certamente, novamente no Python 8.1.

Eric Leschinski
fonte
2
Existe algum documento sobre o que devemos usar em vez de afirmar? Assert parece ser um nome lógico para validação e tem o comportamento desejado, por exemplo, mostrar uma mensagem especial em caso de erro.
AnneTheAgile
18

assert 1==2, "hi"é analisado assert 1==2, "hi"com "hi" como o segundo parâmetro da palavra-chave. Daí porque ele dá um erro apropriadamente.

assert(1==2)é analisado como assert (1==2)sendo idêntico a assert 1==2, porque os parênteses em torno de um único item não criam uma tupla, a menos que haja uma vírgula final, por exemplo (1==2,).

assert(1==2, "hi")é analisado como assert (1==2, "hi"), o que não dá um erro porque uma tupla (False, "hi")não vazia não é um valor falso e não há um segundo parâmetro fornecido para a palavra-chave.

Você não deve usar parênteses porque assertnão é uma função em Python - é uma palavra-chave.

Âmbar
fonte
13

Você pode quebrar a declaração assert sem fazer \isso:

foo = 7
assert foo == 8, (
    'derp should be 8, it is ' + str(foo))

Ou se você tiver uma mensagem ainda mais longa:

foo = 7
assert foo == 8, (
    'Lorem Ipsum is simply dummy text of the printing and typesetting '
    'industry. Lorem Ipsum has been the industry\'s standard dummy text '
    'ever since the 1500s'
)
karantan
fonte
1
Idéia interessante. Eu odeio barras invertidas para continuação, e esta é uma alternativa para envolver assert em uma função de utilidade (que foi minha solução).
Tomasz Gandor
1

A seguir é citado a partir do documento python

As declarações de declaração são uma maneira conveniente de inserir declarações de depuração em um programa:

assert_stmt ::= "assert" expression ["," expression]

A forma simples, expressão assert, é equivalente a if __debug__: if not expression: raise AssertionError

A forma estendida, assert expression1, expression2 , é equivalente a if __debug__: if not expression1: raise AssertionError(expression2)

Então, quando você está usando parênteses aqui, você está usando a forma simples, e a expressão é avaliada como uma tupla, que é sempre True quando convertida em bool

VicX
fonte