Returning NotImplemented from __eq__

前端 未结 2 1845
故里飘歌
故里飘歌 2021-01-11 09:07

What\'s the result of returning NotImplemented from __eq__ special method in python 3 (well 3.5 if it matters)?

The documentation isn\'t cl

相关标签:
2条回答
  • 2021-01-11 09:49

    Not sure where (or if) it is in the docs, but the basic behavior is:

    • try the operation: __eq__(lhs, rhs)
    • if result is not NotImplemented return it
    • else try the reflected operation: __eq__(rhs, lhs)
    • if result is not NotImplemented return it
    • otherwise use appropriate fall back:

      eq -> same objects? -> True, else False

      ne -> different objects? True, else False

      many others -> raise exception

    The reason that eq and ne do not raise exceptions is:

    • they can always be determined (apple == orange? no)
    0 讨论(0)
  • 2021-01-11 10:07

    Actually the == and != check work identical to the ordering comparison operators (< and similar) except that they don't raise the appropriate exception but fall-back to identity comparison. That's the only difference.

    This can be easily seen in the CPython source code (version 3.5.10). I will include a Python version of that source code (at least as far as it's possible):

    _mirrored_op = {'__eq__': '__eq__',  # a == b => b == a
                    '__ne__': '__ne__',  # a != b => b != a
                    '__lt__': '__gt__',  # a < b  => b > a
                    '__le__': '__ge__',  # a <= b => b >= a
                    '__ge__': '__le__',  # a >= b => b <= a
                    '__gt__': '__lt__'   # a > b  => b < a
                   }
    
    def richcmp(v, w, op):
        checked_reverse = 0
        # If the second operand is a true subclass of the first one start with
        # a reversed operation.
        if type(v) != type(w) and issubclass(type(w), type(v)) and hasattr(w, op):
            checked_reverse = 1
            res = getattr(w, _mirrored_op[op])(v)     # reversed
            if res is not NotImplemented:
                return res
        # Always try the not-reversed operation
        if hasattr(v, op):
            res = getattr(v, op)(w)      # normal
            if res is not NotImplemented:
                return res
        # If we haven't already tried the reversed operation try it now!
        if not checked_reverse and hasattr(w, op):
            res = getattr(w, _mirrored_op[op])(v)      # reversed
            if res is not NotImplemented:
                return res
        # Raise exception for ordering comparisons but use object identity in 
        # case we compare for equality or inequality
        if op == '__eq__':
            res = v is w
        elif op == '__ne__':
            res = v is not w
        else:
            raise TypeError('some error message')
    
        return res
    

    and calling a == b then evaluates as richcmp(a, b, '__eq__'). The if op == '__eq__' is the special case that makes your a == b return False (because they aren't identical objects) and your a == a return True (because they are).

    However the behavior in Python 2.x was completely different. You could have up to 4 (or even 6, I don't remember exactly) comparisons before falling back to identity comparison!

    0 讨论(0)
提交回复
热议问题