มีความแตกต่างระหว่าง "foo is None" และ "foo == None" หรือไม่?


217

มีความแตกต่างระหว่าง:

if foo is None: pass

และ

if foo == None: pass

การประชุมที่ฉันเห็นในรหัส Python ส่วนใหญ่ (และรหัสที่ฉันเขียนด้วยตัวเอง) เป็นสิ่งแรก แต่เมื่อเร็ว ๆ นี้ฉันเจอโค้ดที่ใช้อันหลัง ไม่มีอินสแตนซ์ (และอินสแตนซ์เดียวเท่านั้น IIRC) ของ NoneType ดังนั้นมันจึงไม่สำคัญใช่ไหม มีสถานการณ์ใดบ้างที่อาจเกิดขึ้น?

คำตอบ:


253

isผลตอบแทนเสมอTrueถ้ามันเปรียบเทียบวัตถุเช่นเดียวกัน

ในขณะที่==ในที่สุดจะถูกกำหนดโดย__eq__()วิธีการ

กล่าวคือ


>>> class Foo(object):
       def __eq__(self, other):
           return True

>>> f = Foo()
>>> f == None
True
>>> f is None
False

51
คุณอาจต้องการเพิ่มว่า None เป็นซิงเกิลดังนั้น "None is None" จึงเป็น True เสมอ
E-satis

43
และคุณอาจต้องการเพิ่มว่าตัวisดำเนินการไม่สามารถกำหนดเองได้ (มีคลาสที่ผู้ใช้กำหนดเองมากเกินไป)
martineau

@study วิธีการ__eq__(self)เป็นวิธีbuiltin พิเศษที่กำหนดวิธีการ==จัดการเมื่อใช้กับวัตถุ Python ที่นี่เราได้เขียนทับมันเพื่อที่ว่าเมื่อ==มีการใช้งานกับออบเจ็กต์ประเภทFooมันจะส่งกลับจริง ไม่มีวิธีที่เทียบเท่าสำหรับisผู้ปฏิบัติงานดังนั้นพฤติกรรมของisไม่สามารถเปลี่ยนแปลงได้ในวิธีเดียวกัน
เบรนแดน

เป็นเพราะคำจำกัดความของคลาส foo ไม่มีตัวสร้างเช่นฟังก์ชันinitหรือไม่
เรียน

49

คุณอาจต้องการอ่านตัวตนของวัตถุและความเท่าเทียมกัน

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

และคำสั่ง '==' หมายถึงความเท่าเทียมกัน (ค่าเดียวกัน)


อืมฉันคิดว่าลิงก์ของคุณเปลี่ยนไปถ้าคุณไม่สนใจวิธีเรียกฟังก์ชั่นภายนอกจากไพ ธ อน
Pat

a=1;b=1;print(a is b) # Trueฉันก็พยายาม ความคิดใดว่าทำไมa is bกลายเป็นจริงแม้ว่าพวกเขาจะเป็นวัตถุที่แตกต่างกัน 2 (อยู่ในหน่วยความจำที่แตกต่างกัน)?
Johnny Chiu

24

คำเตือน:

if foo:
  # do something

คือไม่เหมือนกับ:

if x is not None:
  # do something

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


12

(ob1 is ob2) เท่ากับ (id(ob1) == id(ob2))


6
... แต่ (ob คือ ob2) นั้นเร็วกว่ามาก Timeit บอกว่า "(a คือ b)" คือ 0.0365 usec ต่อลูปและ "(id (a) == id (b))" คือ 0.153 usec ต่อลูป 4.2x เร็วขึ้น!
AKX

4
isรุ่นไม่จำเป็นต้องเรียกใช้ฟังก์ชันและไม่มีหลามล่ามค้นหาแอตทริบิวต์ที่ทุก ล่ามสามารถตอบได้ทันทีหาก ​​ob1 คืออันที่จริงแล้ว ob2
u0b34a0f6ae

17
ไม่มันไม่ {} is {}เป็นเท็จและid({}) == id({})สามารถ (และอยู่ใน CPython) จริง ดูstackoverflow.com/questions/3877230
Piotr Dobrogost

12

เหตุผลfoo is Noneคือวิธีที่ต้องการคือคุณอาจจัดการวัตถุที่กำหนดของตนเอง__eq__และกำหนดวัตถุให้เท่ากับ None ดังนั้นการใช้เสมอfoo is Noneถ้าคุณจำเป็นต้องดูว่าเป็น NoneInfact


8

ไม่มีความแตกต่างเพราะแน่นอนว่าวัตถุที่เหมือนกันจะเท่ากัน อย่างไรก็ตามPEP 8ระบุไว้อย่างชัดเจนว่าคุณควรใช้is:

การเปรียบเทียบกับซิงเกิลตันเช่นไม่มีควรทำด้วยเสมอหรือไม่ไม่ควรใช้ตัวดำเนินการที่เท่าเทียมกัน


7

isการทดสอบเพื่อระบุตัวตนไม่ใช่ความเท่าเทียมกัน สำหรับคำสั่งของคุณfoo is nonePython เพียงเปรียบเทียบที่อยู่หน่วยความจำของวัตถุ หมายความว่าคุณกำลังถามคำถาม "ฉันมีสองชื่อสำหรับวัตถุเดียวกันหรือไม่"

==ในทางตรงกันข้ามการทดสอบเพื่อความเท่าเทียมกันตามที่กำหนดโดย__eq__()วิธีการ มันไม่ได้เกี่ยวกับตัวตน

In [102]: x, y, z = 2, 2, 2.0

In [103]: id(x), id(y), id(z)
Out[103]: (38641984, 38641984, 48420880)

In [104]: x is y
Out[104]: True

In [105]: x == y
Out[105]: True

In [106]: x is z
Out[106]: False

In [107]: x == z
Out[107]: True

Noneเป็นผู้ประกอบการเดี่ยว ดังนั้นNone is Noneจะเป็นจริงเสมอ

In [101]: None is None
Out[101]: True

5

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

list1 = [1, 2, 3]
list2 = [1, 2, 3]
if list1==list2: print "Equal"
if list1 is list2: print "Same"

สิ่งนี้จะพิมพ์ "Equal" เนื่องจากรายการมีการดำเนินการเปรียบเทียบที่ไม่ใช่การส่งคืนข้อมูลเริ่มต้น


5

@ Jason :

ฉันแนะนำให้ใช้บางสิ่งบางอย่างมากขึ้นตามแนวของ

if foo:
    #foo isn't None
else:
    #foo is None

ฉันไม่ชอบใช้ "if foo:" เว้นแต่ foo จะแสดงค่าบูลีนอย่างแท้จริง (เช่น 0 หรือ 1) หาก foo เป็นสตริงหรือวัตถุหรืออย่างอื่น "ถ้า foo:" อาจใช้งานได้ แต่ดูเหมือนว่าทางลัดขี้เกียจสำหรับฉัน หากคุณกำลังตรวจสอบเพื่อดูว่า x เป็น None หรือไม่ให้พูดว่า "if x เป็น None:"


การตรวจสอบสตริง / รายการว่างด้วย "if var" เป็นวิธีที่ต้องการ การแปลงบูลีนได้รับการกำหนดไว้อย่างดีและเป็นรหัสที่น้อยกว่าซึ่งมีประสิทธิภาพดีกว่า ไม่มีเหตุผลที่ต้องทำ "if len (mylist) == 0" ตัวอย่างเช่น
truppo

ไม่ถูกต้อง. สมมติว่า foo = "" จากนั้นif fooจะคืนค่าเท็จและความคิดเห็น#foo is Noneไม่ถูกต้อง
blokeley

หมายเหตุสำหรับ downvoters - คำตอบของฉันคือการอ้างอิงคำตอบที่ถูกลบไปแล้วและไม่เห็นด้วย ถ้าคุณทำไม่ได้เช่นรหัสในคำตอบของฉันคุณจะต้องupvote :-)
Graeme Perrow

2

