นี่เป็นตัวอย่างที่ดีว่าทำไม__dunder__
ไม่ควรใช้วิธีการโดยตรงเนื่องจากเป็นวิธีที่ไม่เหมาะสมในการทดแทนตัวดำเนินการที่เทียบเท่า คุณควรใช้==
โอเปอเรเตอร์แทนการเปรียบเทียบความเท่าเทียมกันหรือในกรณีพิเศษนี้เมื่อตรวจสอบNone
ใช้is
(ข้ามไปที่ด้านล่างของคำตอบสำหรับข้อมูลเพิ่มเติม)
คุณทำไปแล้ว
None.__eq__('a')
# NotImplemented
ซึ่งผลตอบแทนNotImplemented
ตั้งแต่ประเภทการเปรียบเทียบแตกต่างกัน พิจารณาอีกตัวอย่างหนึ่งที่วัตถุสองชนิดที่แตกต่างกันถูกเปรียบเทียบแบบนี้เช่นและ1
'a'
การทำเช่นนี้ยังไม่ถูกต้องและจะกลับมา(1).__eq__('a')
NotImplemented
วิธีที่ถูกต้องในการเปรียบเทียบค่าทั้งสองนี้เพื่อความเท่าเทียมกันคือ
1 == 'a'
# False
เกิดอะไรขึ้นที่นี่คือ
- ครั้งแรกที่มีการพยายามที่ผลตอบแทน
(1).__eq__('a')
NotImplemented
สิ่งนี้บ่งชี้ว่าการดำเนินการไม่ได้รับการสนับสนุนดังนั้น
'a'.__eq__(1)
NotImplemented
เรียกว่าซึ่งผลตอบแทนที่เดียวกัน ดังนั้น,
- วัตถุได้รับการปฏิบัติราวกับว่าพวกเขาจะไม่เหมือนกันและ
False
จะถูกส่งกลับ
นี่เป็น MCVE เล็ก ๆ น้อย ๆ ที่ดีที่ใช้คลาสที่กำหนดเองเพื่อแสดงให้เห็นว่าสิ่งนี้เกิดขึ้นได้อย่างไร:
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
แน่นอนว่าไม่ได้อธิบายว่าทำไมการดำเนินการจึงกลับเป็นจริง เพราะนี่คือNotImplemented
คุณค่าที่แท้จริง:
bool(None.__eq__("a"))
# True
เหมือนกับ,
bool(NotImplemented)
# True
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับค่าใดที่ถือว่าเป็นความจริงและเป็นเท็จให้ดูส่วนเอกสารเกี่ยวกับการทดสอบความจริงและคำตอบนี้ มันคุ้มค่าที่จะสังเกตว่านี่NotImplemented
คือความจริง แต่มันจะเป็นเรื่องที่แตกต่างกันเมื่อชั้นเรียนกำหนด__bool__
หรือ__len__
วิธีการที่กลับมาFalse
หรือ0
ตามลำดับ
หากคุณต้องการฟังก์ชั่นที่เทียบเท่ากับ==
ผู้ปฏิบัติงานให้ใช้operator.eq
:
import operator
operator.eq(1, 'a')
# False
อย่างไรก็ตามตามที่กล่าวไว้ก่อนหน้านี้สำหรับสถานการณ์เฉพาะที่คุณกำลังตรวจสอบให้None
ใช้is
:
var = 'a'
var is None
# False
var2 = None
var2 is None
# True
ฟังก์ชันที่เทียบเท่ากับสิ่งนี้คือการใช้operator.is_
:
operator.is_(var2, None)
# True
None
เป็นวัตถุพิเศษและมีเพียง 1 รุ่นเท่านั้นที่อยู่ในหน่วยความจำ ณ จุดใดก็ได้ IOW มันเป็นซิงเกิลตันของNoneType
คลาส (แต่วัตถุเดียวกันอาจมีหมายเลขอ้างอิงใด ๆ ) แนวทาง PEP8ทำให้เรื่องนี้อย่างชัดเจน:
การเปรียบเทียบกับซิงเกิลตันNone
ควรทำด้วยเสมอis
หรือ
is not
ไม่ควรใช้ตัวดำเนินการที่เท่าเทียมกัน
โดยสรุปสำหรับ singletons เช่นNone
การตรวจสอบการอ้างอิงมีis
ความเหมาะสมมากขึ้นแม้ว่าทั้งสอง==
และis
จะทำงานได้ดี