python assert с круглыми скобками и без них

105

Вот четыре простых вызова 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")

Обратите внимание, что последний не вызывает ошибки. В чем разница между вызовом assert с круглыми скобками или без них, который вызывает такое поведение? Моя практика заключается в использовании скобок, но из сказанного выше следует, что я не должен.

гефан
источник
Спасибо за полезные ответы. Разница между ключевыми словами и встроенными функциями кажется тонкой. Вот список ключевых слов, для которых, как я полагаю, следует опустить
скобки
2
Одно отличие состоит в том, что вы можете переопределить встроенные функции, но не можете сделать это с помощью ключевых слов (не то чтобы первое было хорошей идеей).
gaefan
Это не различие между функцией и ключевым словом, а вызов функции и оператор . (например, print раньше был оператором и работал без скобок).
Tomasz Gandor

Ответы:

130

Последний assertвыдал бы вам предупреждение ( SyntaxWarning: assertion is always true, perhaps remove parentheses?), если бы вы запустили его через полный интерпретатор, а не через IDLE. Поскольку assertэто ключевое слово, а не функция, вы фактически передаете кортеж в качестве первого аргумента и опускаете второй аргумент.

Напомним, что непустые кортежи оцениваются до True, и поскольку сообщение утверждения является необязательным, вы, по сути, вызывали, assert Trueкогда писали assert(1==2, "hi").

Марк Рушаков
источник
10
Причина этого не в assert (1==2)том, что скобки вокруг одного выражения не создают кортеж автоматически; если бы вы это сделали, вы бы получили то же поведение, что и №4 assert (1==2,). То же самое произошло бы, если бы вы сделали print ('foo', 'bar')вместо print 'foo', 'bar'; вы бы увидели вывод кортежа
Майкл Мрозек
Стоит дополнительно подчеркнуть, что утверждения формы, assert(test, message)вероятно, неверны и, безусловно, сбивают с толку. Без парней!
tcarobruce
19
Итак, как правильно сделать отступ в длинном утверждении относительно PEP8? Кажется невозможным.
stantonk
30

Если вы вставили круглые скобки, потому что хотели многострочное утверждение, то альтернативой является установка обратной косой черты в конце строки, например:

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

Печать:

AssertionError: "derp should be 8, it is 7

Почему этот питон assertдолжен отличаться от всего остального:

Я думаю, что идеология питонов состоит в том, что программа должна самокорректироваться, не беспокоясь о специальном флаге для включения утверждений. Искушение отключить утверждения слишком велико, и поэтому оно устарело.

Я разделяю ваше раздражение тем, что Python assertимеет уникальный синтаксис по сравнению со всеми другими конструкциями программирования Python, и этот синтаксис снова изменился с python2 на python3 и снова изменился с python 3.4 на 3.6. Обеспечение обратной совместимости операторов assert от любой версии к любой другой версии.

Это постукивание по плечу assertгражданина 3-го класса, оно будет полностью удалено в python4 и, конечно же, снова в Python 8.1.

Эрик Лещинский
источник
2
Есть ли документ о том, что мы должны использовать вместо assert? Assert кажется таким логическим именем для проверки, и у него есть желаемое поведение, например, показывать специальное сообщение при ошибке.
AnneTheAgile
18

assert 1==2, "hi"анализируется как assert 1==2, "hi""привет" в качестве второго параметра ключевого слова. Следовательно, почему он правильно выдает ошибку.

assert(1==2)анализируется как assert (1==2)который идентичен assert 1==2, поскольку скобки вокруг одного элемента не создают кортеж, если нет конечной запятой, например (1==2,).

assert(1==2, "hi")анализируется как assert (1==2, "hi"), что не вызывает ошибки, потому что непустой кортеж (False, "hi")не является ложным значением, и для ключевого слова не указан второй параметр.

Вы не должны использовать круглые скобки, потому что assertэто не функция в Python, это ключевое слово.

Янтарь
источник
14

Вы можете прервать оператор assert и без \этого:

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

Или, если у вас еще более длинное сообщение:

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
Интересная идея. Я ненавижу обратную косую черту для продолжения, и это альтернатива заключению assert в служебную функцию (что было моим решением).
Tomasz Gandor
1

Ниже приводится цитата из документа Python.

Операторы Assert - удобный способ вставки отладочных утверждений в программу:

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

Простая форма выражения assert эквивалентна if __debug__: if not expression: raise AssertionError

Расширенная форма assert expression1, expression2 эквивалентна if __debug__: if not expression1: raise AssertionError(expression2)

Итак, когда вы используете здесь круглые скобки, вы используете простую форму, а выражение оценивается как кортеж, который всегда имеет значение True при преобразовании в bool

VicX
источник