มีความแตกต่างระหว่าง“ ==” และ“ เป็น” หรือไม่?


630

ฉันGoogle-Fuได้ล้มเหลวฉัน

ใน Python การทดสอบสองแบบต่อไปนี้มีความเท่าเทียมกันหรือไม่

n = 5
# Test one.
if n == 5:
    print 'Yay!'

# Test two.
if n is 5:
    print 'Yay!'

สิ่งนี้ถือเป็นจริงสำหรับวัตถุที่คุณจะเปรียบเทียบอินสแตนซ์ ( listพูด) หรือไม่?

ตกลงดังนั้นคำตอบของฉันแบบนี้:

L = []
L.append(1)
if L == [1]:
    print 'Yay!'
# Holds true, but...

if L is [1]:
    print 'Yay!'
# Doesn't.

ดังนั้น==ทดสอบค่าที่isทดสอบเพื่อดูว่าพวกเขาเป็นวัตถุเดียวกันหรือไม่

คำตอบ:


928

isจะกลับมาTrueหากตัวแปรสองตัวชี้ไปที่วัตถุเดียวกัน==ถ้าวัตถุที่อ้างถึงโดยตัวแปรนั้นเท่ากัน

>>> a = [1, 2, 3]
>>> b = a
>>> b is a 
True
>>> b == a
True

# Make a new copy of list `a` via the slice operator, 
# and assign it to variable `b`
>>> b = a[:] 
>>> b is a
False
>>> b == a
True

ในกรณีของคุณการทดสอบครั้งที่สองใช้งานได้เพราะ Python แคชวัตถุจำนวนเต็มขนาดเล็กซึ่งเป็นรายละเอียดการนำไปใช้ สำหรับจำนวนเต็มขนาดใหญ่สิ่งนี้จะไม่ทำงาน:

>>> 1000 is 10**3
False
>>> 1000 == 10**3
True

ตัวอักษรเดียวกันถือเป็นจริงสำหรับตัวอักษรสตริง:

>>> "a" is "a"
True
>>> "aa" is "a" * 2
True
>>> x = "a"
>>> "aa" is x * 2
False
>>> "aa" is intern(x*2)
True

โปรดดูคำถามนี้เช่นกัน


2
ฉันพบว่า: echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - fooผลลัพธ์: False True False.
ahuigo

คุณทำให้ฉันสูญเสียb = a[:]ส่วนการคัดลอกรายชื่อผู้ดำเนินการดังนั้นฉันได้แก้ไขคำตอบของคุณเพื่อให้มีความคิดเห็นที่นั่น ดูเหมือนว่าฉันเพิ่งถึงเกณฑ์ที่จะได้ไม่ต้องมีการแก้ไขของฉันได้รับการตรวจสอบก่อนที่พวกเขาจะนำไปใช้ดังนั้นหวังว่าคุณจะเท่ห์ โดยไม่คำนึงถึงนี่เป็นข้อมูลอ้างอิงที่มีประโยชน์สำหรับวิธีคัดลอกรายการที่ฉันเจอและต้องอ้างอิงเพื่อหาว่าคุณกำลังทำอะไร: stackoverflow.com/a/2612815/4561887
Gabriel Staples

วิธีที่จะแสดงให้เห็นถึงความแตกต่างก็คือโดยการเปรียบเทียบวัตถุที่แตกต่างกันซึ่งสามารถของหลักสูตรไม่เป็นวัตถุเดียวกัน ==แต่ยังคงเปรียบเทียบเท่ากับเมื่อใช้ ดังนั้น5.0สำหรับตัวอย่างเช่นเป็นค่าจุดลอยในขณะที่5เป็นจำนวนเต็ม แต่5.0 == 5จะยังคงกลับมาTrueเพราะพวกเขาเป็นตัวแทนของค่าเดียวกัน ในแง่ของประสิทธิภาพและการพิมพ์เป็ดisจะถูกทดสอบโดยล่ามเสมอโดยการเปรียบเทียบหน่วยความจำของตัวถูกดำเนินการในขณะที่==มันขึ้นอยู่กับวัตถุที่จะตัดสินใจว่ามันกำหนดตัวเองเท่ากับสิ่งอื่นใด
Bachsau

