Python afirmar con y sin paréntesis

104

Aquí hay cuatro invocaciones 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")

Tenga en cuenta que el último no genera ningún error. ¿Cuál es la diferencia entre llamar a assert con o sin paréntesis que causa este comportamiento? Mi práctica es usar paréntesis, pero lo anterior sugiere que no debería.

gaefan
fuente
Gracias por las útiles respuestas. La distinción entre palabras clave y funciones integradas parece sutil. Aquí hay una lista de palabras clave, para las cuales supongo, los parens deben omitirse
gaefan
2
Una diferencia es que puede redefinir las funciones integradas, pero no puede hacerlo con palabras clave (no es que la primera sea una buena idea).
gaefan
No se trata de una distinción entre función y palabra clave, sino llamada de función frente a declaración . (por ejemplo, imprimir solía ser una declaración y funcionaba sin paréntesis).
Tomasz Gandor

Respuestas:

129

El último assertle habría dado una advertencia ( SyntaxWarning: assertion is always true, perhaps remove parentheses?) si lo ejecutó a través de un intérprete completo, no a través de IDLE. Debido a que assertes una palabra clave y no una función, en realidad está pasando una tupla como primer argumento y omitiendo el segundo argumento.

Recuerde que las tuplas no vacías evalúan a True, y dado que el mensaje de aserción es opcional, básicamente ha llamado assert Truecuando escribió assert(1==2, "hi").

Mark Rushakoff
fuente
10
La razón es que no sucede porque los assert (1==2)paréntesis alrededor de una sola expresión no crearán una tupla automáticamente; obtendría el mismo comportamiento que el número 4 si lo hiciera assert (1==2,). Lo mismo sucedería si lo hiciera en print ('foo', 'bar')lugar de print 'foo', 'bar'; vería la tupla emitida
Michael Mrozek
Vale la pena enfatizar aún más que las declaraciones de la forma assert(test, message)probablemente sean incorrectas y ciertamente confusas. ¡Sin parens!
tcarobruce
19
Entonces, ¿cuál es la forma correcta de sangrar una declaración de aserción larga, wrt PEP8? Parece imposible.
stantonk
30

Si coloca el paréntesis allí porque desea una afirmación de varias líneas, entonces una alternativa es colocar una barra invertida al final de la línea como esta:

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

Huellas dactilares:

AssertionError: "derp should be 8, it is 7

¿Por qué esta pitón asserttiene que ser diferente de todo lo demás?

Creo que la ideología pitónica es que un programa debe autocorregirse sin tener que preocuparse por la bandera especial para activar afirma. La tentación de desactivar las afirmaciones es demasiado grande y, por lo tanto, está en desuso.

Comparto su molestia de que python asserttiene una sintaxis única en relación con todas las demás construcciones de programación de Python, y esta sintaxis ha cambiado una vez más de python2 a python3 y nuevamente ha cambiado de python 3.4 a 3.6. Hacer declaraciones de aserción que no sean compatibles con versiones anteriores de ninguna versión a ninguna otra versión.

Es un toque en el hombro que assertes un ciudadano de tercera clase, se eliminará por completo en python4, y ciertamente nuevamente en Python 8.1.

Eric Leschinski
fuente
2
¿Hay algún documento sobre lo que deberíamos usar en lugar de afirmar? Assert parece un nombre tan lógico para validar, y tiene el comportamiento deseado, por ejemplo, muestra un mensaje especial en caso de error.
AnneTheAgile
18

assert 1==2, "hi"se analiza assert 1==2, "hi"con "hi" como segundo parámetro para la palabra clave. De ahí por qué da correctamente un error.

assert(1==2)se analiza como assert (1==2)que es idéntico a assert 1==2, porque los paréntesis alrededor de un solo elemento no crean una tupla a menos que haya una coma al final, por ejemplo (1==2,).

assert(1==2, "hi")se analiza como assert (1==2, "hi"), lo que no da un error porque una tupla (False, "hi")no vacía no es un valor falso y no se proporciona un segundo parámetro a la palabra clave.

No debe usar paréntesis porque assertno es una función en Python, es una palabra clave.

Ámbar
fuente
13

Puede romper la declaración de aserción sin \esto:

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

O si tiene un mensaje aún más largo:

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
fuente
1
Idea interesante. Odio las barras diagonales inversas para la continuación, y esta es una alternativa a envolver aserción en una función de utilidad (que fue mi solución).
Tomasz Gandor
1

A continuación se cita del documento de Python

Las declaraciones de afirmación son una forma conveniente de insertar afirmaciones de depuración en un programa:

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

La forma simple, aseverar expresión, es equivalente a if __debug__: if not expression: raise AssertionError

La forma extendida, aseverar expresión1, expresión2 , es equivalente a if __debug__: if not expression1: raise AssertionError(expression2)

Entonces, cuando usa paréntesis aquí, está usando la forma simple y la expresión se evalúa como una tupla, que siempre es True cuando se convierte en bool.

VicX
fuente