Создание Python `assert` генерирует исключение, которое я выбираю
Могу ли я сделать assert
исключение, которое я выбираю вместо AssertionError
?
UPDATE:
Я объясню свою мотивацию: до сих пор у меня были тесты стиля утверждения, которые порождали мои собственные исключения; Например, когда вы создали объект Node
с определенными аргументами, он проверил бы, были ли аргументы хорошими для создания node, и если бы он не повышал бы NodeError
.
Но я знаю, что у Python есть режим -o
, в котором пропущены утверждения, которые я хотел бы иметь, потому что это ускорит мою программу. Но мне все же хотелось бы иметь свои исключения. Вот почему я хочу использовать assert с моими исключениями.
Ответы
Ответ 1
Это сработает. Но это как-то сумасшедшее.
try:
assert False, "A Message"
except AssertionError, e:
raise Exception( e.args )
Почему бы не следующее? Это менее сумасшествие.
if not someAssertion: raise Exception( "Some Message" )
Это всего лишь немного словнее, чем оператор assert
, но не нарушает наше ожидание, что ошибки assert повышают AssertionError
.
Рассмотрим это.
def myAssert( condition, action ):
if not condition: raise action
Затем вы можете более или менее заменить существующие утверждения на что-то вроде этого.
myAssert( {{ the original condition }}, MyException( {{ the original message }} ) )
Как только вы это сделаете, вы теперь можете суетиться с включением или отключением или тем, что вы пытаетесь сделать.
Также прочитайте модуль warnings. Это может быть именно то, что вы пытаетесь сделать.
Ответ 2
Как насчет этого?
>>> def myraise(e): raise e
...
>>> cond=False
>>> assert cond or myraise(RuntimeError)
Traceback (most recent call last):
File "", line 1, in
File "", line 1, in myraise
RuntimeError
Ответ 3
Python также пропускает блоки if __debug__:
при запуске с опцией -o
. Следующий код более подробный, но делает то, что вам нужно без хаков:
def my_assert(condition, message=None):
if not condition:
raise MyAssertError(message)
if __debug__: my_assert(condition, message)
Вы можете сделать это короче, переместив условие if __debug__:
внутри my_assert()
, но затем он будет вызываться (без каких-либо действий внутри), когда оптимизация включена.
Ответ 4
Никогда не используйте утверждение для логики! Только для дополнительных проверок тестирования. Помните, что если Python работает с включенными оптимизациями, утверждения даже не компилируются в байт-код. Если вы это делаете, вы, очевидно, заботитесь о том, чтобы возникало исключение, и если вам это нравится, вы сначала используете неправильные утверждения.
Ответ 5
В Python 2.6.3 по крайней мере это также будет работать:
class MyAssertionError (Exception):
pass
AssertionError = MyAssertionError
assert False, "False"
Traceback (most recent call last):
File "assert.py", line 8, in <module>
assert False, "False"
__main__.MyAssertionError: False
Ответ 6
Чтобы проверить, есть ли у приложения какие-либо накладные расходы, я попробовал этот эксперимент
здесь myassert.py
def myassert(e):
raise e
def f1(): #this is the control for the experiment
cond=True
def f2():
cond=True
try:
assert cond, "Message"
except AssertionError, e:
raise Exception(e.args)
def f3():
cond=True
assert cond or myassert(RuntimeError)
def f4():
cond=True
if __debug__:
raise(RuntimeError)
$ python -O -mtimeit -n100 -r1000 -s'import myassert' 'myassert.f1()'
100 loops, best of 1000: 0.42 usec per loop
$ python -O -mtimeit -n100 -r1000 -s'import myassert' 'myassert.f2()'
100 loops, best of 1000: 0.479 usec per loop
$ python -O -mtimeit -n100 -r1000 -s'import myassert' 'myassert.f3()'
100 loops, best of 1000: 0.42 usec per loop
$ python -O -mtimeit -n100 -r1000 -s'import myassert' 'myassert.f4()'
100 loops, best of 1000: 0.42 usec per loop
Ответ 7
Вы можете позволить <контекстному менеджеру выполнить преобразование для вас, внутри блока с блоком (который может содержать более одного утверждения или более кодовые и функциональные вызовы или то, что вы хотите.
from __future__ import with_statement
import contextlib
@contextlib.contextmanager
def myassert(exctype):
try:
yield
except AssertionError, exc:
raise exctype(*exc.args)
with myassert(ValueError):
assert 0, "Zero is bad for you"
См. предыдущую версию этого ответа для непосредственного подбора сконструированных объектов исключений (KeyError("bad key")
) вместо повторного использования аргументов (-ей) утверждений.