3
1000 is 10**3ตรวจสอบการจริงในหลาม 3.7 ตั้งแต่วันที่ 10 ** 3 intประเภทคือ แต่1000 is 1e3ประเมินการเท็จตั้งแต่ 1e3 floatเป็นประเภท
อาเหม็ดฟาซิห์

@AhmedFasih หรือไม่คือการดำเนินการเป็นความจริงขึ้นอยู่กับและขึ้นอยู่กับคอมไพเลอร์ก่อนการประเมินการแสดงออก1000 is 10**3 ประเมิน 10**3x=10; 1000 is x**3False
chepner

312

มีกฎง่ายๆของหัวแม่มือที่จะบอกคุณเมื่อใช้เป็นหรือ==is

  • ==สำหรับความเท่าเทียมกันค่า ใช้เมื่อคุณต้องการทราบว่าวัตถุสองรายการมีค่าเท่ากันหรือไม่
  • isสำหรับความเสมอภาคอ้างอิง ใช้เมื่อคุณต้องการทราบว่าการอ้างอิงสองรายการอ้างถึงวัตถุเดียวกันหรือไม่

โดยทั่วไปเมื่อคุณกำลังเปรียบเทียบกับสิ่งที่จะเป็นชนิดที่ง่ายคุณมักจะตรวจสอบความเสมอภาคคุ้มค่า==ดังนั้นคุณจึงควรใช้ ตัวอย่างเช่นความตั้งใจของตัวอย่างของคุณน่าจะตรวจสอบว่า x มีค่าเท่ากับ 2 ( ==) ไม่ใช่ว่าxอ้างอิงถึงวัตถุเดียวกันกับ 2 อย่างแท้จริงหรือไม่


สิ่งอื่นที่ควรทราบ: เนื่องจากวิธีการใช้งานการอ้างอิงของ CPython คุณจะได้รับผลลัพธ์ที่ไม่คาดคิดและไม่สอดคล้องกันหากคุณใช้isเพื่อเปรียบเทียบความเท่าเทียมกันของการอ้างอิงในจำนวนเต็มโดยไม่ได้ตั้งใจ:

>>> a = 500
>>> b = 500
>>> a == b
True
>>> a is b
False

นั่นเป็นสิ่งที่เราคาดหวังaและbมีค่าเท่ากัน แต่เป็นหน่วยงานที่แตกต่างกัน แต่แล้วเรื่องนี้ล่ะ

>>> c = 200
>>> d = 200
>>> c == d
True
>>> c is d
True

สิ่งนี้ไม่สอดคล้องกับผลลัพธ์ก่อนหน้า เกิดอะไรขึ้นที่นี่? มันจะเปิดใช้งานการอ้างอิงของวัตถุงูหลามแคชในช่วง -5 ..256 เป็นอินสแตนซ์เดี่ยวสำหรับเหตุผลด้านประสิทธิภาพ นี่คือตัวอย่างที่แสดงให้เห็นถึงสิ่งนี้:

>>> for i in range(250, 260): a = i; print "%i: %s" % (i, a is int(str(i)));
... 
250: True
251: True
252: True
253: True
254: True
255: True
256: True
257: False
258: False
259: False

นี่เป็นอีกเหตุผลที่ชัดเจนที่จะไม่ใช้is: พฤติกรรมจะถูกนำไปใช้กับการใช้งานเมื่อคุณใช้มันอย่างผิด ๆ เพื่อความเท่าเทียมกันของคุณค่า


ด้วยการไปถึงตัวอย่างแรกของa=500และb=500เพียงแค่อยากจะชี้ให้เห็นว่าถ้าคุณตั้งค่าaและbไปยัง interger ระหว่าง [-5 256] ผลตอบแทนจริงa is b Trueข้อมูลเพิ่มเติมได้ที่นี่: stackoverflow.com/q/306313/7571052
AsheKetchum

