क्यों `अगर कोई नहीं .__ eq __ (" ए ")` सच का मूल्यांकन करने लगते हैं (लेकिन काफी नहीं)?


146

यदि आप पायथन 3.7 में निम्नलिखित कथन को निष्पादित करते हैं, तो यह (मेरे परीक्षण से) प्रिंट होगा b:

if None.__eq__("a"):
    print("b")

हालाँकि, का None.__eq__("a")मूल्यांकन करता है NotImplemented

स्वाभाविक रूप से, का "a".__eq__("a")मूल्यांकन करता है True, और "b".__eq__("a")करने के लिए मूल्यांकन करता है False

किसी फ़ंक्शन के रिटर्न मान का परीक्षण करते समय मुझे शुरू में पता चला, लेकिन दूसरे मामले में कुछ भी वापस नहीं किया - इसलिए, फ़ंक्शन वापस आ गया None

यहाँ क्या चल रहा है?

जवाबों:


178

यह इस बात का एक बड़ा उदाहरण है कि __dunder__तरीकों का सीधे उपयोग क्यों नहीं किया जाना चाहिए क्योंकि वे अपने समकक्ष ऑपरेटरों के लिए अक्सर उपयुक्त प्रतिस्थापन नहीं होते हैं; आपको ==समानता की तुलना के लिए ऑपरेटर का उपयोग करना चाहिए , या इस विशेष मामले में, जांच करते समय None, उपयोग करें is(अधिक जानकारी के लिए उत्तर के नीचे की ओर छोड़ें)।

तुमने कर दिया

None.__eq__('a')
# NotImplemented

NotImplementedतुलना के प्रकार भिन्न होने के बाद से जो रिटर्न मिलता है । एक और उदाहरण पर विचार करें, जहां इस प्रकार की दो वस्तुओं की तुलना इस प्रकार की जा रही है, जैसे कि 1और 'a'। करना (1).__eq__('a')भी सही नहीं है, और वापस आ जाएगा NotImplemented। समानता के लिए इन दो मूल्यों की तुलना करने का सही तरीका होगा

1 == 'a'
# False

यहां क्या होता है

  1. सबसे पहले, (1).__eq__('a')कोशिश की जाती है, जो वापस आती है NotImplemented। यह इंगित करता है कि ऑपरेशन समर्थित नहीं है, इसलिए
  2. 'a'.__eq__(1)कहा जाता है, जो भी लौटाता है NotImplemented। इसलिए,
  3. वस्तुओं के साथ ऐसा व्यवहार किया जाता है जैसे कि वे एक जैसी न हों, और Falseवापस आ जाएं।

यह कैसे होता है, यह बताने के लिए कुछ कस्टम कक्षाओं का उपयोग करके एक अच्छा सा MCVE दिया गया है:

class A:
    def __eq__(self, other):
        print('A.__eq__')
        return NotImplemented

class B:
    def __eq__(self, other):
        print('B.__eq__')
        return NotImplemented

class C:
    def __eq__(self, other):
        print('C.__eq__')
        return True

a = A()
b = B()
c = C()

print(a == b)
# A.__eq__
# B.__eq__
# False

print(a == c)
# A.__eq__
# C.__eq__
# True

print(c == a)
# C.__eq__
# True

बेशक, यह स्पष्ट नहीं करता है कि ऑपरेशन सही क्यों है। ऐसा इसलिए है क्योंकि NotImplementedवास्तव में एक सत्य मूल्य है:

bool(None.__eq__("a"))
# True

के समान,

bool(NotImplemented)
# True

सत्य और असत्य माना जाने वाले मूल्यों के बारे में अधिक जानकारी के लिए, सत्य मान परीक्षण पर डॉक्स अनुभाग और साथ ही इस उत्तर को देखें । यहां यह ध्यान देने योग्य है कि है NotImplementedtruthy है, लेकिन यह किया गया है एक अलग कहानी वर्ग एक परिभाषित किया था होगा __bool__या __len__विधि कि लौट आए Falseया 0क्रमशः।


यदि आप ==ऑपरेटर के कार्यात्मक समकक्ष चाहते हैं , तो उपयोग करें operator.eq:

import operator
operator.eq(1, 'a')
# False

हालाँकि, जैसा कि पहले उल्लेख किया गया है, इस विशिष्ट परिदृश्य के लिए , जहाँ आप Noneउपयोग कर रहे हैं is:

var = 'a'
var is None
# False

var2 = None
var2 is None
# True

