Python try-else

Каково предполагаемое использование необязательного предложения else оператора try?

Ответ 1

Операторы в блоке else выполняются, если выполнение падает с конца try - если не было исключений. Честно говоря, я никогда не нашел в этом необходимости.

Однако примечания по обработке исключений:

Использование предложения else лучше, чем добавление дополнительного кода к предложению try, поскольку оно позволяет избежать случайного перехвата исключения, которое не было вызвано кодом, защищаемым оператором try... Кроме.

Итак, если у вас есть метод, который может, например, IOError, и вы хотите перехватывать исключения, которые он вызывает, но есть еще кое-что, что вы хотите сделать, если первая операция завершится успешно, и вы не хотите перехватывать IOError из этой операции вы можете написать что-то вроде этого:

try:
    operation_that_can_throw_ioerror()
except IOError:
    handle_the_exception_somehow()
else:
    # we don't want to catch the IOError if it raised
    another_operation_that_can_throw_ioerror()
finally:
    something_we_always_need_to_do()

Если вы просто поместите another_operation_that_can_throw_ioerror() после operation_that_can_throw_ioerror, except перехватит ошибки второго вызова. И если вы поместите его после всего блока try, он всегда будет запущен, и только после того, как будет finally. else позволяет вам убедиться

  1. вторая операция выполняется, только если нет исключений,
  2. он запускается перед блоком finally, и
  3. любая IOError это поднимает, не поймана здесь

Ответ 2

Существует одна большая причина для использования else - стиля и читаемости. Как правило, рекомендуется хранить код, который может вызывать исключения, рядом с кодом, который их обрабатывает. Например, сравните это:

try:
    from EasyDialogs import AskPassword
    # 20 other lines
    getpass = AskPassword
except ImportError:
    getpass = default_getpass

а также

try:
    from EasyDialogs import AskPassword
except ImportError:
    getpass = default_getpass
else:
    # 20 other lines
    getpass = AskPassword

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

try:
    from EasyDialogs import AskPassword
except ImportError:
    getpass = default_getpass
    return False  # or throw Exception('something more descriptive')

# 20 other lines
getpass = AskPassword

Примечание: Ответ копируется из недавно размещенного дубликата здесь, следовательно, все это "AskPassword" вещи.

Ответ 3

Одно использование: проверьте код, который должен вызвать исключение.

try:
    this_should_raise_TypeError()
except TypeError:
    pass
except:
    assert False, "Raised the wrong exception type"
else:
    assert False, "Didn't raise any exception"

(Этот код должен быть абстрагирован на более общий тест на практике.)

Ответ 4

Попробуй еще Python

Для чего предназначено необязательное условие else оператора try?

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

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

Но важно понимать точные условия, которые вызывают выполнение условия else, потому что return, continue и break могут прервать поток управления в else.

В итоге

Оператор else выполняется, если исключений нет, и если он не прерывается оператором return, continue или break.

Другие ответы пропускают эту последнюю часть.

Из документов:

Необязательное условие else выполняется, если и когда управление выходит из конца предложения try. *

(Добавлен жирный шрифт.) И сноска гласит:

* В настоящее время элемент управления "вытекает из конца", за исключением случая исключения или выполнения оператора return, continue или break.

Требуется хотя бы одно предшествующее, кроме предложения (см. Грамматику). Так что на самом деле это не "try-else", это "try-else-else (-finally)", а else (и, finally) является необязательным.

Python Tutorial развивает предполагаемое использование:

Оператор try... кроме имеет необязательное предложение else, которое, если оно присутствует, должно следовать за всеми, кроме предложений. Это полезно для кода, который должен быть выполнен, если предложение try не вызывает исключение. Например:

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print 'cannot open', arg
    else:
        print arg, 'has', len(f.readlines()), 'lines'
        f.close()

Использование предложения else лучше, чем добавление дополнительного кода к предложению try, поскольку оно позволяет избежать случайного перехвата исключения, которое не было вызвано кодом, защищаемым оператором try... Кроме.

Пример дифференциация else против кода после try блока

Если вы обработаете ошибку, блок else не будет запущен. Например:

def handle_error():
    try:
        raise RuntimeError('oops!')
    except RuntimeError as error:
        print('handled a RuntimeError, no big deal.')
    else:
        print('if this prints, we had no error!') # won't print!
    print('And now we have left the try block!')  # will print!

И сейчас,

