0

Как поймать исключение в итераторе цикла for

68

Проблема с обработкой исключений в цикле for в Python

У меня есть цикл for на Python, который выглядит следующим образом:

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)

И вот содержимое файла test.csv:

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

Данный код завершает выполнение при обработке второй строки. Я хотел бы найти способ пропускать или записывать ошибки для проблемных строк и продолжать выполнение цикла. Спасибо за помощь!

3 ответ(ов)

0

Если ваш внутренний итератор может продолжить свою работу после исключения, вам достаточно обернуть его в простой генератор:

def wrapper(gen):
    while True:
        try:
            yield next(gen)
        except StopIteration:
            break
        except Exception as e:
            print(e)  # или любой другой вид логирования, который вы предпочитаете

Пример использования:

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 это может означать чтение n строк из файла перед оборачиванием его в csv.reader. В других случаях это может означать передачу n в конструктор. Однако в некоторых случаях, как с raisinggenfunc, это просто невозможно.

0

Вы можете обернуть читатель в другой итератор, который будет обрабатывать исключения по вашему усмотрению.

class ExceptionHandlingIterator(object):
    def __init__(self, iterable):
        self._iter = iter(iterable)
        self.handlers = []

    def __iter__(self):
        return self

    def __next__(self):
        try:
            return next(self._iter)
        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')))
# здесь можно прикрепить обработчики к читателю
for line in csv_reader:
    print(line)

В этом примере мы создали класс ExceptionHandlingIterator, который принимает любое итерируемое значение. Метод __next__ пытается вернуть следующий элемент, обрабатывая при этом исключения. Если возникает ошибка, вы можете зарегистрировать обработчики исключений для выполнения специфичных действий. Это дает вам гибкость в управлении исключениями, которые могут возникнуть при работе с данными (например, из CSV-файла).

0

Если вы используете csv.reader в цикле for, то можно обработать ошибки с помощью блока try-except, и цикл продолжит свою работу. Вот пример:

import csv

datarows = []
with open('yourfile.csv', 'r') as file:
    reader = csv.reader(file)
    try:
        for row in reader:
            if row[0] == 'type':
                datarows.append(row)
    except Exception as e:
        # Логируем ошибку, если нужно
        print(f"Произошла ошибка: {e}")

Если в приведенном коде возникнет внутренняя ошибка, выполнение перейдет в блок except, и продолжится итерация по следующей строке в CSV-файле.

Обновление: Учтите, что это может вызвать ошибку, как указано в комментариях. Хотя у меня был успешный опыт работы с данной конструкцией в более старых версиях Python 2.7, в более новых версиях рекомендуется использовать более точечную обработку исключений, чтобы избежать неожиданных ситуаций. Например, можно обрабатывать конкретные ошибки, такие как IndexError, которые могут возникнуть, если в строке недостаточно элементов.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь