अजगर! = ऑपरेशन बनाम "नहीं है"


250

इस सवाल पर एक टिप्पणी में , मैंने एक बयान देखा जिसका उपयोग करने की सिफारिश की गई थी

result is not None

बनाम

result != None

मैं सोच रहा था कि अंतर क्या है, और एक दूसरे पर सिफारिश क्यों की जा सकती है?



1
हम्म। जबकि दोनों प्रश्नों का उत्तर एक ही अवधारणा है, मुझे लगता है कि यहाँ उत्थान और विस्तृत उत्तर स्वतंत्र रूप से पहचान और समानता परीक्षण की अवधारणा में योगदान करते हैं।
23

जवाबों:


301

==एक समानता परीक्षण है । यह जाँचता है कि क्या दाहिने हाथ की ओर और बाएं हाथ की तरफ समान वस्तुएं हैं (उनके __eq__या __cmp__तरीकों के अनुसार )।

isएक पहचान परीक्षा है । यह जाँच करता है कि क्या दाहिने हाथ की तरफ और बाएं हाथ की तरफ एक ही वस्तु है। कोई कार्यप्रणाली नहीं की जाती है, ऑब्जेक्ट isऑपरेशन को प्रभावित नहीं कर सकते हैं ।

आप सिंगलटन के लिए is(और is not) का उपयोग करते हैं , जैसे None, जहाँ आप उन वस्तुओं के बारे में परवाह नहीं करते हैं जो होने का नाटक करना चाहते हैं Noneया जहाँ आप उन वस्तुओं की रक्षा करना चाहते हैं जिनके खिलाफ तुलना की जा रही है None


3
उत्तर के लिए धन्यवाद - क्या आप उन स्थितियों पर विस्तार से बता सकते हैं जब कोई वस्तु किसी की तुलना में टूट सकती है?
viksit

3
@viksit। Noneकुछ तरीके हैं और लगभग कोई विशेषता नहीं है। यदि आपके __eq__परीक्षण से विधि या विशेषता की उम्मीद है, तो यह टूट सकता है। def __eq__( self, other ): return self.size == other.size। उदाहरण के लिए, अगर otherऐसा होता है तो टूट जाएगा None
S.Lott

36
इसे समझने का मेरा पसंदीदा तरीका है: पायथन का isजावा की तरह है ==। अजगर का ==जावा की तरह है .equals()। बेशक यह केवल तभी मदद करता है जब आप जावा को जानते हैं।
मैट्रिक्स

4
@MatrixFrog: PHP में या जावास्क्रिप्ट हम कह सकते हैं कि isतरह है ===(बहुत बराबर), और इसके विपरीत is notकी तरह है !==(वास्तव में बराबर नहीं)।
Orwellophile

3
है is notएक भी ऑपरेटर या यह सिर्फ का परिणाम negating है isकी तरह आंतरिक रूप से not foo is bar?
असद मूसवी

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

नोट: मैं यहां यूनिकोड स्ट्रिंग्स का उपयोग करता हूं, क्योंकि पायथन काफी स्मार्ट है, जो नियमित स्ट्रिंग्स को फिर से उपयोग किए बिना मेमोरी में बनाता है।

यहाँ, मेरे पास दो यूनिकोड स्ट्रिंग्स हैं, aऔर b। उनके पास समान सामग्री है, लेकिन वे स्मृति में समान वस्तु नहीं हैं। हालांकि, जब हम उनकी तुलना करते हैं, तो हम चाहते हैं कि वे बराबर की तुलना करें। यहाँ क्या हो रहा है कि यूनिकोड ऑब्जेक्ट ने __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जाता है।

Rationale: दो वस्तुओं के अलग-अलग डेटा होते हैं, लेकिन यदि कुछ प्रमुख डेटा समान हों तो उन्हें एक ही वस्तु माना जाता है। उदाहरण: अधिकांश प्रकार के मॉडल डेटा

>>> 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

