51

assertの代わりに選択した例外をスローすることはできますかAssertionError?

アップデート:

私の動機を説明します。これまで、私は独自の例外を発生させるアサーション スタイルのテストを行ってきました。たとえば、Node特定の引数でオブジェクトを作成すると、引数がノードの作成に適しているかどうかがチェックされ、そうでない場合は が発生しNodeErrorます。

しかし、Python にはアサートをスキップするモードがあることは知ってい-oます。プログラムを高速化するために、このモードを使用できるようにしたいと考えています。しかし、私はまだ独自の例外を持ちたいと思っています。そのため、私は独自の例外で assert を使用したいと考えています。

4

8 に答える 8

61

これは機能します。しかし、それはちょっとクレイジーです。

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

なぜ以下ではないのですか?これはそれほどクレイジーではありません。

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

これはステートメントよりも少し冗長ですが、assertassert の失敗が raise を発生させるという私たちの期待に反するものではありません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

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()、最適化が有効になっていると(内部でアクションなしで)呼び出されます。

于 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 に答える
3

tryにオーバーヘッドがあるかどうかを確認するために、この実験を試しました

これが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 に答える