Python assert zi bez nawiasów

104

Oto cztery proste wywołania 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")

Zwróć uwagę, że ostatnia nie powoduje błędu. Jaka jest różnica między wywoływaniem funkcji assert z nawiasami lub bez, które powodują takie zachowanie? Moją praktyką jest używanie nawiasów, ale powyższe sugeruje, że nie powinienem.

gaefan
źródło
Dzięki za pomocne odpowiedzi. Rozróżnienie między słowami kluczowymi a funkcjami wbudowanymi wydaje się subtelne. Oto lista słów kluczowych, dla których zakładam, że pareny powinny zostać pominięte: docs.python.org/reference/lexical_analysis.html#keywords
gaefan
2
Jedną różnicą jest to, że możesz przedefiniować wbudowane funkcje, ale nie możesz tego zrobić za pomocą słów kluczowych (nie, że to pierwsze jest dobrym pomysłem).
gaefan
Nie jest to rozróżnienie funkcji i słów kluczowych, ale wywołanie funkcji vs instrukcja . (na przykład - wydruk był kiedyś oświadczeniem i działał bez nawiasów).
Tomasz Gandor

Odpowiedzi:

129

Ten ostatni assertdałby ci ostrzeżenie ( SyntaxWarning: assertion is always true, perhaps remove parentheses?), gdybyś przepuścił go przez pełny interpreter, a nie przez IDLE. Ponieważ assertjest to słowo kluczowe, a nie funkcja, w rzeczywistości przekazujesz krotkę jako pierwszy argument, a pozostawiasz drugi argument.

Przypomnij sobie, że niepuste krotki oceniają do True, a ponieważ komunikat potwierdzenia jest opcjonalny, w zasadzie zadzwoniłeś assert Truepodczas pisania assert(1==2, "hi").

Mark Rushakoff
źródło
10
Przyczyną nie assert (1==2)jest to, że nawiasy wokół pojedynczego wyrażenia nie utworzą automatycznie krotki; miałbyś takie samo zachowanie jak # 4, gdybyś to zrobił assert (1==2,). To samo by się stało, gdybyś zrobił print ('foo', 'bar')zamiast print 'foo', 'bar'; zobaczysz wypisaną krotkę
Michael Mrozek
Warto dodatkowo podkreślić, że wypowiedzi w formularzu assert(test, message)prawdopodobnie są błędne, a na pewno mylące. Żadnych parens!
tcarobruce
19
Jaki jest więc właściwy sposób wcięcia długiego stwierdzenia potwierdzającego, wrt PEP8? Wydaje się niemożliwe.
stantonk
30

Jeśli umieścisz tam nawias, ponieważ chcesz uzyskać potwierdzenie wielowierszowe, alternatywą jest umieszczenie ukośnika odwrotnego na końcu linii w następujący sposób:

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

Wydruki:

AssertionError: "derp should be 8, it is 7

Dlaczego ten Python assertmusi się różnić od wszystkiego innego:

Myślę, że ideologia Pythona polega na tym, że program powinien samokorygować się bez martwienia się o specjalną flagę włączającą potwierdzenia. Pokusa wyłączania potwierdzeń jest zbyt duża i dlatego jest przestarzała.

Podzielam twoją irytację, że python assertma unikalną składnię w stosunku do wszystkich innych konstrukcji programowania w Pythonie, a ta składnia ponownie zmieniła się z python2 na python3 i ponownie z pythona 3.4 na 3.6. Sprawianie, że instrukcje assert nie są wstecznie kompatybilne z żadnej wersji do żadnej innej wersji.

To dotknięcie w ramię, które assertjest obywatelem trzeciej klasy, zostanie całkowicie usunięte w Pythonie4, a na pewno ponownie w Pythonie 8.1.

Eric Leschinski
źródło
2
Czy istnieje dokument na temat tego, czego powinniśmy używać zamiast potwierdzać? Assert wydaje się taką logiczną nazwą do walidacji i ma pożądane zachowanie, np. Wyświetla specjalny komunikat w przypadku błędu.
AnneTheAgile
18

assert 1==2, "hi"jest analizowany tak, jak assert 1==2, "hi"„hi” jako drugi parametr słowa kluczowego. Stąd, dlaczego poprawnie daje błąd.

assert(1==2)jest analizowany jako assert (1==2)identyczny z assert 1==2, ponieważ powiązania wokół pojedynczego elementu nie tworzą krotki, chyba że na końcu znajduje się przecinek, np (1==2,).

assert(1==2, "hi")jest analizowany jako assert (1==2, "hi"), co nie daje błędu, ponieważ niepusta krotka (False, "hi")nie jest wartością fałszywą i nie ma drugiego parametru dostarczonego do słowa kluczowego.

Nie powinieneś używać nawiasów, ponieważ assertnie jest to funkcja w Pythonie - to słowo kluczowe.

Bursztyn
źródło
13

Możesz złamać oświadczenie assert bez \tego:

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

Lub jeśli masz jeszcze dłuższą wiadomość:

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
źródło
1
Ciekawy pomysł. Nienawidzę odwrotnych ukośników jako kontynuacji i jest to alternatywa dla opakowywania assertów w funkcję narzędziową (co było moim rozwiązaniem).
Tomasz Gandor
1

Poniższy cytat pochodzi z dokumentu Python

Instrukcje assert są wygodnym sposobem wstawiania asercji debugowania do programu:

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

Prosta forma, wyrażenie assert, jest równoważne if __debug__: if not expression: raise AssertionError

Forma rozszerzona, assert expression1, expression2 , jest równoważna if __debug__: if not expression1: raise AssertionError(expression2)

Więc kiedy używasz tutaj nawiasów, używasz prostej formy, a wyrażenie jest oceniane jako krotka, co jest zawsze Prawdą, gdy jest rzutowane na bool

VicX
źródło