阅读 134

[译]简析 Python 的 `NotImplemented`

原文链接: zhuanlan.zhihu.com
导读:本文讨论 Python 的 NotImplemented它是什么,它意味着什么,什么时候应该使用。

是什么

>>> type(NotImplemented)
<type 'NotImplementedType'>
复制代码

NotImplemented是 Python 内置命名空间中的六个常量之一。其他还有 False, True, None, Ellipsis__debug__。类似于 EllipsisNotImplemented可以重新赋值。 赋值给它,即使作为属性名称,也不会引发SyntaxError异常,所以它不是真正的“真实(real/true)”的常量。当然,我们永远都不应该重新赋值它。 但是,为了完整:

>>> None = 'hello'
...
SyntaxError: can't assign to keyword
>>> NotImplemented
NotImplemented
>>> NotImplemented = 'do not'
>>> NotImplemented
'do not'
复制代码

意味着什么,什么时候用

NotImplemented是 python 特殊二元方法(例如__eq__(), __lt__(), __add__(), __rsub__())返回的特殊值,表示该操作没有针对其他类型实现。而且,它转换成 bool 类型表示 true

>>> bool(NotImplemented)
True
复制代码

可能会有这样的疑问「应该在操作没有实现时抛出NotImpementedError异常」,通过一些例子,我们将看到为什么在实现二元特殊方法时不应该这样。

让我们通过为两个非常基本的(但无用的)类 A 和 B 编写一个 __eq__来展示NotImplemented常量的使用。[对于这个简单的例子,为避免分心不实现__ne__()。但通常来说,除非有充分的理由,否则每次实现__eq__(),也应该实现__ne__()。]

# example.py
class A(object):
    def __init__(self, value):
        self.value = value
    def __eq__(self, other):
        if isinstance(other, A):
            print('Comparing an A with an A')
            return other.value == self.value
        if isinstance(other, B):
            print('Comparing an A with a B')
            return other.value == self.value
        print('Could not compare A with the other class')
        return NotImplemented
class B(object):
    def __init__(self, value):
        self.value = value
    def __eq__(self, other):
        if isinstance(other, B):
            print('Comparing a B with another B')
            return other.value == self.value
        print('Could not compare B with the other class')
        return NotImplemented
复制代码

现在在 interpreter 中:

>>> from example import A, B
>>> a1 = A(1)
>>> b1 = B(1)
复制代码

现在我们可以尝试对__eq __() 的不同调用并查看会发生什么。提醒一下,在 Python 中,a == b实际上是调用 a.__eq__(b)

>>> a1 == a1
Comparing an A with an A
True
复制代码

如预期的那样,a1 等于 a1(本身),A 类中的__eq __() 方法处理此操作。将 b1 与自身进行比较也会得出类似的结果:

>>> b1 == b1
Comparing a B with another B
True
复制代码

如果我们现在比较 a1 和 b1,会怎么样?由于 A 的__eq __()会检查 other 参数是不是 B 的实例,我们期望 a1 .__ eq __(b1)处理比较操作并返回 True:

>>> a1 == b1
Comparing an A with a B
True
复制代码

现在,如果我们将 b1 与 a1 进行比较(即调用 b1.__eq__(a1)),我们应该期望返回NotImplemented。这是因为 B 的__eq __()仅与其他 B 的实例进行比较。让我们看看发生了什么:

>>> b1 == a1
Could not compare B against the other class
Comparing an A with a B
True
复制代码

b1 .__ eq __(a1)方法返回 NotImplemented导致 A 的__eq __()方法被调用,并且由于在 A 的__eq __()中定义了 A 和 B 之间的比较,我们得到了正确的结果(True)。

这就是返回 NotImplemented所做的事情。NotImplemented告诉运行时它应该请求 other 来满足操作。 在表达式b1 == a1中,b1 .__ eq __(a1)返回 NotImplemented,它告诉 Python 尝试调用 a1 .__ eq __(b1)。 由于 a1 足够知道返回 True,所以表达式可以成功。 如果 A 的__eq __()也返回NotImplemented,那么运行时将回退到基于对象标识(在 CPython 中是对象在内存中的地址)的相等内置行为。

注意,当b1 .__ eq __(a1)失败时抛出一个NotImpementedError异常会突破代码调用,除非被捕获,但 NotImplemented不会被抛出并可以用于进一步的测试。

原文:Python’s `NotImplemented` Type

扩展阅读:

极光日报,极光开发者旗下媒体。
每天导读三篇英文技术文章。
文章分类
后端
文章标签