पाइथन नहीं तो == बनाम अगर! =


183

कोड की इन दो पंक्तियों के बीच क्या अंतर है:

if not x == 'val':

तथा

if x != 'val':

क्या एक दूसरे से अधिक कुशल है?

क्या इसका उपयोग करना बेहतर होगा

if x == 'val':
    pass
else:

101
बेहतर यह है कि आप पढ़ सकते हैं, मुझे संदेह है कि आपके कार्यक्रम की अड़चन यहाँ होगी
थॉमस अय्यूब

1
यह सवाल मुझे "एक्स नॉट इन लिस्ट" और "
समथिंग

5
@SomethingSomething वे अनौपचारिक रूप से व्याख्या कर रहे हैं।
जोंशरशेप

4
मेरे उपरोक्त टिप्पणी के लिए @SomethingSomething संदर्भ: stackoverflow.com/q/8738388/3001761
jonrsharpe

1
@SomethingSomething यह उन लोगों के लिए भी समान है; सिंटैक्स की व्याख्या कैसे की जाती है, इससे कोई फर्क नहीं पड़ता कि दो ऑपरेंड क्या हैं।
जोनरशेप

जवाबों:


229

disदो संस्करणों के लिए उत्पन्न बाइटकोड को देखने के लिए उपयोग करना :

not ==

  4           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               2 (==)
              9 UNARY_NOT           
             10 RETURN_VALUE   

!=

  4           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               3 (!=)
              9 RETURN_VALUE   

उत्तरार्द्ध में कम ऑपरेशन हैं, और इसलिए थोड़ा अधिक कुशल होने की संभावना है।


यह बताया गया commments में (धन्यवाद, @Quincunx ) है कि जहां आप if foo != barबनाम if not foo == barआपरेशन की संख्या बिल्कुल वैसा ही है, यह सिर्फ है कि COMPARE_OPपरिवर्तन और POP_JUMP_IF_TRUEपर स्विच करता है POP_JUMP_IF_FALSE:

not ==:

  2           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               2 (==)
              9 POP_JUMP_IF_TRUE        16

!=

  2           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               3 (!=)
              9 POP_JUMP_IF_FALSE       16

इस मामले में, जब तक कि प्रत्येक तुलना के लिए आवश्यक कार्य की मात्रा में अंतर नहीं होता, यह संभावना नहीं है कि आप किसी भी प्रदर्शन अंतर को देखेंगे।


हालाँकि, ध्यान दें कि दो संस्करण हमेशा तार्किक रूप से समान नहीं होंगे , क्योंकि यह प्रश्न में वस्तुओं के कार्यान्वयन के लिए __eq__और उन पर निर्भर करेगा __ne__। प्रति डाटा मॉडल प्रलेखन :

तुलना ऑपरेटरों के बीच कोई निहित संबंध नहीं हैं। सत्य का x==yअर्थ यह नहीं है कि x!=yवह असत्य है।

उदाहरण के लिए:

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


>>> not Dummy() == Dummy()
False
>>> Dummy() != Dummy()
True

अंत में, और शायद सबसे महत्वपूर्ण बात: सामान्य, जहां दो में कर रहे हैं तार्किक समान, x != yकी तुलना में अधिक पठनीय हैnot x == y


29
व्यवहार में, कोई भी वर्ग जिसके पास __eq__असंगत है __ne__वह फ्लैट-आउट टूटा हुआ है।
केविन

8
कृपया ध्यान दें कि यह हमेशा सच नहीं होता है जिसमें not x == yएक और निर्देश है। जब मैंने कोड को एक में डाल दिया if, तो यह पता चला कि उन दोनों के पास समान निर्देश हैं, बस एक था POP_JUMP_IF_TRUEऔर दूसरे POP_JUMP_IF_FALSE(जो कि उनके बीच एकमात्र अंतर था, एक अलग उपयोग करने के अलावा COMPARE_OP)। जब मैंने ifएस के बिना कोड संकलित किया , तो मुझे वही मिला जो आपको मिला था।
जस्टिन

