我能否使assert
抛出我选择的异常,而不是AssertionError
?
更新:
我来解释一下我的动机:到目前为止,我有一些类似于断言的测试,会引发我自己的异常;例如,当您使用某些参数创建一个Node
对象时,它会检查这些参数是否适合创建节点,如果不适合,则会引发NodeError
。
但我知道Python有一个-o
模式,可以跳过asserts,这让我的程序运行更快。但我仍然想要使用自己的异常。这就是我想要在assert中使用自己异常的原因。
我能否使assert
抛出我选择的异常,而不是AssertionError
?
更新:
我来解释一下我的动机:到目前为止,我有一些类似于断言的测试,会引发我自己的异常;例如,当您使用某些参数创建一个Node
对象时,它会检查这些参数是否适合创建节点,如果不适合,则会引发NodeError
。
但我知道Python有一个-o
模式,可以跳过asserts,这让我的程序运行更快。但我仍然想要使用自己的异常。这就是我想要在assert中使用自己异常的原因。
这个方法可以使用。但有点太疯狂了。
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 }} ) )
一旦你完成了这个步骤,你现在可以自由地处理启用或禁用或其他你想要做的事情。
此外,阅读有关警告模块的内容。这可能正是你想要做的事情。
-o
选项。如果尝试不会造成太多开销,你的疯狂解决方案可能还可以。 - Ram Rachumif __debug__ and not someAssertion:
。 - Ber这个怎么样?
>>> 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
不要将断言用于逻辑!只用于可选的测试检查。请记住,如果Python正在运行时开启了优化,那么断言甚至不会编译成字节码。如果您这样做,显然您关心异常是否被引发,如果您关心的话,那么首先您就错误地使用了断言。
当使用-o
选项运行Python时,Python也会跳过if __debug__:
块。以下代码更加冗长,但可以在不使用hack的情况下完成所需操作:
def my_assert(condition, message=None):
if not condition:
raise MyAssertError(message)
if __debug__: my_assert(condition, message)
你可以通过将 if __debug__:
条件语句放在 my_assert()
函数内部来缩短它,但这样当开启编译器优化时,该条件语句仍然会被调用(而且没有任何操作)。
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")
),而不是重复使用断言的参数。
>>> 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
raise_
是不必要的,assert x >= 0, raise ValueError('oops')
看起来一样,但没有函数调用开销。 - YoavBZ3.8.0
上给了我一个语法错误。据我所知,语法需要逗号后面的东西是一个表达式,比如 raise_(...)
,而不是像 raise ...
那样的语句,这就是为什么我进行了定义 :) - urygaclass 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
AssertionError
是Exception
的子类,因此它可能会在except Exception
中被意外地抑制。 - GingerPlusPlushere is myassert.py
def myassert(e):
raise e
def f1(): #这是实验的控制 cond=True
def f2(): cond=True try: assert cond, "消息" 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