Karena Python tidak menyediakan versi kiri / kanan dari operator pembandingnya, bagaimana cara memutuskan fungsi mana yang akan dipanggil?
class A(object):
def __eq__(self, other):
print "A __eq__ called"
return self.value == other
class B(object):
def __eq__(self, other):
print "B __eq__ called"
return self.value == other
>>> a = A()
>>> a.value = 3
>>> b = B()
>>> b.value = 4
>>> a == b
"A __eq__ called"
"B __eq__ called"
False
Ini sepertinya memanggil keduanya __eq__
fungsi tersebut.
Saya mencari pohon keputusan resmi.
sumber
__eq__
hanya pada contoh beberapa jenis tidak cukup untuk == diganti?Saya menulis jawaban terbaru untuk Python 3 untuk pertanyaan ini.
Secara umum dipahami, tetapi tidak selalu demikian, yang
a == b
memanggila.__eq__(b)
, atautype(a).__eq__(a, b)
.Secara eksplisit, urutan evaluasi adalah:
b
tipe adalah subkelas ketat (bukan tipe yang sama) daria
tipe dan memiliki__eq__
, panggil dan kembalikan nilainya jika perbandingan diimplementasikan,a
sudah__eq__
, panggil dan kembalikan jika perbandingan diterapkan,__eq__
dan ia memilikinya, lalu panggil dan kembalikan jika perbandingan diterapkan,is
.Kami tahu jika perbandingan tidak diterapkan jika metode tersebut kembali
NotImplemented
.(Di Python 2, ada
__cmp__
metode yang dicari, tetapi tidak digunakan lagi dan dihapus di Python 3.)Mari kita uji perilaku pemeriksaan pertama untuk diri kita sendiri dengan membiarkan B subclass A, yang menunjukkan bahwa jawaban yang diterima salah dalam hitungan ini:
yang hanya mencetak
B __eq__ called
sebelum dikembalikanFalse
.Bagaimana kita mengetahui algoritma lengkap ini?
Jawaban lain di sini tampaknya tidak lengkap dan ketinggalan zaman, jadi saya akan memperbarui informasi dan menunjukkan kepada Anda bagaimana Anda dapat mencarinya sendiri.
Ini ditangani di tingkat C.
Kita perlu melihat dua bit kode yang berbeda di sini - default
__eq__
untuk objek kelasobject
, dan kode yang mencari dan memanggil__eq__
metode terlepas dari apakah metode itu menggunakan default__eq__
atau kustom.Default
__eq__
Mencari
__eq__
di dokumen C api yang relevan menunjukkan kepada kita bahwa__eq__
ditangani olehtp_richcompare
- yang dalam"object"
definisi tipe dicpython/Objects/typeobject.c
didefinisikanobject_richcompare
untukcase Py_EQ:
.Jadi di sini, jika
self == other
kita mengembalikanTrue
, kalau tidak kita mengembalikanNotImplemented
objeknya. Ini adalah perilaku default untuk setiap subclass objek yang tidak mengimplementasikan__eq__
metodenya sendiri .Bagaimana
__eq__
dipanggilKemudian kami menemukan dokumen C API, fungsi PyObject_RichCompare , yang memanggil
do_richcompare
.Kemudian kita melihat bahwa
tp_richcompare
fungsi yang dibuat untuk"object"
definisi C dipanggil olehdo_richcompare
, jadi mari kita lihat itu lebih dekat.Pemeriksaan pertama dalam fungsi ini adalah untuk kondisi objek yang dibandingkan:
__eq__
metode,lalu panggil metode lain dengan argumen bertukar, mengembalikan nilai jika diterapkan. Jika metode itu tidak diterapkan, kami melanjutkan ...
Selanjutnya kita melihat apakah kita dapat mencari
__eq__
metode dari tipe pertama dan memanggilnya. Selama hasilnya tidak NotImplemented, yaitu diimplementasikan, kami mengembalikannya.Lain jika kita tidak mencoba metode tipe lain dan metode itu ada, kita kemudian mencobanya, dan jika perbandingan diterapkan, kita mengembalikannya.
Akhirnya, kami mendapatkan fallback jika tidak diterapkan untuk salah satu jenisnya.
Pemeriksaan fallback untuk identitas objek, yaitu, apakah itu objek yang sama di tempat yang sama dalam memori - ini adalah pemeriksaan yang sama untuk
self is other
:Kesimpulan
Sebagai perbandingan, kami menghormati implementasi subclass dari perbandingan terlebih dahulu.
Kemudian kami mencoba membandingkan dengan implementasi objek pertama, kemudian dengan implementasi objek kedua jika tidak dipanggil.
Akhirnya kami menggunakan tes identitas untuk perbandingan kesetaraan.
sumber