python попробуйте, кроме комбинации yield

#python #try-catch #yield #except

#python #попробуйте-catch #выход #кроме

Вопрос:

Я использую функцию f для создания генератора, но иногда это может вызвать ошибку. Я бы хотел, чтобы для основного кода произошли две вещи

  1. for Цикл в главном блоке продолжается после обнаружения ошибки
  2. В except , распечатайте индекс, который генерирует ошибку (в действительности ошибка может не возникать для индекса 3)

Код, который я придумал, останавливается после появления ошибки. Как мне реализовать вышеупомянутые две функции? Большое спасибо.

 def f(n):
    for i in xrange(n):
        if i == 3:
            raise ValueError('hit 3')
        yield i

if __name__ == '__main__':
    a = enumerate(f(10))
    try:
        for i, x in a:
            print i, x
    except ValueError:
        print 'you have a problem with index x'
  

Комментарии:

1. Если исключение возникает внутри генератора, я не вижу способа возобновить выполнение этого генератора, если, конечно, вы не поймаете исключение внутри самого генератора.

2. Неясно, хотите ли вы продолжить for внутри итератора или внутри main ….

3. Я хочу for , чтобы в главном блоке продолжалось. Отредактировано исходное сообщение.

4. @PaoloCasciello Вы не можете продолжить работу в main без продолжения генератора.

5. @brianpck вот почему я попросил разъяснений OP. 🙂 Ваши решения предполагают, что он может таким образом модифицировать свой генератор. Но, как он ответил, он хочет, чтобы основной цикл над генератором знал, для какого индекса он не сработал. Это другая проблема, чем та, на которую вы ответили.

Ответ №1:

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

 def f(n):
    for i in xrange(n):
        try:
            if i == 3:
                raise ValueError('hit 3')
            yield i
        except ValueError:
            print ("Error with key: {}".format(i))
  

Итерация по нему, как в вашем примере, дает:

 >>> for i in f(10):
...     print (i)
...
0
1
2
Error with key: 3
4
5
6
7
8
9
  

Ответ №2:

По состоянию на разъяснения OP, он хочет продолжить внешний основной цикл for в случае ошибки внутри генератора, показывая, при каком индексе произошла ошибка.

В ответе brianpck используется подход изменения генератора таким образом, чтобы он выводил ошибку. Таким образом, основной цикл не знает, что в этом индексе произошла ошибка, и, таким образом, у вас есть по индексу x-1 результаты, следующие за ошибкой. Иногда вы заботитесь о предположении «один индекс <-> один результат».

Чтобы решить эту проблему, мы можем вручную обработать ошибку, выдав ее, а затем решить, что делать в генераторе.

Нравится следующее:

 def f(n):
    for i in xrange(n):
        if i == 3:
            yield ValueError('hit 3')
            continue  # or break, depends on problem logic
        yield i

if __name__ == '__main__':
    a = enumerate(f(10))
    for i, x in a:
        if isinstance(x, ValueError):
            print "Error at index", i
            continue

        print i, x
  

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

Ответ №3:

Я подозреваю, что, как правило, вы хотите иметь возможность перехватывать значения, которые приводят к возникновению ошибок. Без остановки цикла внутри генератора. Вот еще один подход, который включает логическое значение в результат генератора (как 2-кортеж), который указывает, может ли вычисление быть выполнено успешно.

 def f(n):
    for i in range(n):
        accept=True
        try:
            result=1/(3-i)
        except:
            accept=False
        yield accept, i

a=enumerate(f(10))
for k,(ok,i) in a:
    print (ok,i)
  

В этом случае только значение 3 вызывает сбой. Вот результат.

 True 0
True 1
True 2
False 3
True 4
True 5
True 6
True 7
True 8
True 9