इसके समतुल्य कार्यात्मक उपयोग कर रहा है operator.is_:

operator.is_(var2, None)
# True

Noneएक विशेष वस्तु है, और किसी भी समय स्मृति में केवल 1 संस्करण मौजूद है। IOW, यह NoneTypeवर्ग का एकमात्र सिंगलटन है (लेकिन एक ही वस्तु में किसी भी संख्या में संदर्भ हो सकते हैं)। PEP8 दिशा निर्देशों इस स्पष्ट हो जाता है:

Noneहमेशा की तरह एकल ऑपरेटरों के साथ तुलना की जानी चाहिए isया is notकभी नहीं, समानता ऑपरेटरों।

सारांश में, जैसे एकल के लिए None, के साथ एक संदर्भ जांच isअधिक उपयुक्त है, हालांकि दोनों ==और isबस ठीक काम करेगा।


33

आप जो परिणाम देख रहे हैं, वह उसी तथ्य के कारण है

None.__eq__("a") # evaluates to NotImplemented

का मूल्यांकन NotImplemented, और NotImplementedसत्य मूल्य होने के लिए प्रलेखित है True:

https://docs.python.org/3/library/constants.html

विशेष मूल्य जो बाइनरी विशेष तरीके से किया जाना चाहिये (जैसे __eq__(), __lt__(), __add__(), __rsub__(), आदि) संकेत मिलता है कि आपरेशन अन्य प्रकार के संबंध में लागू नहीं है; यथा-स्थान द्विआधारी विशेष तरीकों (जैसे द्वारा लौटाया जा सकता है __imul__(), __iand__()एक ही उद्देश्य के लिए, आदि)। इसका सत्य मूल्य सत्य है।

यदि आप __eq()__विधि को केवल उपयोग करने के बजाय मैन्युअल रूप से कॉल करते हैं ==, तो आपको उस संभावना से निपटने के लिए तैयार रहने की आवश्यकता है जो वह वापस आ सकती है NotImplementedऔर यह कि उसका सत्य मूल्य सत्य है।


16

जैसा कि आप पहले से ही None.__eq__("a")मूल्यांकन कर चुके हैं, NotImplementedहालांकि यदि आप कुछ पसंद करते हैं

if NotImplemented:
    print("Yes")
else:
    print("No")

परिणाम है

हाँ

इसका मतलब है कि इसका सत्य मूल्य NotImplemented true

प्रश्न का परिणाम स्पष्ट है:

None.__eq__(something) पैदावार NotImplemented

और bool(NotImplemented)True का मूल्यांकन करता है

तो if None.__eq__("a")सदा सत्य है


1

क्यों?

यह एक NotImplemented, हाँ:

>>> None.__eq__('a')
NotImplemented
>>> 

लेकिन अगर आप इसे देखें:

>>> bool(NotImplemented)
True
>>> 

NotImplementedवास्तव में एक सत्य मूल्य है, इसलिए वह लौटता है b, जो कुछ भी Trueपास होगा, कुछ भी जो Falseनहीं है।

इसे कैसे हल करें?

आपको यह देखना होगा कि क्या यह Trueइतना संदिग्ध है, जैसा कि आप देखते हैं:

>>> NotImplemented == True
False
>>> 

तो आप ऐसा करेंगे:

>>> if None.__eq__('a') == True:
    print('b')


>>> 

और जैसा कि आप देखते हैं, यह कुछ भी नहीं लौटाएगा।


1
सबसे स्पष्ट रूप से स्पष्ट जवाब - v सार्थक जोड़ - धन्यवाद
scharfmn

1
:) "सार्थक इसके अलावा" मैं जो कहना चाह रहा था उस पर बहुत कब्जा नहीं करता (जैसा कि आप देखते हैं) - शायद "
उत्तेजित

@scharfmn हाँ? मैं यह जानने के लिए उत्सुक हूं कि आपको क्या लगता है कि यह उत्तर जोड़ता है कि पहले से ही कवर नहीं किया गया है।
cs95

किसी भी तरह से दृश्य / उत्तर चीजें यहाँ स्पष्टता जोड़ती हैं - पूर्ण डेमो
scharfmn

@scharfmn ... जो स्वीकार किए गए जवाब में भी संकेत हैं कि संकेतों को हटा दिया गया है। क्या आपने पूरी तरह से उखाड़ फेंका क्योंकि टर्मिनल प्रॉमिस को आलसी तरीके से छोड़ दिया गया है?
cs95
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.