51

我可以assert抛出一个我选择而不是的异常AssertionError吗?

更新:

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

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

4

8 回答 8

61

这将起作用。但这有点疯狂。

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

完成此操作后,您现在可以自由地对启用或禁用或您想要做的任何事情大惊小怪。

另外,请阅读警告模块。这可能正是您想要做的。

于 2009-10-14T21:19:18.063 回答
26

这个怎么样?


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

于 2009-10-14T21:55:25.513 回答
12

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

于 2009-10-14T23:36:48.610 回答
11

使用选项运行时, Python 也会跳过if __debug__:块。-o以下代码更冗长,但无需 hack 即可满足您的需求:

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

if __debug__: my_assert(condition, message)

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

于 2009-10-15T04:01:48.840 回答
5

您可以让上下文管理器在 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")),而不是重用断言的参数。

于 2009-10-14T23:30:21.867 回答
4

至少在 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
于 2009-10-14T21:28:12.533 回答
4

如果你想为此使用断言,这似乎工作得很好:

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

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

于 2018-10-08T14:28:41.127 回答
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

于 2009-10-14T23:53:15.330 回答