assert python avec et sans parenthèses

104

Voici quatre invocations simples d'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")

Notez que le dernier ne soulève pas d'erreur. Quelle est la différence entre l'appel à assert avec ou sans parenthèse qui provoque ce comportement? Ma pratique consiste à utiliser des parenthèses, mais ce qui précède suggère que je ne devrais pas.

gaefan
la source
Merci pour les réponses utiles. La distinction entre les mots-clés et les fonctions intégrées semble subtile. Voici une liste de mots-clés, pour lesquels je suppose que les parens devraient être omis
gaefan
2
Une différence est que vous pouvez redéfinir les fonctions intégrées, mais vous ne pouvez pas le faire avec des mots-clés (pas que la première soit une bonne idée).
gaefan
Ce n'est pas une distinction fonction / mot-clé, mais appel de fonction vs instruction . (par exemple - print était une instruction et fonctionnait sans parenthèses).
Tomasz Gandor

Réponses:

129

Le dernier vous assertaurait donné un avertissement ( SyntaxWarning: assertion is always true, perhaps remove parentheses?) si vous l'aviez exécuté via un interpréteur complet, et non via IDLE. Comme il asserts'agit d'un mot-clé et non d'une fonction, vous passez en fait un tuple comme premier argument et laissez le second argument.

Rappelez-vous que les tuples non vides évaluent à True, et comme le message d'assertion est facultatif, vous l'avez essentiellement appelé assert Truelorsque vous avez écrit assert(1==2, "hi").

Mark Rushakoff
la source
10
La raison en est que les assert (1==2)parenthèses autour d'une seule expression ne créent pas automatiquement un tuple; vous auriez le même comportement que le n ° 4 si vous le faisiez assert (1==2,). La même chose se produirait si vous faisiez à la print ('foo', 'bar')place de print 'foo', 'bar'; vous verriez le tuple sorti
Michael Mrozek
Il vaut la peine de souligner davantage que les déclarations de la forme sont assert(test, message)probablement erronées et certainement déroutantes. Pas de parent!
tcarobruce
19
Alors, quelle est la bonne façon d'indenter une longue déclaration d'assertion, par rapport à PEP8? Cela semble impossible.
stantonk
30

Si vous mettez la parenthèse là-dedans parce que vous vouliez une assertion multiligne, alors une alternative est de mettre une barre oblique inverse à la fin de la ligne comme ceci:

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

Impressions:

AssertionError: "derp should be 8, it is 7

Pourquoi ce python assertdoit-il être différent de tout le reste:

Je pense que l'idéologie pythonique est qu'un programme doit s'auto-corriger sans avoir à se soucier du drapeau spécial pour activer les affirmations. La tentation de désactiver les assertions est trop grande et est donc obsolète.

Je partage votre mécontentement que le python asserta une syntaxe unique par rapport à toutes les autres constructions de programmation python, et cette syntaxe a encore une fois changé de python2 à python3 et à nouveau changé de python 3.4 à 3.6. Rendre les instructions assert non rétrocompatibles d'une version à une autre.

C'est une tape sur l'épaule qui assertest un citoyen de 3ème classe, il sera totalement supprimé en python4, et certainement à nouveau en Python 8.1.

Eric Leschinski
la source
2
Existe-t-il une documentation sur ce que nous devrions utiliser au lieu d'affirmer? Assert semble être un nom logique pour la validation, et il a le comportement souhaité, par exemple afficher un message spécial en cas d'erreur.
AnneTheAgile
18

assert 1==2, "hi"est analysé comme assert 1==2, "hi"avec "hi" comme deuxième paramètre du mot-clé. D'où pourquoi il donne correctement une erreur.

assert(1==2)est analysé comme assert (1==2)étant identique à assert 1==2, car les parenthèses autour d'un seul élément ne créent pas de tuple à moins qu'il n'y ait une virgule à la fin, par exemple (1==2,).

assert(1==2, "hi")est analysé comme assert (1==2, "hi"), ce qui ne donne pas d'erreur car un tuple non vide (False, "hi")n'est pas une valeur fausse et il n'y a pas de deuxième paramètre fourni au mot clé.

Vous ne devriez pas utiliser de parenthèses car ce assertn'est pas une fonction en Python - c'est un mot-clé.

ambre
la source
13

Vous pouvez casser l'instruction assert sans \comme ceci:

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

Ou si vous avez un message encore plus long:

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
la source
1
Idée intéressante. Je déteste les barres obliques inverses pour la suite, et c'est une alternative à l'enveloppement d'assert dans une fonction utilitaire (ce qui était ma solution).
Tomasz Gandor
1

Ce qui suit est cité dans la documentation python

Les instructions Assert sont un moyen pratique d'insérer des assertions de débogage dans un programme:

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

La forme simple, assert expression, équivaut à if __debug__: if not expression: raise AssertionError

La forme étendue, assert expression1, expression2 , équivaut à if __debug__: if not expression1: raise AssertionError(expression2)

Ainsi, lorsque vous utilisez des parenthèses ici, vous utilisez le formulaire simple et l'expression est évaluée comme un tuple, ce qui est toujours True lors du cast en bool.

VicX
la source