Как вернуть значение и вызвать исключение

У меня есть две цели с этим заявлением try/except.

  1. Ему необходимо return значение 1, если проблем не возникло, или 0, если возникли какие-либо проблемы.
  2. Он должен вызвать исключение и завершить скрипт.

У меня работает значение return. У меня тоже работает SystemExit(). Но вместе они не работают.

Мой скрипт Python (актуально):

except IOError:
    value_to_return = 0
    return value_to_return
    raise SystemExit("FOOBAR")

При этом он полностью игнорирует строку raise SystemExit("FOOBAR"). Как мне получить возвращаемое значение и все еще raise SystemExit("FOOBAR")? Кому-то это покажется элементарным, но у меня с этим довольно большие трудности.


person misterbear    schedule 21.01.2014    source источник
comment
Если вы вызываете SystemExit и действительно хотите, чтобы ваш сценарий завершился, куда должно идти возвращаемое значение (скрипт все-таки закончился)? или вы хотите сначала поймать исключение, вернуться, выполнить некоторую обработку ошибок и выйти позже?   -  person    schedule 21.01.2014
comment
если вы вернетесь, повышения не произойдет. Вы не можете сделать оба в любом случае! Выберите, что вы хотите, выйти или вернуться.   -  person Raul Guiu    schedule 21.01.2014
comment
Просто предположение, но вам, вероятно, нужно вернуть 0 и заставить вызывающего поднять SystemExit. Невозможно сделать и то, и другое в одной и той же функции.   -  person roippi    schedule 21.01.2014
comment
Вы пытаетесь вернуть код состояния в оболочку?   -  person Daniel    schedule 21.01.2014
comment
Я перепроверил у ведущего инженера. Он хочет, чтобы мой сценарий вернул 0, поскольку что-то не так, и чтобы сценарий завершился, потому что с этого момента он становится бесполезным. Поэтому мне нужно вернуть 0 и завершить скрипт. Я пробовал все остальные ответы ниже, ни один не работал.   -  person misterbear    schedule 21.01.2014
comment
Там все равно смысла нет. 0 — это код выхода для того, чтобы все прошло нормально, поэтому в данном случае это не звучит как разумный код выхода. Если это код выхода, raise SystemExit без возврата должно быть нормально, или sys.exit(), если вы импортировали sys, или просто запустите поток управления с конца скрипта.   -  person user2357112 supports Monica    schedule 21.01.2014


Ответы (6)


Возврат и повышение являются взаимоисключающими.

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

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

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

person user2357112 supports Monica    schedule 21.01.2014
comment
@ingyhere: Нет, этот учебный раздел просто отстой. Кто-то из IIRC скопировал плохо написанное описание из комментария Github, не изучив его достаточно внимательно. finally приостановит распространение исключения, а затем return отменит исключение и вместо этого вернет "value". - person user2357112 supports Monica; 21.01.2020
comment
справочник по языку содержит более точное описание, в частности Если в предложении finally выполняется оператор return или break, сохраненное исключение отбрасывается. Справочник по языку, как правило, лучше, чем учебник (но справочник по языку также не идеален; например, в нем часто не упоминается, как различные операции могут быть настроены с помощью магических методов). - person user2357112 supports Monica; 21.01.2020
comment
Хорошо, @user2357112поддерживает Монику. Я запустил пример программы, и вы действительно правы. ссылка на Python.org, представленная выше к сожалению, дословно говорится: если исключение не обрабатывается предложением exclude, исключение повторно возникает после того, как предложение finally было выполнено. В нем также обсуждается пример, в котором выполняется finally, а затем исключение. Хотя это не обязательно противоречит тому, что вы написали. К сожалению, в других сообщениях SO есть противоречие. Предыдущий комментарий удален для ясности. - person ingyhere; 21.01.2020

Чтобы выйти из скрипта и вернуть статус выхода, используйте sys.exit():

import sys
sys.exit(value_to_return)
person Dan Getz    schedule 21.01.2014
comment
Не могли бы вы также использовать __builtins__.exit(value_to_return)? - person UCYT5040; 01.06.2021
comment
@UltimateCreeper да, похоже. sys.exit, по-видимому, предпочтительнее в программах, см. в питоне"> stackoverflow.com/questions/6501121/ - person Dan Getz; 01.06.2021

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

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

def your_f():
    try:
      some_io_thingy_ok()
      return 1
    except IOError:
        raise SystemExit("FOOBAR", 0)

try:
    my_returning_value = your_f()
except SystemExit as err:
    my_returning_value = err.args[1]


print(my_returning_value)

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

Когда возникает исключение, оно может иметь связанное значение, также известное как аргумент исключения. Наличие и тип аргумента зависят от типа исключения.

Предложение exclude может указывать переменную после имени исключения. Переменная привязана к экземпляру исключения с аргументами, хранящимися в instance.args. Для удобства экземпляр исключения определяет str(), чтобы аргументы можно было распечатать напрямую, без ссылки на .args. Можно также сначала создать экземпляр исключения, прежде чем его вызывать, и добавить к нему любые атрибуты по желанию.

person Natacha    schedule 15.08.2020

Я думаю, что вы можете искать что-то вроде этого:

def some_function():
    # this function should probably do some stuff, then return 1 if
    # it was successful or 0 otherwise.
    pass

def calling_function():
    a = some_function()
    if a == 1:
        raise SystemExit('Get the heck outta here!')
    else:
        # Everything worked!
        pass
person Cody Piersall    schedule 21.01.2014

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

Например: у меня есть функция (с именем «func»), которая что-то считает, и мне нужен (частичный) результат, даже если во время подсчета произошло исключение. В моем примере я буду использовать исключение KeyboardInterrupt (пользователь нажал CTRL-C).

Без обработки исключений в функции (это неправильно, при любом исключении функция ничего не возвращает):

def func():
    s=0
    for i in range(10):
        s=s+1
        time.sleep(0.1)
    return s


x=0
try:
    for i in range(10):
       s=func()
       x=x+s
except KeyboardInterrupt:
    print(x)
else:
    print(x)

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

def func():
    try:
        s=0
        for i in range(10):
            s=s+1
            time.sleep(0.1)
    except KeyboardInterrupt: # <- the trick is here
        return s, True        # <- the trick is here
    return s, False           # <- the trick is here


x=0
try:
    for i in range(10):
        s,e=func()
        x=x+s
        if e:                         # <- and here
            raise KeyboardInterrupt   # <- and here
except KeyboardInterrupt:
    print(x)
else:
    print(x)

Примечание: мой пример — python3. Модуль времени используется (в обоих приведенных выше кодах), но я не импортировал его, чтобы сделать его короче. Если вы хотите действительно попробовать, поставьте в начале:

import time
person redseven    schedule 06.06.2018

я искал ответ, не используя попытку, используйте ключевое слово «наконец», подобное этому .. если кто-нибудь знает, напишите мне, вот ответ на вашу проблему

try:
    9/0#sample error "don't know how to make IOError"
except ZeroDivisionError:
    value_to_return = 0
    raise SystemExit("FOOBAR")
finally:return value_to_return
person ChesIngosan    schedule 18.09.2020