python afferma con e senza parentesi


104

Ecco quattro semplici invocazioni di 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")

Nota che l'ultimo non solleva un errore. Qual è la differenza tra la chiamata assert con o senza parentesi che causa questo comportamento? La mia pratica consiste nell'usare le parentesi, ma quanto sopra suggerisce che non dovrei.


Grazie per le utili risposte. La distinzione tra parole chiave e funzioni integrate sembra sottile. Ecco un elenco di parole chiave, per le quali presumo che i genitori dovrebbero essere omessi
gaefan

2
Una differenza è che puoi ridefinire le funzioni integrate ma non puoi farlo con le parole chiave (non che la prima sia una buona idea).
gaefan

Non è una distinzione tra funzione e parola chiave, ma chiamata di funzione e istruzione . (ad esempio: print era un'istruzione e funzionava senza parentesi).
Tomasz Gandor

Risposte:


129

L'ultimo ti assertavrebbe dato un warning ( SyntaxWarning: assertion is always true, perhaps remove parentheses?) se lo avessi eseguito tramite un interprete completo, non tramite IDLE. Poiché assertè una parola chiave e non una funzione, in realtà stai passando una tupla come primo argomento e tralascia il secondo argomento.

Ricorda che le tuple non vuote restituiscono il valore True, e poiché il messaggio di asserzione è opzionale, essenzialmente hai chiamato assert Truequando hai scritto assert(1==2, "hi").


10
Il motivo è che non accade perché le assert (1==2)parentesi attorno a una singola espressione non creano automaticamente una tupla; avresti lo stesso comportamento del n. 4 se lo facessi assert (1==2,). La stessa cosa accadrebbe se lo facessi print ('foo', 'bar')invece di print 'foo', 'bar'; vedresti la tupla emessa
Michael Mrozek

Vale la pena sottolineare ulteriormente che le affermazioni della forma assert(test, message)probabilmente sono sbagliate e certamente confuse. Niente genitori!
tcarobruce

19
Allora, qual è il modo corretto per indentare una dichiarazione di asserzione lunga, rispetto a PEP8? Sembra impossibile.
stantonk


30

Se inserisci la parentesi perché desideri un'affermazione su più righe, un'alternativa è inserire una barra rovesciata alla fine della riga in questo modo:

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

Stampe:

AssertionError: "derp should be 8, it is 7

Perché questo pitone assertdeve essere diverso da tutto il resto:

Penso che l'ideologia pitonica sia che un programma dovrebbe auto-correggersi senza doversi preoccupare della bandiera speciale per attivare asserzioni. La tentazione di disattivare le asserzioni è troppo grande e quindi viene deprecata.

Condivido il tuo fastidio per il fatto che python assertabbia una sintassi unica rispetto a tutti gli altri costrutti di programmazione python, e questa sintassi è cambiata ancora una volta da python2 a python3 e di nuovo è cambiata da python 3.4 a 3.6. Fare affermazioni non compatibili con le versioni precedenti da nessuna versione a qualsiasi altra versione.

È un colpetto sulla spalla che assertè un cittadino di terza classe, sarà completamente rimosso in python4 e sicuramente di nuovo in Python 8.1.


2
C'è un documento su ciò che dovremmo usare invece di affermare? Assert sembra un nome logico per la convalida e ha il comportamento desiderato, ad esempio mostra un messaggio speciale in caso di errore.
AnneTheAgile

18

assert 1==2, "hi"viene analizzato come assert 1==2, "hi"con "hi" come secondo parametro per la parola chiave. Ecco perché dà correttamente un errore.

assert(1==2)viene analizzato come assert (1==2)identico a assert 1==2, perché le parentesi attorno a un singolo elemento non creano una tupla a meno che non ci sia una virgola finale, ad es (1==2,).

assert(1==2, "hi")viene analizzato come assert (1==2, "hi"), il che non fornisce un errore perché una tupla non vuota (False, "hi")non è un valore falso e non viene fornito alcun secondo parametro alla parola chiave.

Non dovresti usare le parentesi perché assertnon è una funzione in Python, è una parola chiave.


13

Puoi rompere la dichiarazione di asserzione senza in \questo modo:

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

O se hai un messaggio ancora più lungo:

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'
)

1
Idea interessante. Odio i backslash per la continuazione, e questa è un'alternativa al wrapping assert in una funzione di utilità (che era la mia soluzione).
Tomasz Gandor

1

Di seguito è citato dal documento python

Le istruzioni Assert sono un modo conveniente per inserire asserzioni di debug in un programma:

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

La forma semplice, asserisci espressione, è equivalente a if __debug__: if not expression: raise AssertionError

La forma estesa, asserisci espressione1, espressione2 , è equivalente a if __debug__: if not expression1: raise AssertionError(expression2)

Quindi, quando stai usando le parentesi qui, stai usando la forma semplice e l'espressione viene valutata come una tupla, che è sempre True quando viene castato in bool

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.