assert
の代わりに、選択した例外をAssertionError
にスローさせることはできますか?
更新:
私の動機を説明します。これまで、私は独自の例外を発生させるアサーションスタイルのテストを行ってきました。たとえば、特定の引数を使用してNode
オブジェクトを作成すると、その引数がノードの作成に適しているかどうかが確認され、そうでない場合はNodeError
が発生します。
ただし、Pythonには-o
アサートがスキップされるモード。これは、プログラムを高速化するために使用可能にしたいと考えています。しかし、私は自分自身の例外を持ちたいと思っています。それが私が自分の例外でアサートを使いたい理由です。
これは動作します。しかし、それはちょっとおかしいです。
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 モジュールも参照してください。これはまさにあなたがやろうとしていることかもしれません。
これはどう?
>>> 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が最適化をオンにして実行されている場合、アサートはバイトコードにコンパイルされることすらありません。これを実行している場合は、例外が発生することを明らかに気にします。それからあなたはそもそも間違ったアサートを使っています。
また、Pythonは_if __debug__:
_オプションを指定して実行すると_-o
_ブロックをスキップします。次のコードはより冗長ですが、ハックすることなく必要なことを実行します。
_def my_assert(condition, message=None):
if not condition:
raise MyAssertError(message)
if __debug__: my_assert(condition, message)
_
_if __debug__:
_条件をmy_assert()
内に移動することで短くすることができますが、最適化が有効になっている場合は(内部でアクションなしで)呼び出されます。
コンテキストマネージャー で、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")
)には、この回答の以前のバージョンを参照してください。
試行にオーバーヘッドがあるかどうかを確認するために、この実験を試しました
ここに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
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
これにアサートを使用したい場合、これはかなりうまくいくようです:
>>> 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
は必要なときにのみ作成および生成されることに注意してください。