Returning NotImplemented from __eq__

前端 未结 2 1857
故里飘歌
故里飘歌 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 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!

提交回复
热议问题