รายละเอียดเพิ่มเติมบางส่วน:

  1. isข้อจริงการตรวจสอบถ้าทั้งสองobjects เป็นที่ตั้งของหน่วยความจำเดียวกันหรือไม่ idคือว่าพวกเขาทั้งสองจุดไปยังตำแหน่งที่หน่วยความจำเดียวกันและมีความเหมือนกัน

  2. ผลที่ตามมาของ 1 isทำให้แน่ใจได้หรือไม่ว่าทั้งสอง lexically แสดงobjects มีคุณลักษณะที่เหมือนกัน (attribute-of-attribute ... ) หรือไม่

  3. instantiation ของชนิดดั้งเดิมชอบbool, int, string(ยกเว้นบาง) NoneTypeมีค่าเดียวกันมักจะอยู่ในที่ตั้งหน่วยความจำเดียวกัน

เช่น

>>> int(1) is int(1)
True
>>> str("abcd") is str("abcd")
True
>>> bool(1) is bool(2)
True
>>> bool(0) is bool(0)
True
>>> bool(0)
False
>>> bool(1)
True

และเนื่องจากNoneTypeสามารถมีอินสแตนซ์ของตัวเองได้เพียงตัวเดียวในตาราง "look-up" ของไพ ธ อนดังนั้นอดีตและอันหลังจึงเป็นรูปแบบการเขียนโปรแกรมของนักพัฒนาที่เขียนโค้ด (อาจจะเป็นความมั่นคง) มากกว่า เลือกหนึ่งตัวเลือก


2
ทุกคนที่อ่านสิ่งนี้: อย่าใช้some_string is "bar"เพื่อเปรียบเทียบสตริงที่เคย ไม่มีเหตุผลเดียวที่ยอมรับได้ที่จะทำเช่นนั้นและมันจะทำลายเมื่อคุณไม่คาดหวัง ความจริงที่ว่ามันใช้งานได้บ่อยเพียงเพราะ CPython รู้ว่ามันจะโง่ในการสร้างสองวัตถุที่ไม่เปลี่ยนรูปซึ่งมีเนื้อหาเหมือนกัน แต่มันสามารถเกิดขึ้นได้
ThiefMaster

@ThiefMaster คำตอบมีแนวโน้มที่จะเข้าใจผิดหรือไม่? แม้ว่าเมื่ออ่านอีกครั้งฉันไม่สามารถหาได้ (ด้วยการกล่าวถึง "ข้อยกเว้นบางอย่าง") คำสั่งของคุณมีไว้สำหรับสายอักขระเท่านั้นไม่ใช่intใช่ไหม?
นิ้วเลือดออก

ไม่จริง แต่เนื่องจากคุณมีตัวอย่างในคำตอบของคุณฉันคิดว่ามันเป็นความคิดที่ดีที่จะเตือนผู้ใช้ว่าเป็นความคิดที่ดีที่จะใช้มัน อาจเพิ่มบางอย่างเช่น "# cpython เจาะจง / ไม่รับประกัน" หลังบรรทัด ...
ThiefMaster

1

บทสรุปของ John Machin ที่Noneเป็น singleton เป็นข้อสรุปที่หนุนโดยรหัสนี้

>>> x = None
>>> y = None
>>> x == y
True
>>> x is y
True
>>> 

เนื่องจากNoneเป็นซิงเกิลตันx == Noneและx is Noneก็จะได้ผลเช่นเดียวกัน อย่างไรก็ตามในความเห็นของฉันx == Noneดีที่สุดแล้ว


2
ฉันไม่เห็นด้วยกับความเห็นในตอนท้ายของคำตอบนี้ เมื่อเปรียบเทียบกับไม่มีชัดเจนมักจะตั้งใจว่าวัตถุในคำถามเป็นNoneวัตถุ จากการเปรียบเทียบผู้หนึ่งไม่ค่อยเห็นว่าไม่มีใครใช้ในบริบทอื่นนอกจากจะคล้ายFalseกับค่าอื่น ๆ ที่เป็นจริง ในกรณีเหล่านั้นมันเป็นสำนวนที่น่าสนใจมากกว่าที่จะทำเช่นif x: pass
SingleNegationElimination

0
a is b # returns true if they a and b are true alias
a == b # returns true if they are true alias or they have values that are deemed equivalence 


a = [1,3,4]
b = a[:] #creating copy of list
a is b # if gives false
False
a == b # gives true
True
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.