Подтвердить что ты не робот

Исключить

Я обнаружил следующее поведение, по крайней мере, странное:

def errors():
    try:
        ErrorErrorError
    finally:
        return 10

print errors()
# prints: 10
# It should raise: NameError: name 'ErrorErrorError' is not defined

Исключение исчезает, когда вы используете return внутри предложения finally. Это ошибка? Это где-нибудь документировано?

Но реальный вопрос (и ответ, который я буду отмечать как правильный): Какова причина разработчиков python для этого нечетного поведения?

4b9b3361

Ответ 1

Вы спросили о рассуждениях разработчиков Python. Я не могу говорить за них, но никакого другого поведения не имеет смысла. Функция может либо вернуть значение, либо может вызвать исключение; он не может сделать то и другое. Цель "finally" заключается в том, чтобы обеспечить очистку кода, который "гарантирован" должен выполняться независимо от исключений. Поместив оператор return в предложение finally, вы заявили, что хотите вернуть значение независимо от того, вне зависимости от его исключения. Если бы Python вел себя так, как вы просите, и вызвал исключение, он нарушил бы контракт "finally" (потому что он не смог вернуть значение, которое вы ему сказали).

Ответ 2

Исключение исчезает, когда вы используете return внутри предложения finally... Является ли это документированным где угодно?

Это:

Если, наконец, присутствует, он указывает "обработчик очистки". Предложение try выполняется, включая любые предложения except и else. Если исключение возникает в любом из предложений и не обрабатывается, исключение временно сохраняется. Предложение finally выполняется. Если есть сохраненное исключение, оно будет повторно поднято в конце предложения finally. Если предложение finally возвращает другое исключение или выполняет оператор return или break, сохраненное исключение теряется.

Ответ 3

Вот интересное сравнение для возврата в блоке finally, среди - Java/С#/Python/JavaScript: (архивная ссылка)

Вернись наконец

Просто сегодня я помог с какой-то ошибкой в Java и наткнулся интересная проблема - что произойдет, если вы используете return в try/catch выражение? Должен ли наконец-то запускаться раздел или нет? Я упростила проблема в следующем фрагменте кода:

Что печатает следующий код?

class ReturnFromFinally {  
 public static int a() {  
  try {  
   return 1;  
  }  
  catch (Exception e) {}  
  finally{  
   return 2;  
  }  
 }  

        public static void main(String[] args) {  
  System.out.println(a());  
        }  
}  

Мое первоначальное предположение было бы, что это должно распечатать 1, я звоню return, поэтому я предполагаю, что один будет возвращен. Тем не менее, это не случай:

the second return is executed

Я понимаю логику, наконец, раздел должен быть выполнен, но как-то мне неловко по этому поводу. Давайте посмотрим, что С# делает в этом случае:

class ReturnFromFinally  
{  
 public static int a()  
 {  
  try {  
          return 1;  
  }  
  catch (System.Exception e) {}  
  finally   
  {   
   return 2;  
  }  
 }  

 public static void Main(string[] args)  
 {  
  System.Console.WriteLine(a());  
 }  
}  

error CS0157 Control cannot leave the body of a finally clause

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

Python:

def a():  
 try:  
  return 1  
 finally:  
  return 2  
print a()  

Python returns 2 as well

JavaScript:

<script>  
function ReturnFromFinally()  
{  
 try  
 {  
  return 1;  
 }  
 catch (e)  
 {  
 }  
 finally  
 {  
  return 2;  
 }  
}  
</script>  
<a onclick="alert(ReturnFromFinally());">Click here</a>  

JavaScript returns 2 as well

В C++ и PHP нет пункта finally, поэтому я не могу попробовать последний два языка, для которых у меня есть компилятор/интерпретатор.

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

Ответ 4

Возвращение из окончательно не - хорошая идея. Я знаю, что С# специально запрещает это делать.