44

これはforPython のループです。

for_stmt ::=  "for" target_list "in" expression_list ":" suite

通常、 から値を生成するときにexpression_list例外が発生すると、ループは中止されます。while Trueこの例外をキャッチしてループを続行するためのエレガントな方法 (または同様のものを使用してループを書き直す以外) はありますか?

次に例を示します。

import csv

csv.field_size_limit(10)

reader = csv.reader(open('test.csv', 'r'))
for line in reader:
    print(line)

このファイルで:

foo,bar,baz
xxx,veryverylong,yyy
abc,def,ghi

これは 2 行目で中止されます。失敗した行をスキップまたはログに記録して続行する方法が必要です。

4

4 に答える 4

43

内部の iterable が例外の後も継続できる場合、ラップする必要があるのは自明なジェネレータだけです。

def wrapper(gen):
  while True:
    try:
      yield next(gen)
    except StopIteration:
      break
    except Exception as e:
      print(e) # or whatever kind of logging you want

例えば:

In [9]: list(wrapper(csv.reader(open('test.csv', 'r'))))
field larger than field limit (10)
Out[9]: [['foo', 'bar', 'baz'], ['abc', 'def', 'ghi']]

一方、例外の後で内部イテレータを継続できない場合は、それをラップする方法はありません。

def raisinggenfunc():
    yield 1
    raise ValueError("spurious error")
    yield 3

In [11]: list(wrapper(raisinggenfunc()))
spurious error
Out[11]: [1]

Python ジェネレーター関数を呼び出したり、ジェネレーター式を評価したりして作成されたジェネレーターは再開できません。

そのような場合、反復を再開する新しい反復子を作成する何らかの方法を見つける必要があります。のようなものについては、ファイルから行をcsv.reader読み取ることを意味し、 . それ以外の場合は、コンストラクターに渡すことを意味する場合があります。それ以外の場合は、上記と同様、不可能です。ncsv.readernraisinggenfunc

于 2012-11-30T22:41:14.667 に答える
6

リーダーを別のイテレータでラップして、例外を処理することもできます。

class ExceptionHandlingIterator(object):
    def __init__(self, iterable):
        self._iter = iter(iterable)
        self.handlers = []
    def __iter__(self):
        return self
    def next(self):
        try:
            return self._iter.next()
        except StopIteration as e:
            raise e
        except Exception as e:
            for handler in self.handlers:
                handler(e)
            return self.next()

csv_reader = ExceptionHandlingIterator(csv.reader(open('test.csv', 'r'))
# attach handlers to the reader here
for line in csv_reader:
    print line
于 2012-11-30T22:33:29.873 に答える
4

for ループで使用csv.readerしている場合、try 例外でそれをカバーでき、for ループが続行されることがわかります。サンプルは次のとおりです。

reader=csv.reader
try:
   for row in reader:
      if row[0]=='type':
         datarows.append(row)
except: continue

このコードで内部エラーが発生した場合、except ブロックにジャンプし、CSV ファイルの次の行の反復を続行します。

更新: コメントで指摘されているように、これによりエラーが発生しますが、以前のバージョンの 2.7 で正常に使用できました。

于 2016-03-20T05:46:34.523 に答える
2

残念ながら、これが純粋なPythonでは不可能であることはかなり確実です。

次のコードを確認してください。

def testIter(n):
    count = 0
    while count<n:
        try:
            for i in xrange(count,n):
                if i == 3:
                    raise Exception("Asdfas")
                count = count + 1
                yield i
        except:
            continue

これにより、次が出力されます。

x = testIter(10)
x.next()  # 0
x.next()  # 1
x.next()  # 2
x.next()  # Exception: Asdfas
x.next()  # Exception: StopIteration

while ループの新しい反復で継続することが期待されますが、そうではありません。

エラーが発生しても csv.reader() が続くと指摘する人もいます。テスト ケースを作成する気はありませんが、作成する場合は、ここにある C モジュールとして実装されているためだと思われます。私のCはあまりシャープではないので、あまり掘り下げませんでしたが、可能だとは思わないと言えば十分です.

編集:あなたの質問に直接答えませんでした。再開可能なイテレータの場合、abarnet の言うことを実行します (つまり、C イテレータです)。

編集2:実際には厳密には真実ではありません。

class myInformativeException(Exception):
    def __init__(self, count):
        self.count = count

def testIter(n):
    for i in xrange(n):
        if i==4:
            raise myInformativeException(i)
        yield i

def iterwrap(n):
    x = testIter(n)
    try:
        for i in x:
            yield i
    except myInformativeException as e:
        print "Error on ", e.count

これは以下を出力します:

0
1
2
3
Error on 4

したがって、X 要素の後にイテレータを作成できれば、明らかに可能です。より完全な例が必要な場合はお知らせください。

于 2012-11-30T23:04:11.850 に答える