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 NotImplementedkarena jenis yang dibandingkan berbeda. Pertimbangkan contoh lain di mana dua objek dengan jenis yang berbeda dibandingkan dengan cara ini, seperti 1dan '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
Falsedikembalikan.
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 NotImplementedsebenarnya 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 NotImplementedadalah kebenaran, tetapi itu akan menjadi cerita yang berbeda seandainya kelas mendefinisikan suatu __bool__atau __len__metode yang kembali Falseatau 0masing - 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
Noneadalah objek khusus, dan hanya 1 versi yang ada di memori pada suatu titik waktu. TKI, itu adalah singleton tunggal dari NoneTypekelas (tetapi objek yang sama dapat memiliki sejumlah referensi). The pedoman PEP8 membuat eksplisit:
Perbandingan dengan orang lajang seperti Noneharus selalu dilakukan dengan isatau
is not, tidak pernah dengan operator kesetaraan.
Singkatnya, untuk lajang suka None, cek referensi dengan islebih tepat, meskipun keduanya ==dan isakan berfungsi dengan baik.