มีความแตกต่างระหว่าง==
และis
ใน Python หรือไม่?
ใช่พวกเขามีความแตกต่างที่สำคัญมาก
==
: ตรวจสอบความเท่าเทียมกัน - ความหมายคือวัตถุที่เทียบเท่ากัน (ซึ่งไม่จำเป็นต้องเป็นวัตถุเดียวกัน) จะทดสอบเท่ากัน ตามเอกสารระบุว่า :
ตัวดำเนินการ <,>, ==,> =, <= และ! = เปรียบเทียบค่าของวัตถุสองชนิด
is
: ตรวจสอบตัวตน - ความหมายคือวัตถุ (ตามที่เก็บไว้ในหน่วยความจำ) เป็นวัตถุ อีกครั้งเอกสารกล่าวว่า :
โอเปอเรเตอร์is
และis not
ทดสอบการระบุตัวตนของวัตถุ: x is y
เป็นจริงหากและถ้าx
และy
เป็นวัตถุเดียวกันเท่านั้น เอกลักษณ์ของวัตถุถูกกำหนดโดยใช้id()
ฟังก์ชัน x is not y
ให้ค่าความจริงผกผัน
ดังนั้นการตรวจสอบเอกลักษณ์จึงเหมือนกับการตรวจสอบความเสมอภาคของ ID ของวัตถุ นั่นคือ,
a is b
เหมือนกับ:
id(a) == id(b)
โดยที่id
ฟังก์ชันบิวอินจะส่งกลับจำนวนเต็มว่า "รับประกันว่าจะไม่ซ้ำกันระหว่างวัตถุที่มีอยู่พร้อมกัน" (ดูhelp(id)
) และที่ไหนa
และb
เป็นวัตถุใด ๆ
ทิศทางการใช้งานอื่น ๆ
คุณควรใช้การเปรียบเทียบเหล่านี้สำหรับความหมายของพวกเขา ใช้is
เพื่อตรวจสอบตัวตนและ==
เพื่อตรวจสอบความเท่าเทียมกัน
ดังนั้นโดยทั่วไปเราใช้is
เพื่อตรวจสอบตัวตน โดยปกติจะมีประโยชน์เมื่อเรากำลังตรวจสอบวัตถุที่ควรมีอยู่เพียงครั้งเดียวในหน่วยความจำซึ่งเรียกว่า "ซิงเกิล" ในเอกสารประกอบ
ใช้กรณีis
รวมถึง:
None
- ค่า enum (เมื่อใช้ Enums จากโมดูล enum)
- โมดูลมักจะ
- มักจะเป็นวัตถุคลาสที่เกิดจากคำจำกัดความของชั้นเรียน
- ฟังก์ชั่นมักจะเป็นวัตถุที่เกิดจากการกำหนดฟังก์ชั่น
- สิ่งอื่นใดที่ควรมีอยู่ครั้งเดียวในหน่วยความจำ (singletons ทั้งหมดโดยทั่วไป)
- วัตถุเฉพาะที่คุณต้องการด้วยตัวตน
กรณีการใช้งานปกติสำหรับ==
รวมถึง:
- ตัวเลขรวมถึงจำนวนเต็ม
- เงื่อนไข
- รายการ
- ชุด
- พจนานุกรม
- วัตถุที่ไม่แน่นอนที่กำหนดเอง
- วัตถุที่ไม่เปลี่ยนรูปอื่น ๆ ในตัวส่วนใหญ่
กรณีการใช้งานทั่วไปอีกครั้ง==
เป็นวัตถุที่คุณต้องการอาจจะไม่เหมือนกันวัตถุ แต่มันอาจจะเป็นเทียบเท่าหนึ่ง
PEP 8 ทิศทาง
PEP 8 คู่มือสไตล์ Python อย่างเป็นทางการสำหรับไลบรารี่มาตรฐานยังกล่าวถึงกรณีใช้งานสองกรณีสำหรับis
:
การเปรียบเทียบกับแบบซิงเกิลNone
ควรทำด้วยเสมอis
หรือ
is not
ไม่ควรใช้ตัวดำเนินการที่เท่าเทียมกัน
นอกจากนี้ระวังการเขียนif x
เมื่อคุณหมายถึงif x is not None
- เช่นเมื่อทดสอบว่าตัวแปรหรืออาร์กิวเมนต์ที่ค่าเริ่มต้นNone
ถูกตั้งค่าเป็นค่าอื่น ค่าอื่นอาจมีประเภท (เช่นภาชนะ) ที่อาจเป็นเท็จในบริบทบูลีน!
การอนุมานความเสมอภาคจากตัวตน
ถ้าis
เป็นจริงความเท่าเทียมกันมักจะอนุมานได้ - อย่างมีเหตุผลถ้าวัตถุเป็นของตัวเองมันก็ควรทดสอบว่าเทียบเท่ากับตัวมันเอง
ในกรณีส่วนใหญ่ตรรกะนี้เป็นจริง แต่ขึ้นอยู่กับการดำเนินการตาม__eq__
วิธีพิเศษ อย่างที่เอกสารพูด
พฤติกรรมเริ่มต้นสำหรับการเปรียบเทียบความเท่าเทียมกัน ( ==
และ!=
) ขึ้นอยู่กับตัวตนของวัตถุ ดังนั้นการเปรียบเทียบความเท่าเทียมกันของอินสแตนซ์ที่มีตัวตนเดียวกันส่งผลให้เกิดความเท่าเทียมกันและการเปรียบเทียบความเท่าเทียมกันของอินสแตนซ์ที่มีตัวตนที่แตกต่างกันส่งผลให้เกิดความไม่เท่าเทียมกัน แรงจูงใจสำหรับพฤติกรรมเริ่มต้นนี้คือความปรารถนาที่วัตถุทั้งหมดควรสะท้อนกลับ (เช่น x คือ y หมายถึง x == y)
และเพื่อประโยชน์ของความมั่นคงแนะนำ:
การเปรียบเทียบความเท่าเทียมควรสะท้อนกลับ ในคำอื่น ๆ วัตถุที่เหมือนกันควรเปรียบเทียบเท่ากัน:
x is y
หมายถึง x == y
เราจะเห็นว่านี่เป็นพฤติกรรมเริ่มต้นสำหรับวัตถุที่กำหนดเอง:
>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)
contrapositive ก็มักจะเป็นจริงเช่นกัน - หากการทดสอบบางสิ่งไม่เท่ากันคุณสามารถอนุมานได้ว่าสิ่งนั้นไม่ใช่วัตถุเดียวกัน
เนื่องจากสามารถทำการทดสอบเพื่อความเท่าเทียมกันได้การอนุมานนี้จึงไม่ถือเป็นจริงสำหรับทุกประเภท
ข้อยกเว้น
ข้อยกเว้นที่น่าสังเกตคือnan
- มันจะทำการทดสอบเสมอไม่เท่ากับตัวมัน
>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan # !!!!!
False
การตรวจสอบข้อมูลประจำตัวอาจเป็นการตรวจสอบที่รวดเร็วกว่าการตรวจสอบความเท่าเทียมกัน (ซึ่งอาจต้องมีการตรวจสอบสมาชิกซ้ำ)
แต่ไม่สามารถทดแทนเพื่อความเท่าเทียมกันซึ่งคุณอาจพบวัตถุมากกว่าหนึ่งรายการที่เทียบเท่า
โปรดทราบว่าการเปรียบเทียบความเท่าเทียมกันของรายการและสิ่งอันดับจะถือว่าความเป็นตัวตนของวัตถุเท่ากัน (เพราะเป็นการตรวจสอบที่รวดเร็ว) สิ่งนี้สามารถสร้างความขัดแย้งได้ถ้าลอจิกนั้นไม่สอดคล้องกันซึ่งมีไว้สำหรับnan
:
>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True
เรื่องเตือน:
คำถามกำลังพยายามใช้is
เพื่อเปรียบเทียบจำนวนเต็ม คุณไม่ควรสมมติว่าอินสแตนซ์ของจำนวนเต็มเป็นอินสแตนซ์เดียวกับที่ได้รับจากการอ้างอิงอื่น เรื่องนี้อธิบายว่าทำไม
ผู้แสดงความคิดเห็นมีรหัสที่อาศัยความจริงที่ว่าจำนวนเต็มขนาดเล็ก (-5 ถึง 256 รวม) เป็น singletons ใน Python แทนที่จะตรวจสอบความเท่าเทียมกัน
ว้าวนี่อาจนำไปสู่ข้อบกพร่องที่ร้ายกาจ ฉันมีรหัสบางอย่างที่ตรวจสอบว่า a คือ b ซึ่งทำงานได้ตามที่ฉันต้องการเพราะ a และ b มักเป็นจำนวนน้อย ข้อผิดพลาดเกิดขึ้นในวันนี้หลังจากผ่านไปหกเดือนในการผลิตเพราะในที่สุด a และ b นั้นมีขนาดใหญ่พอที่จะไม่ถูกแคช - gwg
มันทำงานในการพัฒนา มันอาจจะผ่านการไม่เห็นด้วย
และมันใช้งานได้จริง - จนกระทั่งโค้ดตรวจสอบว่าเป็นจำนวนเต็มที่มากกว่า 256 ณ จุดนั้นมันล้มเหลวในการผลิต
นี่คือความล้มเหลวในการผลิตที่อาจติดอยู่ในการตรวจสอบโค้ดหรืออาจเป็นกับตัวตรวจสอบสไตล์
ผมขอเน้น: อย่าใช้is
เพื่อเปรียบเทียบจำนวนเต็ม
echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - foo
ผลลัพธ์:False True False
.