152

Python には、各反復で例外をスローできるリスト内包表記があります。

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

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

[1/egg for egg in eggs]

ZeroDivisionError3 番目の要素で例外が発生します。

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

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

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

しかし、これは私には少し面倒に見えます。

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

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

4

8 に答える 8

151

この質問はかなり古いと思いますが、この種のことを簡単にするための一般的な関数を作成することもできます。

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」引数キーワードのみを作成し、引数リストの最後に配置します。これにより、実際に引数などをキャッチに渡すことがはるかに自然になります。

更新(9年後...):Python 3の場合、私は単にswitch*argshandleを意味したので、ハンドルを指定せずに関数の引数を指定できます。ちょっとした便利さ:

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

これは、理解で定義された関数を使用するときに役立ちます。

from math import log    
eggs = [1,3,0,3,2]
[catch(log, egg) for egg in eggs]
[0.0, 1.0986122886681098, ValueError('math domain error'), 1.0986122886681098, 0.6931471805599453]

Python 2バージョンでは、のhandle前にパスする必要がありましたegg

于 2012-01-18T18:48:01.453 に答える
125

リスト内包表記は式であるため、Python には例外を無視する (または例外の場合は別の値 &c を返す) 組み込みの式がないため、文字どおり「リスト内包表記で例外を処理する」ことは不可能です。他の式を含み、それ以上のものはありません (つまり、ステートメントはなく、ステートメントのみが例外をキャッチ/無視/処理できます)。

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

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

于 2009-10-06T22:10:27.077 に答える
19

使用できます

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

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

于 2009-10-06T21:38:18.953 に答える
13

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

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

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

それがより面倒かどうかを決めるのはあなた次第です

于 2009-10-06T21:50:01.713 に答える
7

最初の質問をした人やブライアン・ヘッドも示唆しているように、ヘルパー機能は優れていて、まったく面倒ではないと思います。すべての作業を 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)]。この答えがあれば、好きな方法で続行することを完全に制御できます。

代替:

def spam2(egg):
    try:
        return 1/egg 
    except ZeroDivisionError:
        # handle division by zero error        
        return ZeroDivisionError

はい、エラーは返されますが、発生しません。

于 2016-11-08T10:23:26.670 に答える