Ini adalah contoh yang bagus tentang mengapa __dunder__
metode tidak boleh digunakan secara langsung karena mereka sering tidak sesuai untuk operator mereka yang setara; Anda harus menggunakan ==
operator sebagai gantinya untuk perbandingan kesetaraan, atau dalam kasus khusus ini, saat memeriksa None
, gunakan is
(lewati ke bagian bawah jawaban untuk informasi lebih lanjut).
Anda sudah selesai
None.__eq__('a')
# NotImplemented
Yang kembali NotImplemented
karena jenis yang dibandingkan berbeda. Pertimbangkan contoh lain di mana dua objek dengan jenis yang berbeda dibandingkan dengan cara ini, seperti 1
dan 'a'
. Melakukannya (1).__eq__('a')
juga tidak benar, dan akan kembali NotImplemented
. Cara yang tepat untuk membandingkan kedua nilai ini untuk persamaan adalah
1 == 'a'
# False
Yang terjadi di sini adalah
- Pertama,
(1).__eq__('a')
dicoba, yang mengembalikan NotImplemented
. Ini menunjukkan bahwa operasi tidak didukung, jadi
'a'.__eq__(1)
disebut, yang juga mengembalikan yang sama NotImplemented
. Begitu,
- Objek diperlakukan seolah-olah tidak sama, dan
False
dikembalikan.
Berikut adalah MCVE kecil yang menyenangkan menggunakan beberapa kelas khusus untuk menggambarkan bagaimana ini terjadi:
class A:
def __eq__(self, other):
print('A.__eq__')
return NotImplemented
class B:
def __eq__(self, other):
print('B.__eq__')
return NotImplemented
class C:
def __eq__(self, other):
print('C.__eq__')
return True
a = A()
b = B()
c = C()
print(a == b)
# A.__eq__
# B.__eq__
# False
print(a == c)
# A.__eq__
# C.__eq__
# True
print(c == a)
# C.__eq__
# True
Tentu saja, itu tidak menjelaskan mengapa operasi itu kembali benar. Ini karena NotImplemented
sebenarnya adalah nilai kebenaran:
bool(None.__eq__("a"))
# True
Sama dengan,
bool(NotImplemented)
# True
Untuk informasi lebih lanjut tentang nilai apa yang dianggap benar dan salah, lihat bagian dokumen tentang Pengujian Nilai Kebenaran , serta jawaban ini . Perlu dicatat di sini bahwa itu NotImplemented
adalah kebenaran, tetapi itu akan menjadi cerita yang berbeda seandainya kelas mendefinisikan suatu __bool__
atau __len__
metode yang kembali False
atau 0
masing - masing.
Jika Anda menginginkan fungsional yang setara dengan ==
operator, gunakan operator.eq
:
import operator
operator.eq(1, 'a')
# False
Namun, seperti disebutkan sebelumnya, untuk skenario khusus ini , tempat Anda memeriksa None
, gunakan is
:
var = 'a'
var is None
# False
var2 = None
var2 is None
# True
Setara fungsional ini menggunakan operator.is_
:
operator.is_(var2, None)
# True
None
adalah objek khusus, dan hanya 1 versi yang ada di memori pada suatu titik waktu. TKI, itu adalah singleton tunggal dari NoneType
kelas (tetapi objek yang sama dapat memiliki sejumlah referensi). The pedoman PEP8 membuat eksplisit:
Perbandingan dengan orang lajang seperti None
harus selalu dilakukan dengan is
atau
is not
, tidak pernah dengan operator kesetaraan.
Singkatnya, untuk lajang suka None
, cek referensi dengan is
lebih tepat, meskipun keduanya ==
dan is
akan berfungsi dengan baik.