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

发布于 2024-08-08 09:20:53 字数 352 浏览 6 评论 0原文

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

更新:

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

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

Can I make assert throw an exception that I choose instead of AssertionError?

UPDATE:

I'll explain my motivation: Up to now, I've had assertion-style tests that raised my own exceptions; For example, when you created a Node object with certain arguments, it would check if the arguments were good for creating a node, and if not it would raise NodeError.

But I know that Python has a -o mode in which asserts are skipped, which I would like to have available because it would make my program faster. But I would still like to have my own exceptions. That's why I want to use assert with my own exceptions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

慈悲佛祖 2024-08-15 09:20:53

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

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

完成此操作后,您现在可以自由地启用或禁用或任何您想要执行的操作。

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

This will work. But it's kind of crazy.

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

Why not the following? This is less crazy.

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

It's only a little wordier than the assert statement, but doesn't violate our expectation that assert failures raise AssertionError.

Consider this.

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

Then you can more-or-less replace your existing assertions with something like this.

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

Once you've done this, you are now free to fuss around with enable or disabling or whatever it is you're trying to do.

Also, read up on the warnings module. This may be exactly what you're trying to do.

回忆躺在深渊里 2024-08-15 09:20:53

这个怎么样?


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

How about this?


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

不知所踪 2024-08-15 09:20:53

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

Never use an assertion for logic! Only for optional testing checks. Remember, if Python is running with optimizations turned on, asserts aren't even compiled into the bytecode. If you're doing this, you obviously care about the exception being raised and if you care, then you're using asserts wrong in the first place.

青朷 2024-08-15 09:20:53

当使用 -o 选项运行时,Python 也会跳过 if __debug__: 块。下面的代码比较冗长,但无需黑客

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

if __debug__: my_assert(condition, message)

即可完成您需要的操作:您可以通过在 my_assert() 内移动 if __debug__: 条件来缩短代码,但随后它会启用优化时调用(内部没有任何操作)。

Python also skips if __debug__: blocks when run with -o option. The following code is more verbose, but does what you need without hacks:

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

if __debug__: my_assert(condition, message)

You can make it shorter by moving if __debug__: condition inside my_assert(), but then it will be called (without any action inside) when optimization is enabled.

江心雾 2024-08-15 09:20:53

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

You can let a context manager do the conversion for you, inside a with block (which may contain more than one assertion, or more code and function calls or what you want.

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"

See a previous version of this answer for substituting constructed exception objects directly (KeyError("bad key")), instead of reusing the assertions' argument(s).

剩一世无双 2024-08-15 09:20:53

至少在 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

In Python 2.6.3 at least, this will also work:

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
溺深海 2024-08-15 09:20:53

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

>>> 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 只会是在需要时创建并提出。

If you want to use asserts for this, this seems to work pretty well:

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

Note that in the assert, the stuff after the comma will only be evaluated if the condition is false, so the ValueError will only be created and raised when needed.

恏ㄋ傷疤忘ㄋ疼 2024-08-15 09:20:53

为了看看尝试是否有任何开销,我

在这里尝试了这个实验是 myassert.py


def myassert(e):
    raise e

def f1(): #这是实验的对照 cond=True

def f2(): 条件=真 尝试: 断言条件,“消息” 除了断言错误,e: 引发异常(e.args)

def f3(): 条件=真 断言 cond 或 myassert(RuntimeError)

def f4(): 条件=真 如果__调试__: 引发(运行时错误)


$ 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

To see if try has any overhead I tried this experiment

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文