Как обрабатывать исключения в списке пониманий? - PullRequest
86 голосов
/ 07 октября 2009

У меня есть некоторое понимание списка в Python, в котором каждая итерация может генерировать исключение.

Например, , если у меня есть:

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

[1/egg for egg in eggs]

Я получу исключение ZeroDivisionError в третьем элементе.

Как мне обработать это исключение и продолжить выполнение понимания списка?

Единственный способ, которым я могу думать, - это использовать вспомогательную функцию:

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

Но это выглядит немного громоздко для меня.

Есть ли лучший способ сделать это в Python?

Примечание: Это простой пример (см. « для примера » выше), который я придумал, потому что мой реальный пример требует некоторого контекста. Я не заинтересован в том, чтобы избегать деления на ноль ошибок, а в том, чтобы обрабатывать исключения в понимании списка.

Ответы [ 5 ]

84 голосов
/ 18 января 2012

Я понимаю, что этот вопрос довольно старый, но вы также можете создать общую функцию, чтобы упростить такие вещи:

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]

Конечно, вы можете сделать функцию дескриптора по умолчанию любой, какой захотите (скажем, вы бы предпочли вернуть 'None' по умолчанию).

Надеюсь, это поможет вам или будущим читателям этого вопроса!

Примечание: в python 3 я бы делал только ключевое слово аргумента handle и помещал его в конец списка аргументов. Это сделало бы на самом деле передачу аргументов и тому подобного через улов намного более естественным.

73 голосов
/ 07 октября 2009

В Python нет встроенного выражения, которое позволяло бы игнорировать исключение (или возвращать альтернативные значения & c в случае исключений), поэтому, буквально говоря, невозможно "обрабатывать исключения в понимании списка", потому что понимание списка является выражением, содержащим другое выражение, ничего более (т.е. операторы no , и только операторы могут перехватывать / игнорировать / обрабатывать исключения).

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

Правильные ответы на вопрос «как обрабатывать исключения в понимании списка» все выражают часть всей этой истины: 1) буквально, т. Е. Лексически в самом понимании, вы не можете; 2) практически вы делегируете задание в функцию или проверяете наличие подверженных ошибкам значений, когда это возможно. Ваше повторное утверждение, что это не ответ, таким образом, является необоснованным.

19 голосов
/ 07 октября 2009

Вы можете использовать

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

это просто пропустит нулевые элементы.

7 голосов
/ 07 октября 2009

Нет, лучшего способа нет. Во многих случаях вы можете использовать избегание, как это делает Питер

Другой вариант - не использовать понимания

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

Вам решать, будет ли это более громоздким или нет

3 голосов
/ 08 ноября 2016

Я думаю, что вспомогательная функция, предложенная тем, кто задает первоначальный вопрос, а также Брайаном Хедом, хороша и совсем не обременительна. Одна строка магического кода, которая выполняет всю работу, просто не всегда возможна, поэтому вспомогательная функция является идеальным решением, если вы хотите избежать циклов 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)]. С этим ответом вы получаете полный контроль над тем, чтобы продолжить, как вы хотите.

...