Mengapa mengembalikan NotImplemented alih-alih menaikkan NotImplementedError

283

Python memiliki singleton bernama NotImplemented.

Mengapa seseorang ingin kembali NotImplementeddaripada mengajukan NotImplementedErrorpengecualian? Tidakkah itu hanya mempersulit menemukan bug, seperti kode yang mengeksekusi metode yang tidak valid?

abyx
sumber

Jawaban:

281

Itu karena __lt__()dan metode perbandingan terkait cukup umum digunakan secara tidak langsung dalam jenis daftar dan semacamnya. Terkadang algoritma akan memilih untuk mencoba cara lain atau memilih pemenang default. Menaikkan pengecualian akan keluar dari jenis kecuali tertangkap, sedangkan NotImplementedtidak dinaikkan dan dapat digunakan dalam tes lebih lanjut.

http://jcalderone.livejournal.com/32837.html

Untuk meringkas tautan itu:

" NotImplementedmemberi sinyal ke runtime bahwa ia harus meminta orang lain untuk memenuhi operasi. Dalam ekspresi a == b, jika a.__eq__(b)kembali NotImplemented, maka Python mencoba b.__eq__(a). Jika bcukup tahu untuk mengembalikan Trueatau False, maka ekspresi dapat berhasil. Jika tidak, maka runtime akan kembali ke perilaku bawaan (yang didasarkan pada identitas untuk ==dan !=). "

SPIFF
sumber
5
Saya akan berhati-hati menggunakannya, karena tautan ini menunjukkan di dekat akhir dokumen.
Jason Coon
16
Ketika interpreter Python memeriksa apakah a.__eq__(b)NotImplemented dikembalikan, bukankah ia bisa dengan mudah menangkap NotImplementedError sebagai gantinya (dan menelepon b.__eq__(a)atau apa pun itu)?
Veky
24
@Veky. Meningkatkan pengecualian mungkin memiliki overhead yang lebih tinggi. Setiap overhead dalam operasi pengurutan akan diperbesar dengan ukuran daftar sehingga meskipun perbedaannya sangat kecil, masih masuk akal untuk menemukan implementasi yang lebih cepat. Anda juga tidak ingin keluar dari loop Anda dan masuk kembali mereka yang membutuhkan implementasi try / catch.
SpliFF
3
Untuk poin pertama, solusi yang lebih cepat adalah mensintesis lt secara otomatis sebagai gt terbalik, alih-alih selalu memanggil sesuatu yang akan mengembalikan NotImplemented - dan Python tidak melakukan itu. Saya tidak berpikir kecepatan adalah alasannya di sini. Dan untuk yang kedua, saya tidak mengerti apa yang Anda katakan: kembali akan membutuhkan banyak keluar dari loop seperti kenaikan gaji. Bahkan, Anda bisa membayangkan pengembalian sebagai memunculkan pengecualian Pengembalian khusus, yang selalu tertangkap dalam ruang lingkup panggilan.
Veky
2
>> "diperbesar oleh ukuran daftar" Setidaknya, kecuali Anda memiliki jenis O (n) yang dunia harus ketahui.
Jonathan Hartley
107

Karena mereka memiliki kasus penggunaan yang berbeda.

Mengutip dokumen (Python 3.6):

NotImplemented

harus dikembalikan oleh metode khusus biner (misalnya __eq__(), __lt__(), __add__(), __rsub__(), dll) untuk menunjukkan bahwa operasi tidak dilaksanakan sehubungan dengan jenis lain

pengecualian NotImplementedError

[...] Dalam kelas dasar yang ditentukan pengguna, metode abstrak harus meningkatkan pengecualian ini ketika mereka membutuhkan kelas turunan untuk mengganti metode, atau saat kelas sedang dikembangkan untuk menunjukkan bahwa implementasi nyata masih perlu ditambahkan.

Lihat tautan untuk detailnya.

Paolo
sumber
Ini harus menjadi jawaban yang diterima. Ini bahkan lebih kuat daripada kasus penggunaan, ini merupakan indikasi niat - yang dengan Kesalahan di akhir nama menandakan bahwa Kesalahan telah terjadi (karena sesuatu tidak diimplementasikan), yang lain bukan kesalahan tetapi "tepat" tingkah laku. Saya akan menyamakannya dengan perbedaan antara mengembalikan NaN atau menaikkan ValueError.
Korone
13

Salah satu alasannya adalah kinerja. Dalam situasi seperti perbandingan kaya, di mana Anda bisa melakukan banyak operasi dalam waktu singkat, menyiapkan dan menangani banyak pengecualian bisa memakan waktu lebih lama daripada sekadar mengembalikan NotImplementednilai.

RichieHindle
sumber