Why does `if None.__eq__(“a”)` evaluate to True?












137















If you execute the following statement in Python 3.7, it will (from my testing) print b:



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


However, None.__eq__("a") evaluates to NotImplemented.



Naturally, "a".__eq__("a") evaluates to True, and "b".__eq__("a") evaluates to False.



I initially discovered this when testing the return value of a function, but didn't return anything in the second case -- so, the function returned None.



What's going on here?










share|improve this question




















  • 2





    The title was wrong. The result is not True, as you noted yourself. It is a "truthy value", i.e. a value x such that bool(x) is True.

    – Bakuriu
    Jan 2 at 9:23











  • The title is fine. if [truthy value] evaluates to true.

    – coldspeed
    Jan 2 at 10:35











  • Besides, changing the title to `why does .. evaluate to a truthy value" implies you know what "truthy" and "falsey" means, and by extension would know the cause of the issue rendering the question moot. Let's not go down that rabbit hole :)

    – coldspeed
    Jan 22 at 10:14


















137















If you execute the following statement in Python 3.7, it will (from my testing) print b:



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


However, None.__eq__("a") evaluates to NotImplemented.



Naturally, "a".__eq__("a") evaluates to True, and "b".__eq__("a") evaluates to False.



I initially discovered this when testing the return value of a function, but didn't return anything in the second case -- so, the function returned None.



What's going on here?










share|improve this question




















  • 2





    The title was wrong. The result is not True, as you noted yourself. It is a "truthy value", i.e. a value x such that bool(x) is True.

    – Bakuriu
    Jan 2 at 9:23











  • The title is fine. if [truthy value] evaluates to true.

    – coldspeed
    Jan 2 at 10:35











  • Besides, changing the title to `why does .. evaluate to a truthy value" implies you know what "truthy" and "falsey" means, and by extension would know the cause of the issue rendering the question moot. Let's not go down that rabbit hole :)

    – coldspeed
    Jan 22 at 10:14
















137












137








137


23






If you execute the following statement in Python 3.7, it will (from my testing) print b:



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


However, None.__eq__("a") evaluates to NotImplemented.



Naturally, "a".__eq__("a") evaluates to True, and "b".__eq__("a") evaluates to False.



I initially discovered this when testing the return value of a function, but didn't return anything in the second case -- so, the function returned None.



What's going on here?










share|improve this question
















If you execute the following statement in Python 3.7, it will (from my testing) print b:



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


However, None.__eq__("a") evaluates to NotImplemented.



Naturally, "a".__eq__("a") evaluates to True, and "b".__eq__("a") evaluates to False.



I initially discovered this when testing the return value of a function, but didn't return anything in the second case -- so, the function returned None.



What's going on here?







python python-3.x string equivalence






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 2 at 10:34









coldspeed

133k23143225




133k23143225










asked Dec 31 '18 at 6:03









The AI ArchitectThe AI Architect

8892918




8892918








  • 2





    The title was wrong. The result is not True, as you noted yourself. It is a "truthy value", i.e. a value x such that bool(x) is True.

    – Bakuriu
    Jan 2 at 9:23











  • The title is fine. if [truthy value] evaluates to true.

    – coldspeed
    Jan 2 at 10:35











  • Besides, changing the title to `why does .. evaluate to a truthy value" implies you know what "truthy" and "falsey" means, and by extension would know the cause of the issue rendering the question moot. Let's not go down that rabbit hole :)

    – coldspeed
    Jan 22 at 10:14
















  • 2





    The title was wrong. The result is not True, as you noted yourself. It is a "truthy value", i.e. a value x such that bool(x) is True.

    – Bakuriu
    Jan 2 at 9:23











  • The title is fine. if [truthy value] evaluates to true.

    – coldspeed
    Jan 2 at 10:35











  • Besides, changing the title to `why does .. evaluate to a truthy value" implies you know what "truthy" and "falsey" means, and by extension would know the cause of the issue rendering the question moot. Let's not go down that rabbit hole :)

    – coldspeed
    Jan 22 at 10:14










2




2





The title was wrong. The result is not True, as you noted yourself. It is a "truthy value", i.e. a value x such that bool(x) is True.

– Bakuriu
Jan 2 at 9:23





The title was wrong. The result is not True, as you noted yourself. It is a "truthy value", i.e. a value x such that bool(x) is True.

– Bakuriu
Jan 2 at 9:23













The title is fine. if [truthy value] evaluates to true.

– coldspeed
Jan 2 at 10:35





The title is fine. if [truthy value] evaluates to true.

– coldspeed
Jan 2 at 10:35