1
एक अन्य उदाहरण है जहां ==और !=परस्पर अनन्य नहीं हैं SQL जैसी कार्यान्वयन से जुड़े है nullमान। एसक्यूएल में nullवापस नहीं करता है trueकरने के लिए !=किसी अन्य मूल्य की तुलना में है, इसलिए एसक्यूएल इंटरफेस के अजगर कार्यान्वयन भी एक ही मुद्दा हो सकता है।
जो

मैं चाहने लगा हूं कि मैंने बीच के संभावित अंतर का उल्लेख नहीं किया है not ==और !=यह मेरे उत्तर का सबसे दिलचस्प हिस्सा लगता है! मुझे नहीं लगता कि यह उस स्थान पर है, जहां पर, क्यों और कब यह समझ में आता है - उदाहरण के लिए देखें कि पायथन के पास __ne__सिर्फ एक ऑपरेटर की विधि क्यों है __eq__?
जोंशरशेप

29

@jonrsharpe का एक उत्कृष्ट विवरण है कि क्या हो रहा है। मैंने सोचा था कि मैं समय में अंतर दिखाऊंगा जब प्रत्येक 3 विकल्प 10,000,000 बार चल रहा हो (दिखाने के लिए थोड़ा अंतर के लिए पर्याप्त)।

उपयोग किया गया कोड:

def a(x):
    if x != 'val':
        pass


def b(x):
    if not x == 'val':
        pass


def c(x):
    if x == 'val':
        pass
    else:
        pass


x = 1
for i in range(10000000):
    a(x)
    b(x)
    c(x)

और cProfile प्रोफाइलर परिणाम:

यहां छवि विवरण दर्ज करें

इसलिए हम देख सकते हैं कि if not x == 'val':और के बीच ~ 0.7% का एक बहुत मिनट का अंतर है if x != 'val':। इनमें से, if x != 'val':सबसे तेज है।

हालांकि, सबसे आश्चर्यजनक रूप से, हम यह देख सकते हैं

if x == 'val':
        pass
    else:

वास्तव में सबसे तेज है, और if x != 'val':~ 0.3% से धड़कता है। यह बहुत पठनीय नहीं है, लेकिन मुझे लगता है कि यदि आप एक नगण्य प्रदर्शन सुधार चाहते हैं, तो कोई इस मार्ग से नीचे जा सकता है।


