为啥在 Python 3 中 NotImplemented 是真实的?
Posted
技术标签:
【中文标题】为啥在 Python 3 中 NotImplemented 是真实的?【英文标题】:Why is NotImplemented truthy in Python 3?为什么在 Python 3 中 NotImplemented 是真实的? 【发布时间】:2019-06-05 15:56:30 【问题描述】:这个问题是由this question 的回答和讨论引发的。下面的 sn-p 说明了问题的症结所在:
>>> bool(NotImplemented)
True
我的问题如下:
-
为什么决定
NotImplemented
的bool
值应该是True
?感觉很奇怪。
是否有我不知道的充分理由?文档似乎只是说,“因为它是”。
有没有以合理方式使用它的示例?
为什么我认为它不直观的原因(请忽略缺乏最佳实践):
>>> class A:
... def something(self):
... return NotImplemented
...
>>> a = A()
>>> a.something()
NotImplemented
>>> if a.something():
... print("this is unintuitive")
...
this is unintuitive
具有如此负面含义(缺乏实现)的东西会被认为是真实的,这似乎是一种奇怪的行为。
相关文字来自:
未实现
二进制特殊方法(例如
__eq__()
、__lt__()
、__add__()
、__rsub__()
等)应返回的特殊值,表示该操作未针对其他类型实现;可以通过就地二进制特殊方法(例如__imul__()
、__iand__()
等)出于相同目的返回。它的真值是真的。——来自Python Docs
编辑 1
为了澄清我的立场,我觉得NotImplemented
能够评估为布尔值本身就是一种反模式。我觉得 Exception 更有意义,但普遍的想法是在评估不同对象之间的比较时出于性能原因选择常量单例。我想我正在寻找令人信服的理由来说明为什么这是选择的“方式”。
【问题讨论】:
True
是默认值(bool(object())
是 True
),没有令人信服的理由来更改它。
所有对象都是真实的,除非该类提供了 false-y 对象。问题是,NotImplemented
有充分的理由不说实话吗?
"3. 有没有合理使用的例子?"有没有任何例子表明对它应用布尔测试是有意义的?提出这个问题的动机是什么?
您的示例代码 sn-p 中的推理完全没有说服力。为什么输入if not a.something()
比输入if a.something()
更直观?
如果NotImplemented
不存在,数据模型中的__radd__
and all the other reflected operations 将如何工作?他们使用这个单例来表示“我不支持这个操作,但另一个操作数可能”。
【参考方案1】:
默认情况下,一个对象被认为是真实的(bool(obj) == True
),除非它的类提供了一种方法来覆盖它的真实性。在NotImplemented
的情况下,没有人提供过一个令人信服的用例让bool(NotImplemented)
返回False
,因此<class 'NotImplementedType'>
从未提供过覆盖。
【讨论】:
相关documentation 虽然我强烈反对没有令人信服的用例,但我相信您已经回答了这个问题。您如何看待我在原始问题中添加的经过编辑的示例以及可能证明将 NotImplemented 更改为 falsy 的合理性? @Julian:没有什么可以证明将其更改为虚假的。您对它的使用是错误的(它仅用于二元运算符重载,以触发对正在操作的其他对象的委托,而不是用于指示尚未实现的方法)。正确的代码将使用raise NotImplementedError("msg")
来避免默默地将结果视为 either 真实或虚假。 IMO,唯一合理的改变是让NotImplementedType.__bool__
提高TypeError
,这样人们就不会在布尔上下文the way Python used to中意外滥用它。
@ShadowRanger 我完全明白这不是使用NotImplemented
单例的正确方法,但这就是我要表达的意思。 python 的禅宗说“应该有一种——最好只有一种——明显的方式来做到这一点”,我认为NotImplemented
单例非常严重地违反了这一点。问题的目的不是“为什么我不能这样做?”只是为了指出这个单例背后的推理模棱两可,以及它的目的是多么模糊(除非你对底层数据模型逻辑非常了解)。
@ShadowRanger 我全心全意地相信引发错误是修复我使用的代码示例的正确方法。我建议制作bool(NotImplemented) == True
的原因是,无论上下文如何,它都会具有逻辑意义,并且底层数据模型可以简单地更新其逻辑以使用此更新的单例,而不会导致不了解NotImplemented
和@ 特质的人们过度混淆987654335@【参考方案2】:
正如accepted answer 已经解释的那样,python 中的所有类都被认为是真实的(bool(obj) returns True
),除非它们通过Truth Value Testing 专门更改它。在某些情况下覆盖它是有意义的,例如空列表 0
或 False
(请参阅一个好的列表 here)。
但是,NotImplemented
没有令人信服的理由是虚假的。它是解释器使用的特殊值,只能通过特殊方法返回,不应该到达常规的python代码。
二进制特殊方法(例如
__eq__()
、__lt__()
、__add__()
、__rsub__()
等)应返回的特殊值,表示该操作未针对其他类型实现。错误地返回
NotImplemented
将导致误导性错误消息或NotImplemented
值被返回给Python 代码。
解释器使用它在方法之间进行选择,或以其他方式影响行为,就像comparison operator ==
或bool()
本身的情况一样(它首先检查__bool__
,然后,如果它返回NotImplemented
, __len__
)。
请注意,存在NotImplementedError
异常,可能是因为它实际上是一个操作未实现的错误。在您的具体示例中,class A
的 something
可能应该引发此异常。
【讨论】:
是的,我现在完全同意你的看法。我意识到NotImplemented
非常专门用于解释器,应该进入用户代码。例外当然是要走的路。以上是关于为啥在 Python 3 中 NotImplemented 是真实的?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在 Python 3 中 NotImplemented 是真实的?
为啥我不能在 Python 3.8 中使用 pip? [复制]