1
@AsheKetchum ใช่แล้วโปรดทราบว่าฉันเขียนว่า "มันเป็นการใช้งานการอ้างอิงของ Python แคชวัตถุจำนวนเต็มในช่วง -5 ..256 เป็นอินสแตนซ์ซิงเกิลสำหรับเหตุผลด้านประสิทธิภาพ"
John Feminella

34

==กำหนดว่าค่าเท่ากันในขณะที่isพิจารณาว่าพวกเขาเป็นวัตถุเดียวกันที่แน่นอน


32

มีความแตกต่างระหว่าง==และ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เพื่อเปรียบเทียบจำนวนเต็ม


"ห้ามใช้เลย" จะเป็นกฎที่ดีเช่นกัน สำนวนis Noneเป็นข้อยกเว้น แต่ที่กล่าวว่า== Noneทำงานเกินไป ...
Jean-François Fabre

@ Jean-FrançoisFabreข้อยกเว้นอื่น: เอกสารราชการดูเหมือนว่าจะแนะนำให้ใช้isสำหรับการเปรียบเทียบEnums
อาเธอร์

@Arthur ฉันได้เพิ่มรายการกรณีการใช้งาน ...
Aaron Hall

19

ความแตกต่างระหว่างisและ==คืออะไร

==และisมีการเปรียบเทียบที่แตกต่างกัน! อย่างที่คนอื่นพูดไปแล้ว:

  • == เปรียบเทียบค่าของวัตถุ
  • is เปรียบเทียบการอ้างอิงของวัตถุ

ในชื่อไพ ธ อนอ้างถึงวัตถุตัวอย่างเช่นในกรณีนี้value1และvalue2อ้างถึงintอินสแตนซ์ที่เก็บค่า1000:

value1 = 1000
value2 = value1

ป้อนคำอธิบายรูปภาพที่นี่

เพราะvalue2หมายถึงวัตถุเดียวกันisและ==จะให้True:

>>> value1 == value2
True
>>> value1 is value2
True

ในตัวอย่างต่อไปนี้ชื่อvalue1และvalue2อ้างถึงintอินสแตนซ์ที่แตกต่างกันแม้ว่าทั้งสองจะเก็บจำนวนเต็มเดียวกัน:

>>> value1 = 1000
>>> value2 = 1000

ป้อนคำอธิบายรูปภาพที่นี่

เพราะค่าเดียวกัน (จำนวนเต็ม) จะถูกเก็บไว้==จะเป็นTrueที่ว่าทำไมมันมักจะเรียกว่า "การเปรียบเทียบค่า" อย่างไรก็ตามisจะกลับมาFalseเพราะสิ่งเหล่านี้เป็นวัตถุที่แตกต่างกัน:

>>> value1 == value2
True
>>> value1 is value2
False

จะใช้เมื่อใด

โดยทั่วไปisการเปรียบเทียบเร็วกว่ามาก นั่นเป็นสาเหตุที่ CPython แคช (หรืออาจนำมาใช้ใหม่อาจเป็นคำที่ดีกว่า) วัตถุบางอย่างเช่นจำนวนเต็มขนาดเล็ก, สตริงบางอย่าง, แต่สิ่งนี้ควรได้รับการปฏิบัติตามรายละเอียดการใช้งานที่อาจเปลี่ยนแปลงได้

คุณควรใช้isเมื่อคุณ:

  • ต้องการตรวจสอบว่าวัตถุสองรายการเป็นวัตถุเดียวกันจริง ๆ หรือไม่ (ไม่ใช่แค่ "คุณค่า" เดียวกัน) ตัวอย่างหนึ่งอาจเป็นได้ถ้าคุณใช้วัตถุซิงเกิลตันเป็นค่าคงที่
  • ต้องการเปรียบเทียบค่ากับงูหลามอย่างต่อเนื่อง ค่าคงที่ใน Python คือ:

    • None
    • True1
    • False1
    • NotImplemented
    • Ellipsis
    • __debug__
    • คลาส (เช่นint is intหรือint is float)
    • อาจมีค่าคงที่เพิ่มเติมในโมดูลในตัวหรือโมดูลของบุคคลที่สาม ตัวอย่างnp.ma.maskedจากโมดูล NumPy)

