Python! = การดำเนินการกับ“ ไม่ได้”


250

ในความคิดเห็นในคำถามนี้ฉันเห็นข้อความที่แนะนำให้ใช้

result is not None

VS

result != None

ฉันสงสัยว่าความแตกต่างคืออะไรและทำไมจึงมีข้อเสนอแนะถึงอีกข้อหนึ่ง



1
อืมมม ในขณะที่คำตอบของคำถามทั้งสองเป็นแนวคิดเดียวกันฉันคิดว่า upvotes และคำตอบโดยละเอียดมีส่วนช่วยในแนวคิดการทดสอบอัตลักษณ์และความเท่าเทียม
viksit

คำตอบ:


301

==เป็นทดสอบความเท่าเทียมกัน ตรวจสอบว่าด้านขวาและด้านซ้ายเป็นวัตถุเท่ากันหรือไม่ (ตามวิธี__eq__หรือ__cmp__วิธี)

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

คุณสามารถใช้is(และis not) สำหรับ singletons เช่นNoneที่คุณไม่สนใจเกี่ยวกับวัตถุที่อาจต้องการที่จะหลอกว่าเป็นหรือที่คุณต้องการที่จะป้องกันวัตถุที่จะหมดเมื่อมีการเปรียบเทียบกับNoneNone


3
ขอบคุณสำหรับคำตอบ - คุณช่วยอธิบายเกี่ยวกับสถานการณ์ที่วัตถุแตกได้หรือไม่เมื่อเปรียบเทียบกับไม่มี
viksit

3
@viksit Noneมีวิธีการเล็กน้อยและแทบไม่มีคุณสมบัติ หาก__eq__การทดสอบของคุณคาดว่าจะมีวิธีการหรือคุณสมบัติ def __eq__( self, other ): return self.size == other.size. ตัวอย่างเช่นถ้าจะทำลายที่จะเกิดขึ้นother None
S.Lott

36
วิธีที่ฉันชอบที่จะเข้าใจเรื่องนี้คือ ธisเป็นเหมือนของ ==Java ธ==เป็นเหมือนของ .equals()Java หลักสูตรนี้จะช่วยได้ก็ต่อเมื่อคุณรู้จัก Java
MatrixFrog

4
@ MatrixFrog: ใน PHP หรือ JavaScript เราจะบอกว่าisมันเป็น===(เท่ากันมาก) และในทางกลับกันis notก็เป็นเหมือน!==(ไม่เท่ากันทั้งหมด)
Orwellophile

3
เป็นis notผู้ประกอบการเดียวหรือเป็นเพียงกวนผลมาจากisภายในเช่นnot foo is bar?
ซาด Moosvi

150

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

คำนิยาม

เอกลักษณ์ของวัตถุ : เมื่อคุณสร้างวัตถุคุณสามารถกำหนดให้กับตัวแปร จากนั้นคุณสามารถกำหนดให้ตัวแปรอื่น เเละอีกอย่าง.

>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True

ในกรณีนี้cancel, closeและdismissทั้งหมดหมายถึงวัตถุเดียวกันในหน่วยความจำ คุณสร้างButtonวัตถุเดียวเท่านั้นและตัวแปรทั้งสามอ้างถึงวัตถุนี้ เรากล่าวว่าcancel, closeและdismissทั้งหมดให้ดูที่เหมือนวัตถุ; นั่นคือพวกเขาอ้างถึงวัตถุหนึ่งเดียว

ความเท่าเทียมกันของวัตถุ : เมื่อคุณเปรียบเทียบสองวัตถุที่คุณมักจะไม่สนใจว่ามันหมายถึงการที่แน่นอนวัตถุเดียวกันในหน่วยความจำ ด้วยความเสมอภาคของวัตถุคุณสามารถกำหนดกฎของคุณเองสำหรับการเปรียบเทียบวัตถุสองชนิด เมื่อคุณเขียนคุณจะได้เป็นหลักบอกว่าif a == b: if a.__eq__(b):สิ่งนี้ช่วยให้คุณกำหนด__eq__วิธีการaเพื่อให้คุณสามารถใช้ตรรกะการเปรียบเทียบของคุณเอง