Besides, changing the title to `why does .. evaluate to a truthy value" implies you know what "truthy" and "falsey" means, and by extension would know the cause of the issue rendering the question moot. Let's not go down that rabbit hole :)

– coldspeed
Jan 22 at 10:14







Besides, changing the title to `why does .. evaluate to a truthy value" implies you know what "truthy" and "falsey" means, and by extension would know the cause of the issue rendering the question moot. Let's not go down that rabbit hole :)

– coldspeed
Jan 22 at 10:14














4 Answers
4






active

oldest

votes


















166














This is a great example of why the __dunder__ methods should not be used directly as they are quite often not appropriate replacements for their equivalent operators; you should use the == operator instead for equality comparisons, or in this special case, when checking for None, use is (skip to the bottom of the answer for more information).



You've done



None.__eq__('a')
# NotImplemented


Which returns NotImplemented since the types being compared are different. Consider another example where two objects with different types are being compared in this fashion, such as 1 and 'a'. Doing (1).__eq__('a') is also not correct, and will return NotImplemented. The right way to compare these two values for equality would be



1 == 'a'
# False


What happens here is




  1. First, (1).__eq__('a') is tried, which returns NotImplemented. This indicates that the operation is not supported, so


  2. 'a'.__eq__(1) is called, which also returns the same NotImplemented. So,

  3. The objects are treated as if they are not the same, and False is returned.


Here's a nice little MCVE using some custom classes to illustrate how this happens:



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




Of course, that doesn't explain why the operation returns true. This is because NotImplemented is actually a truthy value:



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


Same as,



bool(NotImplemented)
# True


For more information on what values are considered truthy and falsey, see the docs section on Truth Value Testing, as well as this answer. It is worth noting here that NotImplemented is truthy, but it would have been a different story had the class defined a __bool__ or __len__ method that returned False or 0 respectively.





If you want the functional equivalent of the == operator, use operator.eq:



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


However, as mentioned earlier, for this specific scenario, where you are checking for None, use is:



var = 'a'
var is None
# False

var2 = None
var2 is None
# True


The functional equivalent of this is using operator.is_:



operator.is_(var2, None)
# True


None is a special object, and only 1 version exists in memory at any point of time. IOW, it is the sole singleton of the NoneType class (but the same object may have any number of references). The PEP8 guidelines make this explicit:




Comparisons to singletons like None should always be done with is or
is not, never the equality operators.




In summary, for singletons like None, a reference check with is is more appropriate, although both == and is will work just fine.






share|improve this answer





















  • 6





    Nevertheless, I think it'd be worthy to note that None should be checked with is None, not ==, operator.eq or .__eq__

    – DeepSpace
    Dec 31 '18 at 11:58








  • 4





    @DeepSpace Thanks for that, I have reworked the answer so as to explain why == is better in any general situation, and why is is more appropriate for this specific one, quoting PEP8 at the bottom. Thanks for the comment!

    – coldspeed
    Dec 31 '18 at 12:12






  • 2





    It's worth mentioning (since it wasn't obvious to me) that NotImplemented belongs to the class <class 'NotImplementedType'>. Here, bool(NotImplemented) evaluates to True, because of some combination of: __bool__ undefined (most likely) / __bool__ explicitly defined to be Tue / __len__ doesn't give 0.

    – jpp
    Dec 31 '18 at 13:29








  • 2





    @jpp I don't think that class defines either __bool__ or __len__. I believe the spec dictates that the object is truthy unless __bool__ or __len__ say otherwise. You can read more here (that link is also included in the answer :-)).

    – coldspeed
    Dec 31 '18 at 14:51








  • 2





    @coldspeed, Yup, I thought so. But it's worth clarification because new users may fall into the trap that 'a' == 'NotImplemented' should return False ! While the underlying reason is you aren't working with strings but a NotImplementedType object.

    – jpp
    Dec 31 '18 at 14:54





















32














The result you are seeing is caused by that fact that



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


evaluates to NotImplemented, and NotImplemented's truth value is documented to be True:



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




Special value which should be returned by the binary special methods (e.g. eq(), lt(), add(), rsub(), etc.) to indicate that the operation is not implemented with respect to the other type; may be returned by the in-place binary special methods (e.g. imul(), iand(), etc.) for the same purpose. Its truth value is true.




If you call the __eq()__ method manually rather than just using ==, you need to be prepared to deal with the possibility it may return NotImplemented and that its truth value is true.