ในกรณีอื่น ๆ คุณควรใช้==เพื่อตรวจสอบความเท่าเทียมกัน

ฉันสามารถปรับแต่งพฤติกรรมได้หรือไม่?

มีแง่มุมบางอย่างที่จะเป็น==ที่ยังไม่ได้รับการกล่าวถึงอยู่แล้วในคำตอบอื่น ๆ : มันเป็นส่วนหนึ่งของงูเหลือม "รูปแบบข้อมูล" นั่นหมายความว่าพฤติกรรมของมันสามารถปรับแต่งได้โดยใช้__eq__วิธีการ ตัวอย่างเช่น:

class MyClass(object):
    def __init__(self, val):
        self._value = val

    def __eq__(self, other):
        print('__eq__ method called')
        try:
            return self._value == other._value
        except AttributeError:
            raise TypeError('Cannot compare {0} to objects of type {1}'
                            .format(type(self), type(other)))

นี่เป็นเพียงตัวอย่างเทียมเพื่อแสดงให้เห็นว่าวิธีการที่เรียกว่าจริง ๆ :

>>> MyClass(10) == MyClass(10)
__eq__ method called
True

โปรดทราบว่าโดยค่าเริ่มต้น (หากไม่มีการใช้งานอื่นที่__eq__สามารถพบได้ในคลาสหรือซูเปอร์คลาส) __eq__ใช้is:

class AClass(object):
    def __init__(self, value):
        self._value = value

>>> a = AClass(10)
>>> b = AClass(10)
>>> a == b
False
>>> a == a

ดังนั้นจึงเป็นเรื่องสำคัญที่จะต้องนำไปใช้__eq__ถ้าคุณต้องการ "มากกว่า" มากกว่าแค่การเปรียบเทียบอ้างอิงสำหรับคลาสที่กำหนดเอง!

ในขณะที่คุณไม่สามารถปรับแต่งการisตรวจสอบ มันก็จะเปรียบเทียบเพียงถ้าคุณมีการอ้างอิงเดียวกัน

การเปรียบเทียบเหล่านี้จะส่งคืนบูลีนเสมอหรือไม่

เพราะ__eq__สามารถนำมาใช้ใหม่หรือแทนที่ก็ไม่ได้ จำกัด อยู่ที่การกลับมาหรือTrue Falseมันสามารถส่งคืนสิ่งใดก็ได้ (แต่ในกรณีส่วนใหญ่ควรส่งคืนบูลีน!)

ตัวอย่างเช่นกับ NumPy arrays ==จะส่งคืนอาร์เรย์:

>>> import numpy as np
>>> np.arange(10) == 2
array([False, False,  True, False, False, False, False, False, False, False], dtype=bool)

แต่isเช็คจะกลับมาเสมอTrueหรือFalse!


1 ดังที่ Aaron Hall กล่าวไว้ในความคิดเห็น:

โดยทั่วไปแล้วคุณไม่ควรทำอะไรis Trueหรือis Falseตรวจสอบเพราะปกติจะใช้ "การตรวจสอบ" เหล่านี้ในบริบทที่แปลงสภาพโดยปริยายเป็นบูลีน (ตัวอย่างเช่นในifคำสั่ง) ดังนั้นการทำการis Trueเปรียบเทียบและการโยนแบบบูลีนโดยปริยายกำลังทำงานมากกว่าการทำแบบบูลีน - และคุณ จำกัด ตัวเองเป็นบูลีน (ซึ่งไม่ถือว่าเป็นไพ ธ อน)

เช่นเดียวกับ PEP8 กล่าวถึง:

อย่าเปรียบเทียบค่าบูลีนไปTrueหรือใช้False==

Yes:   if greeting:
No:    if greeting == True:
Worse: if greeting is True:

2
ฉันจะต้องไม่เห็นด้วยกับการยืนยันของคุณเพื่อเปรียบเทียบ "คงที่" กับis- ชื่อที่ชี้ไปที่ booleans ควรจะตรวจสอบกับบริบทแบบบูล - เหมือนหรือif __debug__: if not __debug__:คุณไม่ควรทำif __debug__ is True:หรือif __debug__ == True:- เพิ่มเติมค่าคงที่เป็นเพียงค่าความหมายคงที่ไม่ใช่แบบซิงเกิลดังนั้นการตรวจสอบด้วยisในกรณีนั้นจะไม่ถูกต้องทางความหมาย ฉันขอท้าให้คุณค้นหาแหล่งข้อมูลเพื่อสนับสนุนการยืนยันของคุณ - ฉันไม่คิดว่าคุณจะพบแหล่งที่มา
Aaron Hall

@AaronHall อะไรที่ทำให้คุณคิดว่าค่าคงที่ไม่ใช่แบบซิงเกิล? หมายเหตุว่ามีเพียงNone, True, Falseและ__debug__เป็นสิ่งที่คุณจะเรียก "ค่าความหมายอย่างต่อเนื่อง" เพราะพวกเขาไม่สามารถมีพระราชเสาวนีย์ แต่ทั้งหมดเป็นแบบซิงเกิล
MSeifert

อ่านPEP 8 - Ctrl-F แล้วมองหาคำว่า "แย่ลง" - ถ้าคุณไม่กล้า
Aaron Hall

@AaronHall ในบางกรณีคุณต้องการis Trueหรือif Falseตรวจสอบ (แต่ใช่สิ่งเหล่านี้ค่อนข้างหายาก - แต่ถ้าคุณทำคุณสามารถทำได้โดยใช้is) นั่นเป็นสาเหตุที่แม้แต่ CPython ก็ใช้งานได้ในบางครั้ง (ตัวอย่างเช่นที่นี่หรือที่นี่ )
MSeifert

19

พวกเขามีความแตกต่างอย่างสิ้นเชิง isตรวจสอบตัวตนของวัตถุในขณะที่==ตรวจสอบความเท่าเทียมกัน (ความคิดที่ขึ้นอยู่กับตัวถูกดำเนินการทั้งสองประเภท)

เป็นเรื่องบังเอิญที่โชคดีที่isดูเหมือนว่า "" จะทำงานอย่างถูกต้องกับจำนวนเต็มเล็กน้อย (เช่น 5 == 4 + 1) นั่นเป็นเพราะCPython เพิ่มประสิทธิภาพการจัดเก็บข้อมูลของจำนวนเต็มในช่วง (-5 ถึง 256) โดยทำให้พวกเขา singletons พฤติกรรมนี้ขึ้นอยู่กับการนำไปปฏิบัติโดยสมบูรณ์และไม่รับประกันว่าจะได้รับการสงวนไว้ภายใต้การดำเนินการเปลี่ยนแปลงเล็กน้อยทุกประเภท

ตัวอย่างเช่น Python 3.5 สร้างสตริงแบบสั้น ๆ แบบซิงเกิล แต่การแบ่งออกเป็นส่วน ๆ ทำให้การทำงานนี้:

>>> "foo" + "bar" == "foobar"
True
>>> "foo" + "bar" is "foobar"
True
>>> "foo"[:] + "bar" == "foobar"
True
>>> "foo"[:] + "bar" is "foobar"
False

10

https://docs.python.org/library/stdtypes.html#comparisons

isการทดสอบเพื่อทดสอบเอกลักษณ์ ==เพื่อความเท่าเทียมกัน

