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












6














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





























    6














    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



























      6












      6








      6


      1





      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 4 hours ago









      coldspeed

      120k19116194




      120k19116194










      asked 5 hours ago









      The AI Architect

      1111312




      1111312
























          3 Answers
          3






          active

          oldest

          votes


















          11














          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; in this case you should use the == operator instead. You've done



          None.__eq__('a')
          # NotImplemented


          Which returns NotImplemented since the types being compared are different. Try comparing any two objects with different types like this (ex (1).__eq__('a')). The right way to do this would be



          None == 'a'
          # False


          What happens here is




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


          2. 'a'.__eq__(None) 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 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.





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



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





          share|improve this answer































            4














            The result you are seeing is documented



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





























              2














              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 NotImplemented.__bool__() returns 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








              New contributor




              Kanjiu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
              Check out our Code of Conduct.


















                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

























                3 Answers
                3






                active

                oldest

                votes








                3 Answers
                3






                active

                oldest

                votes









                active

                oldest

                votes






                active

                oldest

                votes









                11














                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; in this case you should use the == operator instead. You've done



                None.__eq__('a')
                # NotImplemented


                Which returns NotImplemented since the types being compared are different. Try comparing any two objects with different types like this (ex (1).__eq__('a')). The right way to do this would be



                None == 'a'
                # False


                What happens here is




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


                2. 'a'.__eq__(None) 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 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.





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



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





                share|improve this answer




























                  11














                  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; in this case you should use the == operator instead. You've done



                  None.__eq__('a')
                  # NotImplemented


                  Which returns NotImplemented since the types being compared are different. Try comparing any two objects with different types like this (ex (1).__eq__('a')). The right way to do this would be



                  None == 'a'
                  # False


                  What happens here is




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


                  2. 'a'.__eq__(None) 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 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.





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



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





                  share|improve this answer


























                    11












                    11








                    11






                    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; in this case you should use the == operator instead. You've done



                    None.__eq__('a')
                    # NotImplemented


                    Which returns NotImplemented since the types being compared are different. Try comparing any two objects with different types like this (ex (1).__eq__('a')). The right way to do this would be



                    None == 'a'
                    # False


                    What happens here is




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


                    2. 'a'.__eq__(None) 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 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.





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



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





                    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; in this case you should use the == operator instead. You've done



                    None.__eq__('a')
                    # NotImplemented


                    Which returns NotImplemented since the types being compared are different. Try comparing any two objects with different types like this (ex (1).__eq__('a')). The right way to do this would be



                    None == 'a'
                    # False


                    What happens here is




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


                    2. 'a'.__eq__(None) 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 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.





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



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






                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited 40 mins ago

























                    answered 5 hours ago









                    coldspeed

                    120k19116194




                    120k19116194

























                        4














                        The result you are seeing is documented



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


























                          4














                          The result you are seeing is documented



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
























                            4












                            4








                            4






                            The result you are seeing is documented



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



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










                            answered 5 hours ago









                            Mark Meyer

                            35.7k32956




                            35.7k32956























                                2














                                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 NotImplemented.__bool__() returns 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








                                New contributor




                                Kanjiu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                Check out our Code of Conduct.























                                  2














                                  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 NotImplemented.__bool__() returns 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








                                  New contributor




                                  Kanjiu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                  Check out our Code of Conduct.





















                                    2












                                    2








                                    2






                                    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 NotImplemented.__bool__() returns 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








                                    New contributor




                                    Kanjiu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                    Check out our Code of Conduct.









                                    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 NotImplemented.__bool__() returns 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








                                    New contributor




                                    Kanjiu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                    Check out our Code of Conduct.









                                    share|improve this answer



                                    share|improve this answer






                                    New contributor




                                    Kanjiu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                    Check out our Code of Conduct.









                                    answered 4 hours ago









                                    Kanjiu

                                    1837




                                    1837




                                    New contributor




                                    Kanjiu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                    Check out our Code of Conduct.





                                    New contributor





                                    Kanjiu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                    Check out our Code of Conduct.






                                    Kanjiu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                    Check out our Code of Conduct.






























                                        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.





                                        Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                        Please pay close attention to the following guidance:


                                        • 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

                                        Morgemoulin

                                        Scott Moir

                                        Souastre