share|improve this answer

































    16














    As you already figured None.__eq__("a") evaluates to NotImplemented however if you try something like



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


    the result is




    yes




    this mean that the truth value of NotImplemented true



    Therefor the outcome of the question is obvious:



    None.__eq__(something) yields NotImplemented



    And bool(NotImplemented) evaluates to True



    So if None.__eq__("a") is always True






    share|improve this answer

































      1














      Why?



      It returns a NotImplemented, yeah:



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


      But if you look at this:



      >>> bool(NotImplemented)
      True
      >>>


      NotImplemented is actually a truthy value, so that's why it returns b, anything that is True will pass, anything that is False wouldn't.



      How to solve it?



      You have to check if it is True, so be more suspicious, as you see:



      >>> NotImplemented == True
      False
      >>>


      So you would do:



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


      >>>


      And as you see, it wouldn't return anything.






      share|improve this answer



















      • 1





        most visually clear answer - v worthwhile addition - thank you

        – scharfmn
        Jan 29 at 19:27











      • @scharfmn Lol, happy that i posted a good answer :-)

        – U9-Forward
        Jan 30 at 0:14






      • 1





        :) “worthwhile addition” doesn’t quite capture what I was trying to say (as you obv see) - maybe “belated excellence” is what I wanted - cheers

        – scharfmn
        Jan 30 at 0:25






      • 1





        @scharfmn Yeah, i was bored, so answer, lol :-) ...

        – U9-Forward
        Jan 30 at 0:26











      • @scharfmn yes? I'm curious to know what you think this answer adds that hasn't already been covered before.

        – coldspeed
        Feb 1 at 22:43











      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53984116%2fwhy-does-if-none-eq-a-evaluate-to-true%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      166














      This is a great example of why the __dunder__ methods should not be used directly as they are quite often not appropriate replacements for their equivalent operators; you should use the == operator instead for equality comparisons, or in this special case, when checking for None, use is (skip to the bottom of the answer for more information).



      You've done



      None.__eq__('a')
      # NotImplemented


      Which returns NotImplemented since the types being compared are different. Consider another example where two objects with different types are being compared in this fashion, such as 1 and 'a'. Doing (1).__eq__('a') is also not correct, and will return NotImplemented. The right way to compare these two values for equality would be



      1 == 'a'
      # False


      What happens here is




      1. First, (1).__eq__('a') is tried, which returns NotImplemented. This indicates that the operation is not supported, so


      2. 'a'.__eq__(1) is called, which also returns the same NotImplemented. So,

      3. The objects are treated as if they are not the same, and False is returned.


      Here's a nice little MCVE using some custom classes to illustrate how this happens:



      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




      Of course, that doesn't explain why the operation returns true. This is because NotImplemented is actually a truthy value:



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


      Same as,



      bool(NotImplemented)
      # True


      For more information on what values are considered truthy and falsey, see the docs section on Truth Value Testing, as well as this answer. It is worth noting here that NotImplemented is truthy, but it would have been a different story had the class defined a __bool__ or __len__ method that returned False or 0 respectively.





      If you want the functional equivalent of the == operator, use operator.eq:



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


      However, as mentioned earlier, for this specific scenario, where you are checking for None, use is:



      var = 'a'
      var is None
      # False

      var2 = None
      var2 is None
      # True


      The functional equivalent of this is using operator.is_:



      operator.is_(var2, None)
      # True


      None is a special object, and only 1 version exists in memory at any point of time. IOW, it is the sole singleton of the NoneType class (but the same object may have any number of references). The PEP8 guidelines make this explicit:




      Comparisons to singletons like None should always be done with is or
      is not, never the equality operators.




      In summary, for singletons like None, a reference check with is is more appropriate, although both == and is will work just fine.






      share|improve this answer





















      • 6





        Nevertheless, I think it'd be worthy to note that None should be checked with is None, not ==, operator.eq or .__eq__

        – DeepSpace
        Dec 31 '18 at 11:58








      • 4





        @DeepSpace Thanks for that, I have reworked the answer so as to explain why == is better in any general situation, and why is is more appropriate for this specific one, quoting PEP8 at the bottom. Thanks for the comment!

        – coldspeed
        Dec 31 '18 at 12:12






      • 2





        It's worth mentioning (since it wasn't obvious to me) that NotImplemented belongs to the class <class 'NotImplementedType'>. Here, bool(NotImplemented) evaluates to True, because of some combination of: __bool__ undefined (most likely) / __bool__ explicitly defined to be Tue / __len__ doesn't give 0.

        – jpp
        Dec 31 '18 at 13:29








      • 2





        @jpp I don't think that class defines either __bool__ or __len__. I believe the spec dictates that the object is truthy unless __bool__ or __len__ say otherwise. You can read more here (that link is also included in the answer :-)).

        – coldspeed
        Dec 31 '18 at 14:51








      • 2





        @coldspeed, Yup, I thought so. But it's worth clarification because new users may fall into the trap that 'a' == 'NotImplemented' should return False ! While the underlying reason is you aren't working with strings but a NotImplementedType object.

        – jpp
        Dec 31 '18 at 14:54


















      166














      This is a great example of why the __dunder__ methods should not be used directly as they are quite often not appropriate replacements for their equivalent operators; you should use the == operator instead for equality comparisons, or in this special case, when checking for None, use is (skip to the bottom of the answer for more information).



      You've done



      None.__eq__('a')
      # NotImplemented


      Which returns NotImplemented since the types being compared are different. Consider another example where two objects with different types are being compared in this fashion, such as 1 and 'a'. Doing (1).__eq__('a') is also not correct, and will return NotImplemented. The right way to compare these two values for equality would be



      1 == 'a'
      # False


      What happens here is




      1. First, (1).__eq__('a') is tried, which returns NotImplemented. This indicates that the operation is not supported, so


      2. 'a'.__eq__(1) is called, which also returns the same NotImplemented. So,

      3. The objects are treated as if they are not the same, and False is returned.


      Here's a nice little MCVE using some custom classes to illustrate how this happens:



      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




      Of course, that doesn't explain why the operation returns true. This is because NotImplemented is actually a truthy value:



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


      Same as,



      bool(NotImplemented)
      # True


      For more information on what values are considered truthy and falsey, see the docs section on Truth Value Testing, as well as this answer. It is worth noting here that NotImplemented is truthy, but it would have been a different story had the class defined a __bool__ or __len__ method that returned False or 0 respectively.





      If you want the functional equivalent of the == operator, use operator.eq:



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


      However, as mentioned earlier, for this specific scenario, where you are checking for None, use is:



      var = 'a'
      var is None
      # False

      var2 = None
      var2 is None
      # True


      The functional equivalent of this is using operator.is_:



      operator.is_(var2, None)
      # True


      None is a special object, and only 1 version exists in memory at any point of time. IOW, it is the sole singleton of the NoneType class (but the same object may have any number of references). The PEP8 guidelines make this explicit:




      Comparisons to singletons like None should always be done with is or
      is not, never the equality operators.




      In summary, for singletons like None, a reference check with is is more appropriate, although both == and is will work just fine.






      share|improve this answer





















      • 6





        Nevertheless, I think it'd be worthy to note that None should be checked with is None, not ==, operator.eq or .__eq__

        – DeepSpace
        Dec 31 '18 at 11:58








      • 4





        @DeepSpace Thanks for that, I have reworked the answer so as to explain why == is better in any general situation, and why is is more appropriate for this specific one, quoting PEP8 at the bottom. Thanks for the comment!

        – coldspeed
        Dec 31 '18 at 12:12






      • 2





        It's worth mentioning (since it wasn't obvious to me) that NotImplemented belongs to the class <class 'NotImplementedType'>. Here, bool(NotImplemented) evaluates to True, because of some combination of: __bool__ undefined (most likely) / __bool__ explicitly defined to be Tue / __len__ doesn't give 0.

        – jpp
        Dec 31 '18 at 13:29








      • 2





        @jpp I don't think that class defines either __bool__ or __len__. I believe the spec dictates that the object is truthy unless __bool__ or __len__ say otherwise. You can read more here (that link is also included in the answer :-)).

        – coldspeed
        Dec 31 '18 at 14:51








      • 2





        @coldspeed, Yup, I thought so. But it's worth clarification because new users may fall into the trap that 'a' == 'NotImplemented' should return False ! While the underlying reason is you aren't working with strings but a NotImplementedType object.

        – jpp
        Dec 31 '18 at 14:54
















      166












      166








      166







      This is a great example of why the __dunder__ methods should not be used directly as they are quite often not appropriate replacements for their equivalent operators; you should use the == operator instead for equality comparisons, or in this special case, when checking for None, use is (skip to the bottom of the answer for more information).



      You've done



      None.__eq__('a')
      # NotImplemented


      Which returns NotImplemented since the types being compared are different. Consider another example where two objects with different types are being compared in this fashion, such as 1 and 'a'. Doing (1).__eq__('a') is also not correct, and will return NotImplemented. The right way to compare these two values for equality would be



      1 == 'a'
      # False


      What happens here is




      1. First, (1).__eq__('a') is tried, which returns NotImplemented. This indicates that the operation is not supported, so


      2. 'a'.__eq__(1) is called, which also returns the same NotImplemented. So,

      3. The objects are treated as if they are not the same, and False is returned.


      Here's a nice little MCVE using some custom classes to illustrate how this happens:



      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




      Of course, that doesn't explain why the operation returns true. This is because NotImplemented is actually a truthy value:



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


      Same as,



      bool(NotImplemented)
      # True


      For more information on what values are considered truthy and falsey, see the docs section on Truth Value Testing, as well as this answer. It is worth noting here that NotImplemented is truthy, but it would have been a different story had the class defined a __bool__ or __len__ method that returned False or 0 respectively.





      If you want the functional equivalent of the == operator, use operator.eq:



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


      However, as mentioned earlier, for this specific scenario, where you are checking for None, use is:



      var = 'a'
      var is None
      # False

      var2 = None
      var2 is None
      # True


      The functional equivalent of this is using operator.is_:



      operator.is_(var2, None)
      # True


      None is a special object, and only 1 version exists in memory at any point of time. IOW, it is the sole singleton of the NoneType class (but the same object may have any number of references). The PEP8 guidelines make this explicit:




      Comparisons to singletons like None should always be done with is or
      is not, never the equality operators.




      In summary, for singletons like None, a reference check with is is more appropriate, although both == and is will work just fine.






      share|improve this answer















      This is a great example of why the __dunder__ methods should not be used directly as they are quite often not appropriate replacements for their equivalent operators; you should use the == operator instead for equality comparisons, or in this special case, when checking for None, use is (skip to the bottom of the answer for more information).



      You've done



      None.__eq__('a')
      # NotImplemented


      Which returns NotImplemented since the types being compared are different. Consider another example where two objects with different types are being compared in this fashion, such as 1 and 'a'. Doing (1).__eq__('a') is also not correct, and will return NotImplemented. The right way to compare these two values for equality would be



      1 == 'a'
      # False


      What happens here is




      1. First, (1).__eq__('a') is tried, which returns NotImplemented. This indicates that the operation is not supported, so


      2. 'a'.__eq__(1) is called, which also returns the same NotImplemented. So,

      3. The objects are treated as if they are not the same, and False is returned.


      Here's a nice little MCVE using some custom classes to illustrate how this happens:



      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




      Of course, that doesn't explain why the operation returns true. This is because NotImplemented is actually a truthy value:



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


      Same as,



      bool(NotImplemented)
      # True


      For more information on what values are considered truthy and falsey, see the docs section on Truth Value Testing, as well as this answer. It is worth noting here that NotImplemented is truthy, but it would have been a different story had the class defined a __bool__ or __len__ method that returned False or 0 respectively.





      If you want the functional equivalent of the == operator, use operator.eq:



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


      However, as mentioned earlier, for this specific scenario, where you are checking for None, use is:



      var = 'a'
      var is None
      # False

      var2 = None
      var2 is None
      # True


      The functional equivalent of this is using operator.is_:



      operator.is_(var2, None)
      # True


      None is a special object, and only 1 version exists in memory at any point of time. IOW, it is the sole singleton of the NoneType class (but the same object may have any number of references). The PEP8 guidelines make this explicit:




      Comparisons to singletons like None should always be done with is or
      is not, never the equality operators.




      In summary, for singletons like None, a reference check with is is more appropriate, although both == and is will work just fine.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Dec 31 '18 at 15:04

























      answered Dec 31 '18 at 6:16









      coldspeedcoldspeed

      133k23143225




      133k23143225








      • 6





        Nevertheless, I think it'd be worthy to note that None should be checked with is None, not ==, operator.eq or .__eq__

        – DeepSpace
        Dec 31 '18 at 11:58








      • 4





        @DeepSpace Thanks for that, I have reworked the answer so as to explain why == is better in any general situation, and why is is more appropriate for this specific one, quoting PEP8 at the bottom. Thanks for the comment!

        – coldspeed
        Dec 31 '18 at 12:12






      • 2





        It's worth mentioning (since it wasn't obvious to me) that NotImplemented belongs to the class <class 'NotImplementedType'>. Here, bool(NotImplemented) evaluates to True, because of some combination of: __bool__ undefined (most likely) / __bool__ explicitly defined to be Tue / __len__ doesn't give 0.

        – jpp
        Dec 31 '18 at 13:29








      • 2





        @jpp I don't think that class defines either __bool__ or __len__. I believe the spec dictates that the object is truthy unless __bool__ or __len__ say otherwise. You can read more here (that link is also included in the answer :-)).

        – coldspeed
        Dec 31 '18 at 14:51








      • 2





        @coldspeed, Yup, I thought so. But it's worth clarification because new users may fall into the trap that 'a' == 'NotImplemented' should return False ! While the underlying reason is you aren't working with strings but a NotImplementedType object.

        – jpp
        Dec 31 '18 at 14:54
















      • 6





        Nevertheless, I think it'd be worthy to note that None should be checked with is None, not ==, operator.eq or .__eq__

        – DeepSpace
        Dec 31 '18 at 11:58








      • 4





        @DeepSpace Thanks for that, I have reworked the answer so as to explain why == is better in any general situation, and why is is more appropriate for this specific one, quoting PEP8 at the bottom. Thanks for the comment!

        – coldspeed
        Dec 31 '18 at 12:12






      • 2





        It's worth mentioning (since it wasn't obvious to me) that NotImplemented belongs to the class <class 'NotImplementedType'>. Here, bool(NotImplemented) evaluates to True, because of some combination of: __bool__ undefined (most likely) / __bool__ explicitly defined to be Tue / __len__ doesn't give 0.

        – jpp
        Dec 31 '18 at 13:29








      • 2





        @jpp I don't think that class defines either __bool__ or __len__. I believe the spec dictates that the object is truthy unless __bool__ or __len__ say otherwise. You can read more here (that link is also included in the answer :-)).

        – coldspeed
        Dec 31 '18 at 14:51








      • 2





        @coldspeed, Yup, I thought so. But it's worth clarification because new users may fall into the trap that 'a' == 'NotImplemented' should return False ! While the underlying reason is you aren't working with strings but a NotImplementedType object.

        – jpp
        Dec 31 '18 at 14:54










      6




      6





      Nevertheless, I think it'd be worthy to note that None should be checked with is None, not ==, operator.eq or .__eq__

      – DeepSpace
      Dec 31 '18 at 11:58







      Nevertheless, I think it'd be worthy to note that None should be checked with is None, not ==, operator.eq or .__eq__

      – DeepSpace
      Dec 31 '18 at 11:58






      4




      4





      @DeepSpace Thanks for that, I have reworked the answer so as to explain why == is better in any general situation, and why is is more appropriate for this specific one, quoting PEP8 at the bottom. Thanks for the comment!

      – coldspeed
      Dec 31 '18 at 12:12





      @DeepSpace Thanks for that, I have reworked the answer so as to explain why == is better in any general situation, and why is is more appropriate for this specific one, quoting PEP8 at the bottom. Thanks for the comment!

      – coldspeed
      Dec 31 '18 at 12:12




      2




      2





      It's worth mentioning (since it wasn't obvious to me) that NotImplemented belongs to the class <class 'NotImplementedType'>. Here, bool(NotImplemented) evaluates to True, because of some combination of: __bool__ undefined (most likely) / __bool__ explicitly defined to be Tue / __len__ doesn't give 0.

      – jpp
      Dec 31 '18 at 13:29







      It's worth mentioning (since it wasn't obvious to me) that NotImplemented belongs to the class <class 'NotImplementedType'>. Here, bool(NotImplemented) evaluates to True, because of some combination of: __bool__ undefined (most likely) / __bool__ explicitly defined to be Tue / __len__ doesn't give 0.

      – jpp
      Dec 31 '18 at 13:29






      2




      2





      @jpp I don't think that class defines either __bool__ or __len__. I believe the spec dictates that the object is truthy unless __bool__ or __len__ say otherwise. You can read more here (that link is also included in the answer :-)).

      – coldspeed
      Dec 31 '18 at 14:51







      @jpp I don't think that class defines either __bool__ or __len__. I believe the spec dictates that the object is truthy unless __bool__ or __len__ say otherwise. You can read more here (that link is also included in the answer :-)).

      – coldspeed
      Dec 31 '18 at 14:51






      2




      2





      @coldspeed, Yup, I thought so. But it's worth clarification because new users may fall into the trap that 'a' == 'NotImplemented' should return False ! While the underlying reason is you aren't working with strings but a NotImplementedType object.

      – jpp
      Dec 31 '18 at 14:54







      @coldspeed, Yup, I thought so. But it's worth clarification because new users may fall into the trap that 'a' == 'NotImplemented' should return False ! While the underlying reason is you aren't working with strings but a NotImplementedType object.

      – jpp
      Dec 31 '18 at 14:54















      32














      The result you are seeing is caused by that fact that



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


      evaluates to NotImplemented, and NotImplemented's truth value is documented to be True:



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




      Special value which should be returned by the binary special methods (e.g. eq(), lt(), add(), rsub(), etc.) to indicate that the operation is not implemented with respect to the other type; may be returned by the in-place binary special methods (e.g. imul(), iand(), etc.) for the same purpose. Its truth value is true.




      If you call the __eq()__ method manually rather than just using ==, you need to be prepared to deal with the possibility it may return NotImplemented and that its truth value is true.






      share|improve this answer






























        32














        The result you are seeing is caused by that fact that



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


        evaluates to NotImplemented, and NotImplemented's truth value is documented to be True:



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




        Special value which should be returned by the binary special methods (e.g. eq(), lt(), add(), rsub(), etc.) to indicate that the operation is not implemented with respect to the other type; may be returned by the in-place binary special methods (e.g. imul(), iand(), etc.) for the same purpose. Its truth value is true.




        If you call the __eq()__ method manually rather than just using ==, you need to be prepared to deal with the possibility it may return NotImplemented and that its truth value is true.






        share|improve this answer




























          32












          32








          32







          The result you are seeing is caused by that fact that



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


          evaluates to NotImplemented, and NotImplemented's truth value is documented to be True:



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




          Special value which should be returned by the binary special methods (e.g. eq(), lt(), add(), rsub(), etc.) to indicate that the operation is not implemented with respect to the other type; may be returned by the in-place binary special methods (e.g. imul(), iand(), etc.) for the same purpose. Its truth value is true.




          If you call the __eq()__ method manually rather than just using ==, you need to be prepared to deal with the possibility it may return NotImplemented and that its truth value is true.






          share|improve this answer















          The result you are seeing is caused by that fact that



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


          evaluates to NotImplemented, and NotImplemented's truth value is documented to be True:



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




          Special value which should be returned by the binary special methods (e.g. eq(), lt(), add(), rsub(), etc.) to indicate that the operation is not implemented with respect to the other type; may be returned by the in-place binary special methods (e.g. imul(), iand(), etc.) for the same purpose. Its truth value is true.




          If you call the __eq()__ method manually rather than just using ==, you need to be prepared to deal with the possibility it may return NotImplemented and that its truth value is true.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jan 12 at 1:59

























          answered Dec 31 '18 at 6:19









          Mark MeyerMark Meyer

          38.7k33159




          38.7k33159























              16














              As you already figured None.__eq__("a") evaluates to NotImplemented however if you try something like



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


              the result is




              yes




              this mean that the truth value of NotImplemented true



              Therefor the outcome of the question is obvious:



              None.__eq__(something) yields NotImplemented



              And bool(NotImplemented) evaluates to True



              So if None.__eq__("a") is always True






              share|improve this answer






























                16














                As you already figured None.__eq__("a") evaluates to NotImplemented however if you try something like



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


                the result is




                yes




                this mean that the truth value of NotImplemented true



                Therefor the outcome of the question is obvious:



                None.__eq__(something) yields NotImplemented



                And bool(NotImplemented) evaluates to True



                So if None.__eq__("a") is always True






                share|improve this answer




























                  16












                  16








                  16







                  As you already figured None.__eq__("a") evaluates to NotImplemented however if you try something like



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


                  the result is




                  yes




                  this mean that the truth value of NotImplemented true



                  Therefor the outcome of the question is obvious:



                  None.__eq__(something) yields NotImplemented



                  And bool(NotImplemented) evaluates to True



                  So if None.__eq__("a") is always True






                  share|improve this answer















                  As you already figured None.__eq__("a") evaluates to NotImplemented however if you try something like



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


                  the result is




                  yes




                  this mean that the truth value of NotImplemented true



                  Therefor the outcome of the question is obvious:



                  None.__eq__(something) yields NotImplemented



                  And bool(NotImplemented) evaluates to True



                  So if None.__eq__("a") is always True







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Dec 31 '18 at 14:54

























                  answered Dec 31 '18 at 6:30









                  KanjiuKanjiu

                  42110




                  42110























                      1














                      Why?



                      It returns a NotImplemented, yeah:



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


                      But if you look at this:



                      >>> bool(NotImplemented)
                      True
                      >>>


                      NotImplemented is actually a truthy value, so that's why it returns b, anything that is True will pass, anything that is False wouldn't.



                      How to solve it?



                      You have to check if it is True, so be more suspicious, as you see:



                      >>> NotImplemented == True
                      False
                      >>>


                      So you would do:



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


                      >>>


                      And as you see, it wouldn't return anything.






                      share|improve this answer



















                      • 1





                        most visually clear answer - v worthwhile addition - thank you

                        – scharfmn
                        Jan 29 at 19:27











                      • @scharfmn Lol, happy that i posted a good answer :-)

                        – U9-Forward
                        Jan 30 at 0:14






                      • 1





                        :) “worthwhile addition” doesn’t quite capture what I was trying to say (as you obv see) - maybe “belated excellence” is what I wanted - cheers

                        – scharfmn
                        Jan 30 at 0:25






                      • 1





                        @scharfmn Yeah, i was bored, so answer, lol :-) ...

                        – U9-Forward
                        Jan 30 at 0:26











                      • @scharfmn yes? I'm curious to know what you think this answer adds that hasn't already been covered before.

                        – coldspeed
                        Feb 1 at 22:43
















                      1














                      Why?



                      It returns a NotImplemented, yeah:



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


                      But if you look at this:



                      >>> bool(NotImplemented)
                      True
                      >>>


                      NotImplemented is actually a truthy value, so that's why it returns b, anything that is True will pass, anything that is False wouldn't.



                      How to solve it?



                      You have to check if it is True, so be more suspicious, as you see:



                      >>> NotImplemented == True
                      False
                      >>>


                      So you would do:



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


                      >>>


                      And as you see, it wouldn't return anything.






                      share|improve this answer



















                      • 1





                        most visually clear answer - v worthwhile addition - thank you

                        – scharfmn
                        Jan 29 at 19:27











                      • @scharfmn Lol, happy that i posted a good answer :-)

                        – U9-Forward
                        Jan 30 at 0:14






                      • 1





                        :) “worthwhile addition” doesn’t quite capture what I was trying to say (as you obv see) - maybe “belated excellence” is what I wanted - cheers

                        – scharfmn
                        Jan 30 at 0:25






                      • 1





                        @scharfmn Yeah, i was bored, so answer, lol :-) ...

                        – U9-Forward
                        Jan 30 at 0:26











                      • @scharfmn yes? I'm curious to know what you think this answer adds that hasn't already been covered before.

                        – coldspeed
                        Feb 1 at 22:43














                      1












                      1








                      1







                      Why?



                      It returns a NotImplemented, yeah:



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


                      But if you look at this:



                      >>> bool(NotImplemented)
                      True
                      >>>


                      NotImplemented is actually a truthy value, so that's why it returns b, anything that is True will pass, anything that is False wouldn't.



                      How to solve it?



                      You have to check if it is True, so be more suspicious, as you see:



                      >>> NotImplemented == True
                      False
                      >>>


                      So you would do:



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


                      >>>


                      And as you see, it wouldn't return anything.






                      share|improve this answer













                      Why?



                      It returns a NotImplemented, yeah:



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


                      But if you look at this:



                      >>> bool(NotImplemented)
                      True
                      >>>


                      NotImplemented is actually a truthy value, so that's why it returns b, anything that is True will pass, anything that is False wouldn't.



                      How to solve it?



                      You have to check if it is True, so be more suspicious, as you see:



                      >>> NotImplemented == True
                      False
                      >>>


                      So you would do:



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


                      >>>


                      And as you see, it wouldn't return anything.







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Jan 28 at 6:15









                      U9-ForwardU9-Forward

                      15.9k51542




                      15.9k51542








                      • 1





                        most visually clear answer - v worthwhile addition - thank you

                        – scharfmn
                        Jan 29 at 19:27











                      • @scharfmn Lol, happy that i posted a good answer :-)

                        – U9-Forward
                        Jan 30 at 0:14






                      • 1





                        :) “worthwhile addition” doesn’t quite capture what I was trying to say (as you obv see) - maybe “belated excellence” is what I wanted - cheers

                        – scharfmn
                        Jan 30 at 0:25






                      • 1





                        @scharfmn Yeah, i was bored, so answer, lol :-) ...

                        – U9-Forward
                        Jan 30 at 0:26











                      • @scharfmn yes? I'm curious to know what you think this answer adds that hasn't already been covered before.

                        – coldspeed
                        Feb 1 at 22:43














                      • 1





                        most visually clear answer - v worthwhile addition - thank you

                        – scharfmn
                        Jan 29 at 19:27











                      • @scharfmn Lol, happy that i posted a good answer :-)

                        – U9-Forward
                        Jan 30 at 0:14






                      • 1





                        :) “worthwhile addition” doesn’t quite capture what I was trying to say (as you obv see) - maybe “belated excellence” is what I wanted - cheers

                        – scharfmn
                        Jan 30 at 0:25






                      • 1





                        @scharfmn Yeah, i was bored, so answer, lol :-) ...

                        – U9-Forward
                        Jan 30 at 0:26











                      • @scharfmn yes? I'm curious to know what you think this answer adds that hasn't already been covered before.

                        – coldspeed
                        Feb 1 at 22:43








                      1




                      1





                      most visually clear answer - v worthwhile addition - thank you

                      – scharfmn
                      Jan 29 at 19:27





                      most visually clear answer - v worthwhile addition - thank you

                      – scharfmn
                      Jan 29 at 19:27













                      @scharfmn Lol, happy that i posted a good answer :-)

                      – U9-Forward
                      Jan 30 at 0:14





                      @scharfmn Lol, happy that i posted a good answer :-)

                      – U9-Forward
                      Jan 30 at 0:14




                      1




                      1





                      :) “worthwhile addition” doesn’t quite capture what I was trying to say (as you obv see) - maybe “belated excellence” is what I wanted - cheers

                      – scharfmn
                      Jan 30 at 0:25





                      :) “worthwhile addition” doesn’t quite capture what I was trying to say (as you obv see) - maybe “belated excellence” is what I wanted - cheers

                      – scharfmn
                      Jan 30 at 0:25




                      1




                      1





                      @scharfmn Yeah, i was bored, so answer, lol :-) ...

                      – U9-Forward
                      Jan 30 at 0:26





                      @scharfmn Yeah, i was bored, so answer, lol :-) ...

                      – U9-Forward
                      Jan 30 at 0:26













                      @scharfmn yes? I'm curious to know what you think this answer adds that hasn't already been covered before.

                      – coldspeed
                      Feb 1 at 22:43





                      @scharfmn yes? I'm curious to know what you think this answer adds that hasn't already been covered before.

                      – coldspeed
                      Feb 1 at 22:43


















                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53984116%2fwhy-does-if-none-eq-a-evaluate-to-true%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Bressuire

                      Cabo Verde

                      Gyllenstierna