我可以让assert
抛出我选择的例外而不是AssertionError
吗?
更新
我将解释我的动机:到目前为止,我已经进行了断言式测试,这些测试提出了我自己的例外情况;例如,当您使用某些参数创建Node
对象时,它将检查参数是否适合创建节点,如果不是,则会引发NodeError
。
但是我知道Python有-o
模式,其中跳过了断言,我希望它可用,因为它会使我的程序更快。但我仍然希望有自己的例外。这就是为什么我想在我自己的例外中使用assert。
答案 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
仅在需要时创建和引发。