web-dev-qa-db-ja.com

リスト内包表記の例外を処理する方法は?

私はPythonで各反復が例外をスローできるリスト内包表記を持っています。

たとえば、私が持っている場合:

eggs = (1,3,0,3,2)

[1/Egg for Egg in eggs]

3番目の要素でZeroDivisionError例外を取得します。

この例外を処理し、リスト内包表記の実行を継続するにはどうすればよいですか?

私が考えることができる唯一の方法は、ヘルパー関数を使用することです:

def spam(Egg):
    try:
        return 1/Egg
    except ZeroDivisionError:
        # handle division by zero error
        # leave empty for now
        pass

しかし、これは少し面倒です。

Pythonでこれを行うより良い方法はありますか?

注:これは簡単な例です(上記の「for instance」を参照)。実際の例ではコンテキストが必要なため、考えました。 。ゼロ除算エラーを回避するのではなく、リスト内包の例外を処理することに興味があります。

88
Nathan Fellman

Pythonには例外を無視できる(または例外の場合は代替値&cを返す)組み込み式がないため、文字通り、リスト内の例外を処理することはできませんリスト内包表記は他の式を含む式であるためです(つまり、noステートメントであり、ステートメントのみが例外をキャッチ/無視/処理できます)。

関数呼び出しは式であり、関数本体には必要なすべてのステートメントを含めることができるため、気づいたように、例外が発生しやすい部分式の評価を関数に委任することは、実行可能な1つの回避策です(実行可能な場合は、他の回答でも示唆されているように、例外を引き起こす可能性のある値をチェックします)。

「リスト内包の例外を処理する方法」という質問に対する正しい回答は、すべてこの真実のすべての一部を表現しています。 2)実際には、可能な場合はジョブを関数に委任するか、エラーが発生しやすい値を確認します。したがって、これが答えではないという繰り返しの主張には根拠がありません。

75
Alex Martelli

私はこの質問がかなり古いことを知っていますが、この種のことをより簡単にする一般的な関数を作成することもできます:

def catch(func, handle=lambda e : e, *args, **kwargs):
    try:
        return func(*args, **kwargs)
    except Exception as e:
        return handle(e)

次に、あなたの理解で:

eggs = (1,3,0,3,2)
[catch(lambda : 1/Egg) for Egg in eggs]
[1, 0, ('integer division or modulo by zero'), 0, 0]

もちろん、デフォルトのハンドル関数を好きなように作成できます(たとえば、デフォルトでは「なし」を返します)。

これがあなたやこの質問の今後の視聴者に役立つことを願っています!

注:python 3では、 'handle'引数キーワードのみを作成し、引数リストの最後に配置します。これにより、catchを介して実際に引数などを渡すことがより自然になります。 。

86
Bryan Head

使用できます

[1/Egg for Egg in eggs if Egg != 0]

これは、ゼロの要素を単にスキップします。

20
Peter

いいえ、より良い方法はありません。多くの場合、Peterのように回避を使用できます

他のオプションは、内包表記を使用しないことです

eggs = (1,3,0,3,2)

result=[]
for Egg in eggs:
    try:
        result.append(Egg/0)
    except ZeroDivisionError:
        # handle division by zero error
        # leave empty for now
        pass

それがもっと面倒かどうかを決めるのはあなた次第

7
John La Rooy

最初の質問をする人とブライアンヘッドも提案したように、ヘルパー関数は良いもので、まったく面倒ではないと思います。すべての作業を行う1行のマジックコードが常に可能であるとは限らないため、forループを避けたい場合、ヘルパー関数は完璧なソリューションです。ただし、これを次のように変更します。

_# A modified version of the helper function by the Question starter 
def spam(Egg):
    try:
        return 1/Egg, None
    except ZeroDivisionError as err:
        # handle division by zero error        
        return None, err
_

出力はこの[(1/1, None), (1/3, None), (None, ZeroDivisionError), (1/3, None), (1/2, None)]になります。この答えを使用すると、任意の方法で続行するために完全に制御できます。

3
Elmex80s