ค่าจำนวนเต็ม (เล็ก) แต่ละค่าจะถูกแมปกับค่าเดียวดังนั้นทุก ๆ 3 จะเหมือนกันและเท่ากัน นี่เป็นรายละเอียดการนำไปใช้งานไม่ใช่ส่วนหนึ่งของข้อมูลจำเพาะทางภาษา


6

คำตอบของคุณถูกต้อง isประกอบการเปรียบเทียบตัวตนของวัตถุสอง ==ประกอบการเปรียบเทียบค่าของวัตถุสอง

เอกลักษณ์ของวัตถุจะไม่เปลี่ยนแปลงเมื่อมีการสร้างขึ้น คุณอาจคิดว่ามันเป็นที่อยู่ของวัตถุในหน่วยความจำ

คุณสามารถควบคุมพฤติกรรมการเปรียบเทียบค่าวัตถุโดยการกำหนด__cmp__วิธีการหรือการเปรียบเทียบที่อุดมไปด้วย__eq__วิธีการเช่น


4

มีลักษณะที่คำถามกองล้นงูใหญ่“คือ” ผู้ประกอบการจะทำงานโดยไม่คาดคิดกับจำนวนเต็ม

สิ่งที่สำคัญที่สุดก็คือการisตรวจสอบเพื่อดูว่าเป็นวัตถุเดียวกันหรือไม่ "" ไม่เท่ากับกัน (ตัวเลขด้านล่าง 256 เป็นกรณีพิเศษ) ""


3

สรุปisตรวจสอบว่าทั้งสองอ้างอิงชี้ไปที่วัตถุเดียวกันหรือไม่ ==ตรวจสอบว่าวัตถุทั้งสองมีค่าเท่ากันหรือไม่

a=[1,2,3]
b=a        #a and b point to the same object
c=list(a)  #c points to different object 

if a==b:
    print('#')   #output:#
if a is b:
    print('##')  #output:## 
if a==c:
    print('###') #output:## 
if a is c:
    print('####') #no output as c and a point to different object 

2

ตามที่ John Feminella พูดส่วนใหญ่คุณจะใช้ == และ! = เนื่องจากวัตถุประสงค์ของคุณคือการเปรียบเทียบค่า ฉันต้องการจัดหมวดหมู่สิ่งที่คุณจะทำในช่วงเวลาที่เหลือ:

มีเพียงหนึ่งเดียวของอินสแตนซ์ของ NoneType คือ None เป็นซิงเกิลตัน ดังนั้นfoo == Noneและfoo is Noneหมายความว่าเหมือนกัน อย่างไรก็ตามในisการทดสอบได้เร็วขึ้นและการประชุม Pythonic foo is Noneคือการใช้งาน

ถ้าคุณกำลังทำวิปัสสนาบางส่วนหรือสิเกี่ยวกับการเก็บขยะหรือการตรวจสอบไม่ว่าจะเป็นสตริงที่สร้างขึ้นเองของคุณฝึกงานแกดเจ็ตเป็นคนที่ทำงานหรือเยี่ยงแล้วคุณอาจจะมีการใช้งานในกรณีมีfoobar

ความจริงและเท็จนอกจากนี้ยังมี (ตอนนี้) singletons แต่ไม่มีการใช้งานในกรณีและกรณีที่ไม่มีการใช้งานสำหรับfoo == Truefoo is True


2

ส่วนใหญ่ตอบไปแล้ว เช่นเดียวกับบันทึกเพิ่มเติม (ตามความเข้าใจและการทดลองของฉัน แต่ไม่ได้มาจากแหล่งเอกสาร)

== ถ้าวัตถุที่อ้างถึงโดยตัวแปรมีค่าเท่ากัน

จากคำตอบข้างต้นควรอ่านว่า

== ถ้าวัตถุที่อ้างอิงโดยตัวแปรมีค่าเท่ากันและวัตถุที่เป็นประเภท / คลาสเดียวกัน

. ฉันมาถึงข้อสรุปนี้จากการทดสอบด้านล่าง:

list1 = [1,2,3,4]
tuple1 = (1,2,3,4)

print(list1)
print(tuple1)
print(id(list1))
print(id(tuple1))