>>> handle_error()
handled a RuntimeError, no big deal.
And now we have left the try block!

Ответ 5

Try-кроме-еще отлично подходит для объединения шаблона EAFP с Duck-Typing:

try:
  cs = x.cleanupSet
except AttributeError:
  pass
else:
  for v in cs:
    v.cleanup()

Вы могли бы подумать, что этот наивный код подходит:

try:
  for v in x.cleanupSet:
    v.clenaup()
except AttributeError:
  pass

Это отличный способ случайно скрыть серьезные ошибки в вашем коде. Я опечатал там уборку, но ошибка AttributeError, которая дала бы мне знать, проглатывается. Хуже того, что если бы я написал это правильно, но метод очистки иногда передавал пользовательский тип, имеющий атрибут с неправильным именем, что приводило к тому, что он молча терпел неудачу на полпути и оставлял файл закрытым? Удачи в отладке этого.

Ответ 6

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

try:
    data = something_that_can_go_wrong()
except Exception as e: # yes, I know that a bad way to do it...
    handle_exception(e)
else:
    do_stuff(data)
finally:
    clean_up()

Ответ 7

Даже если вы не можете думать об использовании этого прямо сейчас, вы можете поспорить, что для этого нужно использовать его. Вот пример невообразимого:

С else:

a = [1,2,3]
try:
    something = a[2]
except:
    print "out of bounds"
else:
    print something

Без else:

try:
    something = a[2]
except:
    print "out of bounds"

if "something" in locals():
    print something

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

Ответ 8

Из Ошибки и исключения # Обработка исключений - docs.python.org

Оператор try ... except имеет необязательное предложение else, которое, когда они присутствуют, должны следовать всем, кроме оговорок. Это полезно для кода который должен быть выполнен, если предложение try не вызывает исключения. Например:

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print 'cannot open', arg
    else:
        print arg, 'has', len(f.readlines()), 'lines'
        f.close()

Использование предложения else лучше, чем добавление дополнительного кода в предложение try, поскольку оно позволяет избежать случайного обнаружения исключения это не было вызвано защитой кода попыткой... кроме утверждение.

Ответ 9

Вот хороший пример try-else в PEP 380. В основном, это сводится к обработке различных исключений в разных частях алгоритма.

Что-то вроде этого:

try:
    do_init_stuff()
except:
    handle_init_suff_execption()
else:
    try:
        do_middle_stuff()
    except:
        handle_middle_stuff_exception()

Это позволяет вам написать код обработки исключений ближе к месту возникновения исключения.

Ответ 10

Глядя на ссылку на Python, кажется, что else выполняется после try, когда нет исключения. Необязательное предложение else выполняется, если и когда управление течет с конца предложения try. 2 Исключения в предложении else не обрабатываются предыдущими исключениями.

Погружение в python имеет пример, где, если я правильно понимаю, в блоке try они пытаются импортировать модуль, когда это вы не получаете исключение и связываете по умолчанию, но когда он работает, вы можете перейти в блок else и связать то, что требуется (см. ссылку для примера и объяснения).

Если вы попытались выполнить работу в блоке catch, это может вызвать другое исключение - я предполагаю, что когда блок else подходит.

Ответ 11

Что это. Блок else для предложения try-except существует для кода, который запускается, когда (и только тогда) успешная попытка выполнена успешно. Его можно использовать, и его можно злоупотреблять.

try:
    fp= open("configuration_file", "rb")
except EnvironmentError:
    confdata= '' # it ok if the file can't be opened
else:
    confdata= fp.read()
    fp.close()

# your code continues here
# working with (possibly empty) confdata

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

Ответ 12

Большинство ответов, похоже, сосредоточены на том, почему мы не можем просто помещать материал в предложение else в самом предложении try. Вопрос else в заявлении try... что хорошо для, конкретно спрашивает, почему код предложения else не может идти после самого блока try, и этот вопрос дублируется этот, но я не вижу ясного ответа на этот вопрос здесь. Я чувствую, что fooobar.com/questions/17802/... отлично отвечает на этот вопрос. Я также попытался осветить различное значение различных статей в fooobar.com/questions/17803/....

Ответ 13

Возможно, использование может быть:

#debug = []

