为什么NotImplemented不会引发TypeError错误?

3
假设我定义一个类名为A,我不想让任何人在没有排除的情况下写出该类的不等式。
class A():
    def __ne__(self, other):
        return NotImplemented
print(A() != A())

但是这将打印出 True,虽然我故意“关闭”了!=运算符,并且不会引发TypeError
2个回答

9
当你返回NotImplemented,表示你不知道__ne__是应该返回True还是False
通常情况下,Python会交换操作数; 如果a != b的结果是NotImplemented,则它将尝试b != a。这里也会失败,因为你在运算符的两侧使用相同的类型。对于!=运算符,Python将退回到比较它们的内存地址,而这些地址不相同(两个分离的实例),所以返回False
有关详细信息,请参见do_richcompare C函数
如果这是你预期的结果,那么你必须手动引发TypeError()

3.x 的富比较实现的简单性让人欣慰。在 2.x 中,Python 不是调用 __ne__ 两次,而是调用了6次 (一次是当 slot_tp_richcomparePyObject_RichCompare调用时,另外4次是当try_rich_compare在正常和交换顺序时尝试)。最后,在default_3way_compare中进行指针比较,由于需要转换为 uintptr_t 才能支持排序,使得这个过程变得复杂。 - Eryk Sun
是的,看到这个问题上有 python-3.x 标签,我感到相当宽慰。如果要详细说明在 Python 2 中如何工作,那么答案会变得 稍微 冗长一些。然而,对于 A() != A(),我只计算了 4 次对 __ne__ 的调用,按照 LR、RL、RL、LR(左手和右手实例)的顺序。 - Martijn Pieters

-2

它返回True,因为你正在返回一个异常,而不是抛出它。这意味着你将非空对象(异常)作为测试结果返回。非空对象会被视为True,除非另有规定。 请记住,直到你抛出异常之前,它只是一个普通的对象。

所以你应该有一个像这样的方法:

class A():
    def __ne__(self, other):
        raise NotImplementedError

2
不是一个异常。阅读 __ne__ 的文档;它是为了这个特定目的而设计的单例模式。 - Martijn Pieters
没错,我在考虑异常。不要误会,但是文档在这方面存在缺陷,因为NotImplemented的bool()返回True,并且没有提供任何有意义的错误信息。因此,正确的做法是引发异常,至少在OP的意图方面是这样(就我所理解的)。 - EnricoGiampieri
不,NotImplemented 是一个非常有用的哨兵值(即表示某些东西没有实现的值)。 - user395760
NotImplemented 是一种特殊的单例,用于这种情况。Python 比较代码会专门测试它。我认为一个专门的异常可能是更好的选择(比如 StopIteration),但这可能是 Python 很早期的遗留问题。然而,也许还有一些边缘情况,异常不是合适的响应方式。在数值强制转换等方面,NotImplemented(以及 C API 等效的 Py_NotImplemented)还有更多的用法。 - Martijn Pieters
如果这个答案是错误的,也许你可以编辑或删除它? - Yaroslav Nikitenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接