print(list1 == tuple1)
print(list1 is tuple1)

นี่คือเนื้อหาของรายการและ tuple เหมือนกัน แต่ประเภท / คลาสแตกต่างกัน


2

Python ที่แตกต่างระหว่างคือและเท่ากับ (==)

ตัวดำเนินการ is อาจดูเหมือนเหมือนกับตัวดำเนินการความเสมอภาค แต่ไม่เหมือนกัน

is คือการตรวจสอบว่าตัวแปรทั้งสองชี้ไปที่วัตถุเดียวกันหรือไม่ในขณะที่เครื่องหมาย == จะตรวจสอบว่าค่าสำหรับตัวแปรสองตัวนั้นเหมือนกันหรือไม่

ดังนั้นหากตัวดำเนินการ is ส่งคืน True ดังนั้นความเสมอภาคนั้นเป็นจริงแน่นอน แต่ตรงกันข้ามอาจเป็นจริงหรือไม่ก็ได้

นี่คือตัวอย่างที่แสดงให้เห็นถึงความคล้ายคลึงกันและความแตกต่าง

>>> a = b = [1,2,3]
>>> c = [1,2,3]
>>> a == b
True
>>> a == c
True
>>> a is b
True
>>> a is c
False
>>> a = [1,2,3]
>>> b = [1,2]
>>> a == b
False
>>> a is b
False
>>> del a[2]
>>> a == b
True
>>> a is b
False
Tip: Avoid using is operator for immutable types such as strings and numbers, the result is unpredictable.

1
โปรดใช้เครื่องหมายคำพูดบล็อกสำหรับข้อความที่คุณยกมาจากแหล่งอื่น ณ จุดนี้คุณต้องระบุที่มา (ดูstackoverflow.com/help/referencing ) หากนี่เป็นข้อความของคุณเองโปรดลบเครื่องหมายคำพูดบล็อกออก
Martijn Pieters

0

ในขณะที่คนอื่น ๆ ในโพสต์นี้ตอบคำถามโดยละเอียดฉันจะเน้นเป็นส่วนใหญ่การเปรียบเทียบระหว่างisและ== สำหรับสตริงที่สามารถให้ผลลัพธ์ที่แตกต่างกันและฉันจะกระตุ้นให้โปรแกรมเมอร์ใช้อย่างระมัดระวัง

สำหรับการเปรียบเทียบสตริงให้ใช้==แทนis:

str = 'hello'
if (str is 'hello'):
    print ('str is hello')
if (str == 'hello'):
    print ('str == hello')

ออก:

str is hello
str == hello

แต่ในตัวอย่างด้านล่าง==และisจะได้ผลลัพธ์ที่แตกต่าง:

str = 'hello sam'
    if (str is 'hello sam'):
        print ('str is hello sam')
    if (str == 'hello sam'):
        print ('str == hello sam')

ออก:

str == hello sam

สรุป:

ใช้isอย่างระมัดระวังเพื่อเปรียบเทียบระหว่างสตริง


ทำไม "คือ" "ทำงานเช่นนั้นสำหรับสตริงที่มีช่องว่าง?
Akash Gupta

ตามคำตอบก่อนหน้า: ดูเหมือนว่า python ทำการแคชกับจำนวนเต็มขนาดเล็กและสตริงซึ่งหมายความว่ามันใช้การอ้างอิงวัตถุเดียวกันสำหรับการเกิดขึ้นของสตริง 'hello' ใน snapshot ของรหัสนี้ในขณะที่มันไม่ preform แคชสำหรับ 'hello sam' ค่อนข้างใหญ่กว่า 'hello' (นั่นคือจัดการการอ้างอิงที่แตกต่างกันของสตริง 'Hello sam' และนั่นเป็นสาเหตุที่ตัวดำเนินการ 'is' ส่งคืนค่าเท็จในตัวอย่างต่อมา) โปรดแก้ไขฉันหากฉันผิด
Rida Shamasneh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.