使Python的`assert`抛出我选择的异常

时间:2009-10-14 21:15:43

标签: python exception assert

我可以让assert抛出我选择的例外而不是AssertionError吗?

更新

我将解释我的动机:到目前为止,我已经进行了断言式测试,这些测试提出了我自己的例外情况;例如,当您使用某些参数创建Node对象时,它将检查参数是否适合创建节点,如果不是,则会引发NodeError

但是我知道Python有-o模式,其中跳过了断言,我希望它可用,因为它会使我的程序更快。但我仍然希望有自己的例外。这就是为什么我想在我自己的例外中使用assert。

8 个答案:

答案 0 :(得分:51)

这会奏效。但这有点疯狂。

try:
    assert False, "A Message"
except AssertionError, e:
    raise Exception( e.args )

为什么不以下?这不那么疯狂了。

if not someAssertion: raise Exception( "Some Message" )

它只比assert语句有点晦涩,但并没有违反我们对断言失败提出AssertionError的期望。

考虑一下。

def myAssert( condition, action ):
    if not condition: raise action

然后你可以用这样的东西或多或少地替换现有的断言。

myAssert( {{ the original condition }}, MyException( {{ the original message }} ) )

完成此操作后,您现在可以自由地使用启用或禁用或者您正在尝试做的任何事情。

另外,请阅读warnings模块。这可能正是你想要做的。

答案 1 :(得分:23)

这个怎么样?


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

答案 2 :(得分:7)

当使用if __debug__:选项运行时,Python也会跳过-o个块。以下代码更详细,但您可以在没有黑客的情况下完成所需的操作:

def my_assert(condition, message=None):
    if not condition:
        raise MyAssertError(message)

if __debug__: my_assert(condition, message)

您可以通过在if __debug__:内移动my_assert()条件来缩短它,但是在启用优化时它将被调用(内部没有任何操作)。

答案 3 :(得分:6)

永远不要使用逻辑断言!仅用于可选的测试检查。请记住,如果Python在启用优化的情况下运行,则断言甚至不会编译为字节码。如果你这样做,你显然关心被引发的异常,如果你关心,那么你首先使用的是错误。

答案 4 :(得分:4)

你可以让context manager为你做转换,在一个with块内(可能包含多个断言,或者更多的代码和函数调用或者你想要的。

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")),而不是重用断言的参数。

答案 5 :(得分:3)

至少在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 :(得分:3)

要查看尝试是否有任何开销我尝试了此实验

这是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 :(得分:1)

如果要对此使用断言,这似乎效果很好:

>>> def raise_(e): raise e
...
>>> x = -2
>>> assert x >= 0, raise_(ValueError('oops'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in raise_
ValueError: oops

请注意,在断言中,仅在条件为false时才评估逗号后面的内容,因此ValueError仅在需要时创建和引发。