Pythonでアサーションを無効にする


89

Pythonでアサーションを無効にするにはどうすればよいですか?

つまり、アサーションが失敗した場合、アサーションがスローするのAssertionErrorではなく、続行する必要があります。

それ、どうやったら出来るの?

回答:


74

Pythonでアサーションを無効にするにはどうすればよいですか?

単一のプロセス、環境、または1行のコードに影響を与える複数のアプローチがあります。

それぞれを実演します。

プロセス全体について

-Oフラグ(大文字のO)を使用すると、プロセス内のすべてのアサートステートメントが無効になります。

例えば:

$ python -Oc "assert False"

$ python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError

無効とは、それに続く式も実行しないことを意味することに注意してください。

$ python -Oc "assert 1/0"

$ python -c "assert 1/0"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

環境のために

環境変数を使用して、このフラグを設定することもできます。

これは、環境を使用または継承するすべてのプロセスに影響します。

たとえば、Windowsでは、環境変数を設定してからクリアします。

C:\>python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError
C:\>SET PYTHONOPTIMIZE=TRUE

C:\>python -c "assert False"

C:\>SET PYTHONOPTIMIZE=

C:\>python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError

Unixでも同じ(それぞれの機能にsetとunsetを使用)

コード内のシングルポイント

あなたはあなたの質問を続けます:

アサーションが失敗した場合、AssertionErrorをスローしたくはありませんが、続行します。

実行に失敗したコードが必要な場合は、制御フローがアサーションに到達しないようにすることができます。次に例を示します。

if False:
    assert False, "we know this fails, but we don't get here"

または、アサーションエラーをキャッチできます。

try:
    assert False, "this code runs, fails, and the exception is caught"
except AssertionError as e:
    print(repr(e))

印刷するもの:

AssertionError('this code runs, fails, and the exception is caught')

を処理した時点から続行しますAssertionError

参考文献

以下からのドキュメントassert

次のようなassertステートメント:

assert expression #, optional_message

と同等です

if __debug__:
    if not expression: raise AssertionError #(optional_message)

そして、

組み込み変数__debug__は、最適化が要求されたときのTrue通常の状況下にありますFalse(コマンドラインオプション-O)。

そしてさらに

への割り当て__debug__は違法です。組み込み変数の値は、インタープリターの起動時に決定されます。

使用法のドキュメントから:

-O

基本的な最適化をオンにします。これにより、コンパイルされた(バイトコード)ファイルのファイル名拡張子が.pycから.pyoに変更されます。PYTHONOPTIMIZEも参照してください。

そして

PYTHONOPTIMIZE

これが空でない文字列に設定されている場合は、-Oオプションを指定することと同じです。整数に設定すると、-O複数回指定するのと同じです。


「コード内のシングルポイント」の場合に失敗するコードをスキップすることは可能でしょうか?__debug__Falseに設定してみましたが、許可されていません。
Matthijs

1
@Matthijsは、制御フローがそれに到達しないことを確認するか(たとえばif False: assert False)、アサーションエラーをキャッチすることができます。それらはあなたの選択です。あなたの質問に対処するために答えを更新しました。
アーロンホール

答えてくれてありがとう、でもまだ完全には私が考えていたものではありません。実行時に関数内のアサーションを無効にしたいのですが、理想的には、ある種のコンテキストマネージャーを使用します。アサーションが評価さfoo()れますwith skip_assertion(): foo()。アサーションをオフに切り替えます。私は機能上の別のフラグを追加するために持っていけないことは、この存在の恩恵
Matthijs

2
関数のバイトコードを書き換えたり、ASTを書き換えたり、関数自体を書き換えたりすることができます。(手動またはプログラムで、どちらの場合も)。ASTを書き換えることは、おそらく最も信頼できるアプローチです(「単に」AssertオブジェクトをPassオブジェクトに置き換える)。コンテキストマネージャーはそのために直接機能しませんが、そのように装飾された関数を使用するある種のメカニズムを持つことができます。とにかく、私はそれをお勧めしません。あなたがそうしたい理由は、あなたが制御していないコードを呼び出して、AssertionErrorsを取得しているからだと思います。もしそうなら、あなたはおそらく別の修正を見つける必要があります。
アーロンホール

59

-Oフラグを指定してPythonを呼び出します。

test.py:

assert(False)
print 'Done'

出力:

C:\temp\py>C:\Python26\python.exe test.py
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    assert(False)
AssertionError

C:\temp\py>C:\Python26\python.exe -O test.py
Done

8
アサートは機能ではないため、親は不要です。
アーロンホール

15

すでに与えられている2つの答えは両方とも有効です(いずれか-Oまたは-OOコマンドラインでPythonを呼び出します)。

それらの違いは次のとおりです。

  • -O基本的な最適化をオンにします。これにより、コンパイルされた(バイトコード)ファイルのファイル名拡張子が.pycから.pyoに変更されます。

  • -OO docstringを破棄する -O最適化に加えて、ます。

Pythonドキュメントから)



3

(ほとんどの)アサーションを無効にしないでください。注意が他の場所にある場合、それらは予期しないエラーをキャッチします。「10の累乗」のルール5を参照してください。

代わりに、次のような方法でいくつかの高価なアサーションチェックを保護します。

import logging
logger = logging.getLogger(__name__)

if logger.getEffectiveLevel() < logging.DEBUG:
    ok = check_expensive_property()
    assert ok, 'Run !'

重要なアサーションを保持し、assertステートメントを最適化できるようにする1つの方法は、選択ステートメント内でそれらを上げることです。

if foo_is_broken():
    raise AssertionError('Foo is broken!')

1
//、しかし、問題は、ステートメントが依然として循環的複雑度を追加し、エラー処理が残りを処理する必要があるということです。
Nathan Basanese 2017年

1
上記のように保護されるアサーションは、実行を大幅に遅くする高価な呼び出しです。一部のアルゴリズムでは、この種のチェックはプログラム全体よりも桁違いに長くかかる可能性があります。正しさをチェックするために、同じアルゴリズムの素朴で単純な実装(エラーが含まれる可能性が低い)を実行することを考えてください。または、通常の操作では問題にならないものを徹底的に列挙してチェックします。
ioannis Filippidis 2017年

このようなステートメントはコードにネストを追加しないため、読みやすさに関する問題はあまり見られません。それが問題である場合、それを関数呼び出しとして抽出することで邪魔にならないようにすることができます(そして、そのようなリファクタリングは循環的複雑度を減らすはずです)。いずれにせよ、循環的複雑度が安全性チェックを支配するべきではありません。
ioannis Filippidis 2017年

2

最適化モードで実行すると、次のことが実行されます。

python -OO module.py
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.