Comportamento estranho Try-Except-Else-Finalmente com declarações Return

88

Este é um código que está se comportando de maneira peculiar. Esta é uma versão simplificada do comportamento que escrevi. Isso ainda demonstrará o comportamento estranho e eu tinha algumas perguntas específicas sobre por que isso está ocorrendo.

Estou usando o Python 2.6.6 no Windows 7.

def demo1():
    try:
        raise RuntimeError,"To Force Issue"
    except:
        return 1
    else:
        return 2
    finally:
        return 3

def demo2():
    try:
        try:
            raise RuntimeError,"To Force Issue"
        except:
            return 1
        else:
            return 2
        finally:
            return 3
    except:
        print 4
    else:
        print 5
    finally:
        print 6

Resultados:

>>> print demo1()
3
>>> print demo2()
6
3
  • Por que a demonstração um está retornando 3 em vez de 1?
  • Por que o demo dois imprime 6 em vez de imprimir 6 w / 4 ou 5?
Kyle Owens
fonte

Respostas:

124

Porque as finallyinstruções têm garantia de execução (bem, presumindo que não haja queda de energia ou qualquer coisa fora do controle do Python). Isso significa que antes que a função possa retornar, ela deve executar o bloco finally, que retorna um valor diferente.

O estado dos documentos Python :

Quando uma instrução return, break ou continue é executada no conjunto try de uma instrução try… finally, a cláusula finally também é executada 'na saída'.

O valor de retorno de uma função é determinado pela última instrução de retorno executada. Visto que a cláusula finally sempre executa, uma instrução return executada na cláusula finally será sempre a última executada:

Isso significa que quando você tenta retornar, o finallybloco é chamado, retornando seu valor, ao invés do que você teria.

Gareth Latty
fonte
4
por que o 5 não imprime no segundo exemplo? isso ainda não está bem explicado, eu acho. o de retorno é bem respondido, mas por que o 5 no segundo exemplo não é impresso
Joran Beasley
5
Oh, eu acho que descobri que o retorno na tentativa inicial faz com que ele pule imediatamente para o exterior finalmente
Joran Beasley
2
Exatamente, porque os finallyblocos sempre são executados.
Gareth Latty
2
Na demonstração dois, por que ele executa o aninhado, finalmente, expulso para fora finalmente e depois volta para o aninhado para finalizar o retorno, em vez de simplesmente retornar Nenhum do lado de fora finalmente?
Kyle Owens
1
Porque quando a returninstrução é chamada, o Python verifica se há finallycláusulas abertas que precisam ser executadas (consulte a citação acima).
Gareth Latty
6

A ordem de execução é:

  1. tente bloquear tudo é concluído normalmente -> bloco finalmente -> função termina
  2. tente executar o bloco e entrar na exceção A -> bloco finalmente -> término da função
  3. tente o bloco faz um valor de retorno e chama o retorno -> bloco finalmente -> valor de retorno do popup -> termina a função

Portanto, qualquer retorno no bloco finally encerrará as etapas antecipadamente.

Fred Huang
fonte