यहाँ, मेरे पास दो डेल मॉनिटर हैं, aऔर b। उनके पास एक ही मेक और मॉडल है। हालाँकि, उनके पास न तो समान डेटा है और न ही मेमोरी में समान ऑब्जेक्ट हैं। हालांकि, जब हम उनकी तुलना करते हैं, तो हम चाहते हैं कि वे बराबर की तुलना करें। यहाँ क्या हो रहा है कि मॉनिटर ऑब्जेक्ट ने __eq__विधि को लागू किया ।

class Monitor(object):
    # ...

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

आपके सवाल का जवाब दे रहा हूं

तुलना करते समय None, हमेशा उपयोग करें is not। पायथन में कोई भी एकल नहीं है - स्मृति में इसका केवल एक उदाहरण है।

पहचान की तुलना करके , यह बहुत जल्दी प्रदर्शन किया जा सकता है। पायथन यह जाँचता है कि जिस ऑब्जेक्ट का आप उल्लेख कर रहे हैं, उसमें वैसा ही मेमोरी एड्रेस है जैसा कि वैश्विक कोई भी वस्तु नहीं है - दो नंबरों की तुलना में बहुत तेज।

समानता की तुलना करके , पायथन को यह देखना होगा कि आपकी वस्तु में कोई __eq__विधि है या नहीं। यदि ऐसा नहीं होता है, तो यह एक __eq__विधि की तलाश में प्रत्येक सुपरक्लास की जांच करता है । यदि यह एक पाता है, तो पायथन इसे कहता है। यह विशेष रूप से बुरा है यदि __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
यह समानता को तोड़ने के बारे में नहीं है, यह समानता को लागू करने के बारे में है । यह परिभाषित करने के लिए बहुत सारे कारण हैं कि कोई वस्तु दूसरे की तुलना कैसे करती है।
थॉमस वाउटर्स

1
मैं कहूंगा कि यह सुरक्षा के निहितार्थ से अधिक भ्रम के निहितार्थ हैं।
ग्रेग हेविगिल

2
मैं एक कारण के खिलाफ नकली समानता के खिलाफ नहीं आया हूं None, लेकिन Noneअन्य प्रकार के खिलाफ समानता को लागू करने के दुष्प्रभाव के रूप में गलत व्यवहार हो सकता है। यह इतना सुरक्षा निहितार्थ नहीं है क्योंकि यह सिर्फ शुद्धता निहितार्थ है।
इग्नासियो वाज़केज़-अब्राम

आह, मैं देख रहा हूँ। स्पष्टीकरण के लिए Thx।
19

10
>>> () है ()
सच
>>> 1 1 है
सच
>>> (1,) == (1,)
सच
>>> (1,) है (1,)
असत्य
>>> ए = (1)
>>> बी = ए
>>> ए बी है
सच

कुछ ऑब्जेक्ट एकल हैं, और इस तरह isउनके साथ समतुल्य है ==। ज्यादातर नहीं हैं।


4
इनमें से अधिकांश केवल संयोग / कार्यान्वयन विवरण द्वारा काम करते हैं। ()और 1स्वाभाविक रूप से एकल नहीं हैं।
माइक ग्राहम

1
CPython कार्यान्वयन में, छोटे पूर्णांक ( -NSMALLNEGINTS <= n <= NSMALLPOSINTS) और खाली ट्यूपल एकल हैं । वास्तव में यह न तो प्रलेखित है और न ही इसकी गारंटी है, लेकिन यह बदलने की संभावना नहीं है।
इफिशिएंट

3
इसे कैसे लागू किया जाता है, यह सार्थक या उपयोगी या शैक्षिक नहीं है।
माइक ग्राहम

1
और विशेष रूप से, सीपीथॉन केवल पायथन कार्यान्वयन नहीं है। पायथन कार्यान्वयन में भिन्नता वाले व्यवहार पर निर्भर होना आमतौर पर मेरे लिए एक बुरा विचार होगा।
me_and
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.