def debuglog(text, obj=None):
    " Simple little logger. "
    try:
        debug   # does global exist?
    except NameError:
        pass    # if not, don't even bother displaying
    except:
        print('Unknown cause. Debug debuglog().')
    else:
        # debug does exist.
        # Now test if you want to log this debug message
        # from caller "obj"
        try:
            if obj in debug:
                print(text)     # stdout
        except TypeError:
            print('The global "debug" flag should be an iterable.')
        except:
            print('Unknown cause. Debug debuglog().')

def myfunc():
    debuglog('Made it to myfunc()', myfunc)

debug = [myfunc,]
myfunc()

Возможно, это приведет вас к использованию.

Ответ 14

Блок else часто может существовать для дополнения функциональности, которая встречается в каждом блоке except.

try:
    test_consistency(valuable_data)
except Except1:
    inconsistency_type = 1
except Except2:
    inconsistency_type = 2
except:
    # Something else is wrong
    raise
else:
    inconsistency_type = 0

"""
Process each individual inconsistency down here instead of
inside the except blocks. Use 0 to mean no inconsistency.
"""

В этом случае inconsistency_type устанавливается в каждом исключающем блоке, так что поведение дополняется в случае без ошибок в else.

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

Ответ 15

Вот еще одно место, где мне нравится использовать этот шаблон:

 while data in items:
     try
        data = json.loads(data)
     except ValueError as e:
        log error
     else:
        # work on the `data`

Ответ 16

Я нашел else полезное для работы с возможно неправильным файлом конфигурации:

try:
    value, unit = cfg['lock'].split()
except ValueError:
    msg = 'lock monitoring config must consist of two words separated by white space'
    self.log('warn', msg)
else:
     # get on with lock monitoring if config is ok

Исключение при чтении конфигурации lock отключает мониторинг блокировки, и ValueErrors записывает полезное предупреждающее сообщение.

Ответ 17

Я нашел конструкцию try: ... else: полезной в ситуации, когда вы выполняете запросы к базе данных и регистрируете результаты этих запросов в отдельной базе данных того же типа/типа. Скажем, у меня много рабочих потоков, которые обрабатывают запросы к базе данных, отправленные в очередь

#in a long running loop
try:
    query = queue.get()
    conn = connect_to_db(<main db>)
    curs = conn.cursor()
    try:
        curs.execute("<some query on user input that may fail even if sanitized">)
    except DBError:
        logconn = connect_to_db(<logging db>)
        logcurs = logconn.cursor()
        logcurs.execute("<update in DB log with record of failed query")
        logcurs.close()
        logconn.close()
    else:

        #we can't put this in main try block because an error connecting
        #to the logging DB would be indistinguishable from an error in 
        #the mainquery 

        #We can't put this after the whole try: except: finally: block
        #because then we don't know if the query was successful or not

        logconn = connect_to_db(<logging db>)
        logcurs = logconn.cursor()
        logcurs.execute("<update in DB log with record of successful query")
        logcurs.close()
        logconn.close()
        #do something in response to successful query
except DBError:
    #This DBError is because of a problem with the logging database, but 
    #we can't let that crash the whole thread over what might be a
    #temporary network glitch
finally:
    curs.close()
    conn.close()
    #other cleanup if necessary like telling the queue the task is finished

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

Ответ 18

Предположим, что ваша логика программирования зависит от того, есть ли в словаре запись с заданным ключом. Вы можете проверить результат dict.get(key) используя конструкцию if... else..., или вы можете сделать:

try:
    val = dic[key]
except KeyError:
    do_some_stuff()
else:
    do_some_stuff_with_val(val)

Ответ 19

Один из сценариев использования, о которых я могу думать, - непредсказуемые исключения, которые можно обойти, если вы попробуете еще раз. Например, когда операции в блоке try включают случайные числа:

while True:
    try:
        r = random.random()
        some_operation_that_fails_for_specific_r(r)
    except Exception:
        continue
    else:
        break

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

Ответ 20

Блок else: путается и (почти) бесполезен. Он также является частью операторов for и while.

На самом деле, даже при if -statement, else: можно портить ужасно, создавая ошибки, которые очень трудно найти.

Рассмотрим это.

   if a < 10:
       # condition stated explicitly
   elif a > 10 and b < 10:
       # condition confusing but at least explicit
   else:
       # Exactly what is true here?
       # Can be hard to reason out what condition is true

Подумайте дважды о else:. Это, как правило, проблема. Избегайте его, кроме как в if -statement, и даже тогда рассмотрите документирование условия else, чтобы сделать его явным.