Подтвердить что ты не робот

Создание Python `assert` генерирует исключение, которое я выбираю

Могу ли я сделать assert исключение, которое я выбираю вместо AssertionError?

UPDATE:

Я объясню свою мотивацию: до сих пор у меня были тесты стиля утверждения, которые порождали мои собственные исключения; Например, когда вы создали объект Node с определенными аргументами, он проверил бы, были ли аргументы хорошими для создания node, и если бы он не повышал бы NodeError.

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

4b9b3361

Ответ 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")) вместо повторного использования аргументов (-ей) утверждений.