31
मुझे आशा है कि हर कोई इस जानकारी पर कार्रवाई नहीं करना जानता है ! 0.3% सुधार के लिए अपठनीय परिवर्तन करना - या यहां तक ​​कि 10% सुधार - शायद ही कभी एक अच्छा विचार है, और इस तरह के सुधार से बहुत अधिक संभावना है (और अच्छे तरीके से नहीं : पायथन रनटाइम में बहुत मामूली बदलाव किसी भी लाभ को खत्म या उलट सकता है।
मालवोलियो

1
@ मालवोलियो इसके अलावा, पायथन के विभिन्न कार्यान्वयन हैं।
सेस टिम्मरमैन

6

पहले एक पायथन में आवश्यक से अधिक एक ऑपरेशन को अंजाम देना होता है (इसके बजाए सिर्फ इसकी जाँच नहीं करना है कि क्या यह सच नहीं है कि यह बराबर है, इस प्रकार एक और ऑपरेशन करना है)। एक निष्पादन से अंतर बताना असंभव होगा, लेकिन अगर कई बार चलाया जाता है, तो दूसरा अधिक कुशल होगा। कुल मिलाकर मैं दूसरे का उपयोग करूंगा, लेकिन गणितीय रूप से वे समान हैं


5
>>> from dis import dis
>>> dis(compile('not 10 == 20', '', 'exec'))
  1           0 LOAD_CONST               0 (10)
              3 LOAD_CONST               1 (20)
              6 COMPARE_OP               2 (==)
              9 UNARY_NOT
             10 POP_TOP
             11 LOAD_CONST               2 (None)
             14 RETURN_VALUE
>>> dis(compile('10 != 20', '', 'exec'))
  1           0 LOAD_CONST               0 (10)
              3 LOAD_CONST               1 (20)
              6 COMPARE_OP               3 (!=)
              9 POP_TOP
             10 LOAD_CONST               2 (None)
             13 RETURN_VALUE

यहां आप देख सकते हैं कि not x == yएक से अधिक निर्देश हैं x != y। इसलिए अधिकांश मामलों में प्रदर्शन अंतर बहुत कम होगा जब तक आप लाखों तुलनाएं नहीं कर रहे हैं और तब भी यह अड़चन का कारण नहीं होगा।


5

एक अतिरिक्त ध्यान दें, क्योंकि अन्य उत्तरों ने आपके प्रश्न का उत्तर अधिकतर सही ढंग से दिया है, यह है कि यदि कोई वर्ग केवल परिभाषित करता है __eq__()और नहीं __ne__(), तो आपका COMPARE_OP (!=)भाग जाएगा __eq__()और इसे नकार देगा। उस समय, आपका तीसरा विकल्प थोड़ा और अधिक कुशल होने की संभावना है, लेकिन केवल तभी विचार किया जाना चाहिए यदि आपने गति की आवश्यकता की है, क्योंकि इसे जल्दी से समझना मुश्किल है।


3

यह आपके पढ़ने के तरीके के बारे में है। notऑपरेटर गतिशील है, इसलिए आप इसे लागू करने में सक्षम हैं

if not x == 'val':

लेकिन !=एक ऑपरेटर के रूप में एक बेहतर संदर्भ में पढ़ा जा सकता है जो इसके विपरीत ==करता है।


3
आपका क्या मतलब है " notऑपरेटर गतिशील है" ?
जोंशरशेप

1
@jonrsharpe मुझे लगता है कि वह इसका मतलब है कि "नहीं x" कॉल करेंगे एक्स .__ bool __ () [अजगर 3 - अजगर 2 का उपयोग करता है अशून्य ] और परिणाम वापस लौटने (देखें docs.python.org/3/reference/datamodel.html#object। __bool__ )
jdferreira

1

मैं ऊपर अपनी पठनीयता टिप्पणी पर विस्तार करना चाहता हूं।

फिर, मैं पूरी तरह से अन्य (प्रदर्शन-महत्वहीन) चिंताओं को पढ़ने से सहमत हूं।

मैं जो इंगित करना चाहूंगा वह यह है कि मस्तिष्क "सकारात्मक" की तुलना में तेजी से "सकारात्मक" की व्याख्या करता है। उदाहरण के लिए, "स्टॉप" बनाम "मत जाओ" (शब्दों की संख्या में अंतर के कारण एक घटिया उदाहरण)।

इसलिए एक विकल्प दिया:

if a == b
    (do this)
else
    (do that)

कार्यात्मक-समतुल्य के लिए बेहतर है:

if a != b
    (do that)
else
    (do this)

कम पठनीयता / समझने की क्षमता अधिक कीड़े की ओर ले जाती है। शायद शुरुआती कोडिंग में नहीं, लेकिन रखरखाव के रूप में (आपके जितना स्मार्ट नहीं!) में परिवर्तन ...


1
मस्तिष्क "सकारात्मक" की तुलना में तेजी से "नकारात्मक" करता है यह अनुभव से है या आपने इस बारे में अध्ययन पढ़ा है? मैं सिर्फ इसलिए पूछ रहा हूं क्योंकि यह (ऐसा करो) या (ऐसा करो) कोड पर निर्भर करता है, मुझे समझने के लिए एक! = B आसान लगता है।
lafferc
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.