Perilaku Mencoba-Kecuali-Lain-Akhirnya yang aneh dengan pernyataan Kembali

91

Ini adalah beberapa kode yang berperilaku aneh. Ini adalah versi sederhana dari perilaku yang saya tulis. Ini masih akan menunjukkan perilaku aneh dan saya memiliki beberapa pertanyaan khusus tentang mengapa ini terjadi.

Saya menggunakan Python 2.6.6 di 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

Hasil:

>>> print demo1()
3
>>> print demo2()
6
3
  • Mengapa demo satu menghasilkan 3, bukan 1?
  • Mengapa demo dua pencetakan 6 alih-alih mencetak 6 w / 4 atau 5?
Kyle Owens
sumber

Jawaban:

128

Karena finallypernyataan dijamin akan dieksekusi (yah, anggap tidak ada pemadaman listrik atau apa pun di luar kendali Python). Ini berarti bahwa sebelum fungsi dapat kembali, ia harus menjalankan blok akhirnya, yang mengembalikan nilai yang berbeda.

The Python docs negara:

Ketika pernyataan kembali, putus atau lanjutkan dieksekusi dalam rangkaian percobaan pernyataan coba ... akhirnya, klausa akhirnya juga dieksekusi 'di jalan keluar.'

Nilai kembali dari suatu fungsi ditentukan oleh pernyataan pengembalian terakhir yang dieksekusi. Karena klausa akhirnya selalu dieksekusi, pernyataan pengembalian yang dieksekusi di klausa akhirnya akan selalu menjadi yang terakhir dieksekusi:

Ini berarti bahwa ketika Anda mencoba untuk mengembalikan, finallyblok tersebut dipanggil, mengembalikan nilainya, bukan nilai yang seharusnya Anda miliki.

Gareth Latty
sumber
4
mengapa 5 tidak mencetak pada contoh kedua? ini masih belum dijelaskan dengan baik menurut saya. kembalinya satu dijawab dengan baik tetapi mengapa 5 di contoh kedua tidak dicetak
Joran Beasley
5
oh saya pikir saya menemukan itu kembali pada percobaan awal menyebabkannya melompat segera ke luar akhirnya
Joran Beasley
2
Tepat sekali, karena finallyblok selalu berjalan.
Gareth Latty
2
Dalam demo dua, mengapa ia mengeksekusi nested akhirnya, menendang ke luar akhirnya kemudian kembali ke sarang akhirnya untuk menyelesaikan pengembalian alih-alih hanya mengembalikan None dari luar akhirnya?
Kyle Owens
1
Karena ketika returnpernyataan itu dipanggil, Python memeriksa finallyklausa terbuka apa pun yang perlu dijalankan (lihat kutipan di atas).
Gareth Latty
7

Urutan eksekusi adalah:

  1. coba blok semua selesai secara normal -> akhirnya blok -> fungsi berakhir
  2. coba blokir dan masuk ke pengecualian A -> akhirnya blok -> fungsi berakhir
  3. coba blok membuat nilai kembali dan panggil kembali -> akhirnya blok -> nilai kembali popup -> fungsi berakhir

Jadi, pengembalian apa pun di blok terakhir akan mengakhiri langkah-langkah sebelumnya.

Fred Huang
sumber