Python-assert vs if&return


12

テキストファイルに対して何かを行うスクリプトを書いています(ただし、それは私の質問とは無関係です)。そのため、ファイルに何かを行う前に、ファイルが存在するかどうかを確認します。私はこれを行うことができますが、問題はありませんが、問題は美学の問題です。

これは、同じことを2つの異なる方法で実装する私のコードです。

def modify_file(filename):
    assert os.path.isfile(filename), 'file does NOT exist.'


Traceback (most recent call last):
  File "clean_files.py", line 15, in <module>
    print(clean_file('tes3t.txt'))
  File "clean_files.py", line 8, in clean_file
    assert os.path.isfile(filename), 'file does NOT exist.'
AssertionError: file does NOT exist.

または:

def modify_file(filename):
    if not os.path.isfile(filename):
        return 'file does NOT exist.'


file does NOT exist.

最初の方法は、ほとんど些細な出力を生成します。私が気にする唯一のことは、ファイルが存在しないということです。

2番目のメソッドは文字列を返します、それは簡単です。

私の質問は次のとおりです。ファイルが存在しないことをユーザーに知らせるにはどの方法が良いですか?assertメソッドを使用すると、どういうわけか、より多くのPythonのようです。

回答:


33

代わりに、3番目のオプション:use raiseと特定の例外を使用します。これは組み込み例外の 1つであるか、ジョブのカスタム例外を作成できます。

この場合、私はを使用しますIOErrorが、a ValueErrorも適合する可能性があります。

def modify_file(filename):
    if not os.path.isfile(filename):
        raise IOError('file does NOT exist.')

特定の例外を使用すると、さまざまな例外的な状況に対して他の例外を発生させることができ、呼び出し元は例外を適切に処理できます。

もちろん、多くのファイル操作(のようなopen()自体が上げOSErrorすでに、ファイルが存在するかどうかを明示的に最初にテストすることは、ここでは冗長です。

使用しないでくださいassert-Oフラグを指定してpythonを実行すると、すべてのアサーションがコードから削除されます。


冗長性に関する興味深い点!それを避けることをお勧めしますか?すなわち、「それは上後でとにかく失敗します」
シプリアンTomoiagă

1
@CiprianTomoiagă:なぜテストが2倍になるのですか?次の行をした場合modify_file()with open(filename) as f:、その後IOErrorも提起されるだろう。また、最近のPythonバージョンでは、このAPIを使用する開発者に役立つ可能性のあるIOErrorFileNotFoundError具体的に思い浮かぶ)サブクラスの詳細が提供されています。コードが独自のチェックとレイズを行うとIOError、その有用な詳細は失われます。
マーティンピーターズ

@MartijnPietersは、「なぜテストを2倍にするのか」に対する受け入れられる答えでしょう。open()が失敗したときに発生した例外よりも最初のチェックが速い場合 たとえば、ファイルの存在を確認する方が、開こうとするよりも速く、最終的に開くことができない場合。
マルセルウィルソン

1
@MarcelWilson:いいえ、I / Oを行うメソッドに対して微最適化するためです。Pythonのセマンティクスを微調整しても、I / Oが高速化されることはなく、読みやすさと保守性が損なわれるだけです。よりインパクトのある分野に焦点を当てると思います。
マーティンピーターズ

12

assertは、ユーザーではなく、関数を呼び出すプログラマーがミスを犯した場合を対象としています。使用してassertそのような状況の下では、あなたは必ず、プログラマがテスト中に正しく機能を使用されていることを確認することができますが、その後の生産でそれを取り除きます。

そのパスをコード内で確実に実行する必要があるため、その値はいくぶん制限されています。またif、本番環境では別のステートメントを使用して問題を追加で処理したいことがよくあります。 assert「ユーザーがヒットした場合にこの問題を回避したいが、開発者がヒットした場合はクラッシュし、この関数を誤って呼び出すコードを修正したい」などの状況で最も役立ちます。

特定のケースでは、欠落ファイルはほぼ間違いなくユーザーエラーであり、例外を発生させて処理する必要があります。


5

UsingAssertionsEffectivelyから

isinstance()のチェックは過度に使用しないでください。アヒルのように鳴る場合、おそらく本当にそうであるかを深く調べる必要はありません。元のプログラマが予期していなかった値を渡すと便利な場合があります。

アサーションの配置を検討する場所:

checking parameter types, classes, or values
checking data structure invariants
checking "can't happen" situations (duplicates in a list, contradictory state variables.)
after calling a function, to make sure that its return is reasonable 

全体的なポイントは、何かがうまくいかない場合、できるだけ早くそれを完全に明らかにしたいということです。

後で問題が発生したときにどのようにしてそこにたどり着いたかを解明するよりも、入ってくる時点で誤ったデータをキャッチする方が簡単です。

アサーションは、単体テストまたはシステムテストの代わりではなく、補完的なものです。アサーションは、オブジェクトまたは関数の内部状態を検査するためのクリーンな方法であるため、外部の動作を検査するブラックボックステストに対する「無料の」クリアボックス支援を提供します。

アサーションは、不適切なユーザー入力またはオペレーティングシステム/環境の障害(ファイルが見つからないなど)が原因で発生する可能性がある障害ケースのテストには使用しないでください。代わりに、例外を発生させるか、エラーメッセージを出力するか、適切なものを使用してください。アサーションをプログラムのセルフテストにのみ使用する必要がある重要な理由の1つは、コンパイル時にアサーションを無効にできることです。

Pythonが-Oオプションで起動された場合、アサーションは取り除かれ、評価されません。したがって、コードがアサーションを頻繁に使用するが、パフォーマンスが重要な場合、リリースビルドでアサーションをオフにするシステムがあります。(しかし、本当に必要な場合を除き、これをしないでください。顧客がマシンを使用する場合にのみバグが発生することが科学的に証明されており、アサーションもそこに役立つことを望んでいます。

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