เหตุผลสำหรับการเปรียบเทียบความเท่าเทียมกัน

เหตุผล:วัตถุสองรายการมีข้อมูลเหมือนกัน แต่ไม่เหมือนกัน (ไม่ใช่วัตถุเดียวกันในหน่วยความจำ) ตัวอย่าง:สตริง

>>> greeting = "It's a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True

หมายเหตุ: ฉันใช้สตริง Unicode ที่นี่เพราะ Python ฉลาดพอที่จะใช้สตริงปกติโดยไม่ต้องสร้างสตริงใหม่ในหน่วยความจำ

ที่นี่ผมมีสองสาย Unicode, และa bพวกเขามีเนื้อหาเดียวกันแน่นอน แต่พวกเขาไม่ใช่วัตถุเดียวกันในหน่วยความจำ อย่างไรก็ตามเมื่อเราเปรียบเทียบพวกเขาเราต้องการให้พวกเขาเปรียบเทียบเท่ากัน สิ่งที่เกิดขึ้นที่นี่คือวัตถุ Unicode ได้ใช้__eq__วิธีการ

class unicode(object):
    # ...

    def __eq__(self, other):
        if len(self) != len(other):
            return False

        for i, j in zip(self, other):
            if i != j:
                return False

        return True

หมายเหตุ: __eq__เปิดunicodeใช้งานอย่างมีประสิทธิภาพมากกว่านี้แน่นอน

เหตุผล:วัตถุสองชิ้นมีข้อมูลต่างกัน แต่ถือว่าเป็นวัตถุเดียวกันหากข้อมูลสำคัญบางอย่างเหมือนกัน ตัวอย่าง:ข้อมูลโมเดลส่วนใหญ่

>>> import datetime
>>> a = Monitor()
>>> a.make = "Dell"
>>> a.model = "E770s"
>>> a.owner = "Bob Jones"
>>> a.warranty_expiration = datetime.date(2030, 12, 31)
>>> b = Monitor()
>>> b.make = "Dell"
>>> b.model = "E770s"
>>> b.owner = "Sam Johnson"
>>> b.warranty_expiration = datetime.date(2005, 8, 22)
>>> a is b
False
>>> a == b
True

ที่นี่ผมมีสองหน้าจอ Dell, และa bพวกเขามียี่ห้อและรุ่นเดียวกัน อย่างไรก็ตามพวกเขาไม่มีข้อมูลเดียวกันหรือเป็นวัตถุเดียวกันในหน่วยความจำ อย่างไรก็ตามเมื่อเราเปรียบเทียบพวกเขาเราต้องการให้พวกเขาเปรียบเทียบเท่ากัน สิ่งที่เกิดขึ้นที่นี่คือวัตถุ Monitor ใช้__eq__วิธีการ

class Monitor(object):
    # ...

    def __eq__(self, other):
        return self.make == other.make and self.model == other.model

ตอบคำถามของคุณ

เมื่อเทียบกับใช้เสมอNone is notไม่มี singleton ใน Python มีอินสแตนซ์เดียวเท่านั้นในหน่วยความจำ

โดยการเปรียบเทียบตัวตนนี้สามารถทำได้อย่างรวดเร็ว Python ตรวจสอบว่าวัตถุที่คุณอ้างถึงมีที่อยู่หน่วยความจำเดียวกันกับวัตถุไม่มีทั่วโลกหรือไม่ - การเปรียบเทียบตัวเลขสองจำนวนอย่างรวดเร็วมาก

โดยการเปรียบเทียบความเท่าเทียมกัน Python จะต้องค้นหาว่าวัตถุของคุณมี__eq__วิธีการหรือไม่ หากไม่เป็นเช่นนั้นมันจะตรวจสอบซูเปอร์คลาสแต่ละรายการที่กำลังมองหา__eq__วิธีการ ถ้ามันพบหนึ่ง Python เรียกมันว่า นี้จะไม่ดีโดยเฉพาะอย่างยิ่งถ้าเป็นวิธีการที่ช้าและไม่ได้กลับทันทีเมื่อมันสังเกตเห็นว่าวัตถุอื่น__eq__None

