web-dev-qa-db-ja.com

Pythonの設計:なぜ関数ではなくステートメントをアサートするのですか?

Pythonでは、assertはステートメントであり、関数ではありません。これは意図的な決定でしたか? assertを関数ではなくステートメント(および予約語)にすることには利点がありますか?

thedocs によると、_assert expression1, expression2_はに展開されます

_if __debug__:
    if not expression1: raise AssertionError(expression2)
_

ドキュメントには、「現在のコードジェネレーターは、コンパイル時に最適化が要求されたときに、assertステートメントのコードを出力しない」とも記載されています。詳細がわからないので、これを可能にするためには特別なケースが必要だったようです。ただし、特別な場合を使用して、assert()関数への呼び出しを最適化することもできます。

assertが関数の場合、次のように書くことができます。

_assert(some_long_condition,
       "explanation")
_

ただし、assertはステートメントであるため、タプルは常にTrueと評価され、次のようになります。

_SyntaxWarning: assertion is always true, perhaps remove parentheses?
_

それを書く正しい方法は

_assert some_long_condition, \
       "explanation"
_

これは間違いなくあまりきれいではありません。

57
cberzan

Assertを関数ではなくステートメント(および予約語)にすることには利点がありますか?

  1. @mgilsonが指摘したように、ユーザー関数に再割り当てすることはできません。つまり、コンパイル時に効果的に無効にすることができます。
  2. 2番目のオプションのパラメーターの評価は、アサーションが失敗するかどうか/失敗するまで延期されます。関数と関数の引数でこれを行うのは厄介です(ラムダを渡す必要があります)。2番目のパラメーターの評価を延期しないと、追加のオーバーヘッドが発生します。
33
vladr

pythonおよび他の言語(具体的にはC)のassertのすばらしい点の1つは、正しい_#define_(オプションで)を追加するだけで、それらを削除してコードを最適化できることです。コマンドラインで、これまでに使用したコンパイラ)または最適化フラグ(Pythonでは_-O_)。 assertが関数になった場合、組み込みのassert関数があるかユーザー定義かが実行時までわからないため、この機能をpythonに追加することはできません。同名の機能。


また、Pythonでは、関数呼び出しはかなり高価であることに注意してください。インラインをコード_if __debug__: ..._に置き換えることは、関数呼び出しを行うよりもおそらくはるかに効率的です。これは、パフォーマンスが重要なルーチンにassertステートメントを配置した場合に重要になる可能性があります。

17
mgilson

私はPythonの専門家ではありませんが、パフォーマンスが最大の理由の1つだと思います。

関数としてassert(expression、description)がある場合、式の評価にコストがかかる場合、非デバッグモードであっても、Pythonは、両方の式を評価して、assert関数に渡す必要があります。 。

アサーションを展開することにより、式と説明のステートメントは、本当に必要な場合を除いて、実際には評価されません(debugがtrueと評価された場合)。必要のないときにパフォーマンスに影響を与えない(つまり、本番システムでパフォーマンスが低下しない)アサートを行う場合は重要だと思います。

7
Adrian Shum

他の回答(および一種のオフトピック)に加えて、ヒント。バックスラッシュの使用を避けるために、括弧内に暗黙の線結合を使用できます。 ;-)

の代わりに:

assert some_long_condition, \
       "explanation"

あなたは書くことができます:

assert some_long_condition, (
       "explanation")
7
siebz0r