73

私は最近 Python を独学していて、コード実行前のエラー チェックに関する LBYL/EAFP のイディオムを発見しました。Python では、受け入れられているスタイルは EAFP のようで、この言語でうまく機能するようです。

LBYL ( Look Before You Leap ) : _ _

def safe_divide_1(x, y):
    if y == 0:
        print "Divide-by-0 attempt detected"
        return None
    else:
        return x/y

EAFP (許可よりも許し求める簡単です):

def safe_divide_2(x, y):
    try:
        return x/y
    except ZeroDivisionError:  
        print "Divide-by-0 attempt detected"
        return None

私の質問は次のとおりです。私は、Java および C++ のバックグラウンドから来て、主要なデータ検証構造として EAFP を使用することさえ聞いたことがありませんでした。EAFP は Java で使用するのに賢明なものですか? または、例外によるオーバーヘッドが多すぎますか? 例外が実際にスローされたときのオーバーヘッドしかないことはわかっているので、EAFP のより単純な方法が使用されない理由がわかりません。好みだけですか?

4

5 に答える 5

139

ファイルにアクセスしている場合、EAFP は LBYL よりも信頼性が高くなります。これは、LBYL に含まれる操作がアトミックではなく、ファイル システムが見ている時間とジャンプする時間の間に変化する可能性があるためです。実際、標準的な名前は TOCTOU - チェック時間、使用時間です。不正確なチェックによるバグは TOCTOU バグです。

一意の名前を持つ必要がある一時ファイルを作成することを検討してください。選択したファイル名がまだ存在するかどうかを確認する最善の方法は、ファイルを作成してみることです。オプションを使用して、ファイルが既に存在する場合に操作が失敗することを確認してください (POSIX/Unix 用語では、O_EXCL フラグを にopen())。ファイルが既に存在するかどうかを (おそらく を使用してaccess()) テストしようとすると、「いいえ」と表示されてからファイルを作成しようとするまでの間に、誰かまたは他の何かがファイルを作成した可能性があります。

逆に、既存のファイルを読み取ろうとするとします。ファイルの存在確認(LBYL)で「ある」と表示されても、実際に開いてみると「ない」ということがわかります。

どちらの場合も、最終的な操作を確認する必要がありますが、LBYL は自動的には役に立ちませんでした。

(SUID または SGID プログラムをいじっている場合access()は、別の質問をします。LBYL に関連している可能性がありますが、コードは失敗の可能性を考慮に入れる必要があります。)

于 2009-01-01T17:52:24.157 に答える
55

Python と Java の例外の相対的なコストに加えて、両者の間には哲学や態度の違いがあることに注意してください。Java は、型 (およびその他すべて) について非常に厳密になろうとしており、クラス/メソッド シグネチャの明示的で詳細な宣言を必要とします。使用しているオブジェクトのタイプとその機能を正確に知っている必要があることを前提としています。対照的に、Python の「ダック タイピング」は、オブジェクトのマニフェスト タイプが何であるかを確実に知らない (気にするべきではない) ことを意味します。この種の寛容な環境では、物事はうまくいくと思い込み、うまくいかなかった場合の結果に対処する準備を整えることが唯一の健全な態度です。Java の自然な制限はそうではありません。そんなカジュアルな着こなしにも合います。(これは、アプローチや言語のいずれかを軽蔑することを意図したものではなく、むしろ、これらの態度は各言語のイディオムの一部であり、異なる言語間でイディオムをコピーすると、しばしばぎこちなくコミュニケーションが取れなくなる可能性があるということです...)

于 2009-01-02T23:31:52.107 に答える
12

例外は、Java よりも Python でより効率的に処理されます。これが、Python でその構造が見られる理由の少なくとも一部です。Java では、そのように例外を使用するのは (パフォーマンスの点で) 非効率的です。

于 2009-01-01T14:30:19.043 に答える
9

個人的には、これは慣習によって裏付けられていると思いますが、EAFP は決して良い方法ではありません。これは、次と同等のものと見なすことができます。

if (o != null)
    o.doSomething();
else
    // handle

とは対照的に:

try {
    o.doSomething()
}
catch (NullPointerException npe) { 
    // handle
}

さらに、次の点を考慮してください。

if (a != null)
    if (b != null)
        if (c != null)
            a.getB().getC().doSomething();
        else
            // handle c null
    else
        // handle b null
else
    // handle a null

これはあまり洗練されていないように見えるかもしれません (そして、これは大雑把な例です。ご容赦ください) が、それを取得するためにすべてを try-catch でラップするのとは対照的に、エラーを処理する際の粒度がはるかに高くなりますNullPointerException。どこで、なぜそれを手に入れたのかを考えてみてください。

私の見方では、まれな状況を除いて、EAFP は決して使用されるべきではありません。また、あなたが問題を提起したので:はい、例外がスローされなくても、try-catch ブロックにはオーバーヘッドが発生します。

于 2009-01-01T09:57:00.047 に答える