คุณไม่ได้ใช้งาน__eq__หรือไม่? จากนั้นงูหลามอาจจะหา__eq__วิธีการobjectและใช้สิ่งนั้นแทน - เพียงแค่ตรวจสอบตัวตนของวัตถุอยู่แล้ว

เมื่อเปรียบเทียบกับสิ่งอื่น ๆ !=มากที่สุดในหลามคุณจะใช้


42

พิจารณาสิ่งต่อไปนี้:

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

c = Bad()
c is None # False, equivalent to id(c) == id(None)
c == None # True, equivalent to c.__eq__(None)

1
นี่เป็นตัวอย่างที่เป็นประโยชน์และเรียบง่ายมาก ขอบคุณ.
msarafzadeh

18

None.__eq__()เป็นซิงเกิลจึงเปรียบเทียบตัวตนมักจะทำงานในขณะที่วัตถุสามารถปลอมเปรียบเทียบความเท่าเทียมกันผ่านทาง


อ่าน่าสนใจ! ในสถานการณ์ใดที่เราอาจต้องการปลอมการเปรียบเทียบความเท่าเทียมกัน btw? ฉันเดาว่านี่มีผลกระทบด้านความปลอดภัยไม่ทางใดก็ทางหนึ่ง
viksit

1
มันไม่เกี่ยวกับความเสมอภาคแกล้งมันเป็นเรื่องของการใช้ความเท่าเทียมกัน มีเหตุผลมากมายที่ต้องการกำหนดวิธีเปรียบเทียบกับวัตถุอื่น
Thomas Wouters

1
ฉันจะบอกว่ามันมีความสับสนมากกว่านัยทางความปลอดภัย
Greg Hewgill

2
ฉันไม่ได้คิดหาเหตุผลที่จะสร้างความเท่าเทียมกันNoneแต่พฤติกรรมที่ไม่ถูกต้องNoneอาจเกิดขึ้นได้ซึ่งเป็นผลข้างเคียงของการใช้ความเท่าเทียมกับประเภทอื่น มันไม่ได้เกี่ยวข้องกับความปลอดภัยมากนักเพราะมันเป็นเพียงนัยที่ถูกต้อง
Ignacio Vazquez-Abrams

อ่าฉันก็เห็นอย่างนั้น ขอบคุณสำหรับการชี้แจง
viksit

10
>>> () คือ ()
จริง
>>> 1 คือ 1
จริง
>>> (1,) == (1,)
จริง
>>> (1,) คือ (1,)
เท็จ
>>> a = (1,)
>>> b = a
>>> a คือ b
จริง

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


4
งานเหล่านี้ส่วนใหญ่ทำงานโดยบังเอิญเท่านั้น ()และ1ไม่ได้เป็นโสดเดี่ยว
Mike Graham

1
ในการปรับใช้ CPython จำนวนเต็มขนาดเล็ก ( -NSMALLNEGINTS <= n <= NSMALLPOSINTS) และ tuples ที่ว่างเปล่าคือ singletons อันที่จริงมันไม่ได้เป็นเอกสารหรือรับประกัน แต่ก็ไม่น่าจะเปลี่ยนแปลง
ephemient

3
มันเป็นวิธีการใช้งาน แต่ไม่มีความหมายหรือมีประโยชน์หรือเพื่อการศึกษา
Mike Graham

1
และโดยเฉพาะอย่างยิ่ง CPython ไม่ได้เป็นเพียงการติดตั้ง Python เท่านั้น การใช้พฤติกรรมที่แตกต่างกันไปตามการใช้งานของ Python นั้นดูเหมือนจะเป็นความคิดที่แย่สำหรับฉัน
me_and
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.