python与numpy中的布尔和类型检查

dra*_*ock 13 python boolean numpy pep8

if今天在python 条款中遇到了意外的结果:

import numpy
if numpy.allclose(6.0, 6.1, rtol=0, atol=0.5):
    print 'close enough'  # works as expected (prints message)

if numpy.allclose(6.0, 6.1, rtol=0, atol=0.5) is True:
    print 'close enough'  # does NOT work as expected (prints nothing)
Run Code Online (Sandbox Code Playgroud)

经过一番探讨(即这个问题,特别是这个答案)之后,我明白了原因:type返回的numpy.allclose()numpy.bool_而不是简单的旧bool,而且显然是foo = numpy.bool_(1),然后if foo将评估,True同时if foo is True将评估False.这似乎是is运营商的工作.

我的问题是:为什么numpy有自己的布尔类型,根据这种情况,最佳做法是什么?我可以写逃脱if foo:得到预期的行为在上面的例子,但我喜欢更严格if foo is True:,因为它排除之类的东西2,并[2]从返回True,有时显式类型检查是可取的.

aba*_*ert 17

你正在做一些被认为是反模式的事情.引用PEP 8:

不要使用==将布尔值与True或False进行比较.

Yes:   if greeting:
No:    if greeting == True:
Worse: if greeting is True:
Run Code Online (Sandbox Code Playgroud)

numpy不是为了促进你的非pythonic代码而设计的,这不是numpy中的错误.事实上,这是一个完美的例子,说明为什么你的个人习语是一种反模式.


正如PEP 8所说,使用is True甚至更糟糕== True.为什么?因为你正在检查对象标识:不仅结果必须在布尔上下文中(通常只需要你),并且等于布尔True值,它实际上必须是常量True.很难想象这是你想要的任何情况.

你特别不想在这里:

>>> np.True_ == True
True
>>> np.True_ is True
False
Run Code Online (Sandbox Code Playgroud)

所以,你所做的只是明确地使你的代码与numpy不兼容,以及各种其他C扩展库(可以想象一个纯Python库可以返回一个等于的自定义值True,但我不知道任何这样做) .


在您的特定情况下,没有理由排除2[2].如果您阅读了文档numpy.allclose,那么显然不会返回它们.但是考虑一些其他功能,就像标准库中的许多功能一样,只是说它们评估为真或假.这意味着他们明确被允许返回其中一个真实的论点,并且经常会这样做.你为什么要考虑这个假?


最后,为什么numpy或任何其他C扩展库定义了这样的bool兼容但不是bool类型?

通常,这是因为它们包装了C int或C++ bool或其他类似的类型.在numpy的情况下,它包含一个值,该值可以存储在最快的机器字类型或单个字节(在某些情况下甚至可能是一个位),以适应性能,并且您的代码不必关心哪个,因为所有表示看起来都是一样的,包括真实和等于True常数.

  • 实际上,传统上我认为`如果问候是真的'比`if greeting == True`更好; 当你想要接受真实但不是真正的价值观时,这是一种罕见的情况,但却是一种合理的情况. (3认同)
  • 仅供参考,您引用了[有争议的] PEP8的一部分(https://github.com/jcrocholl/pep8/issues/134#issuecomment-14952244). (2认同)
  • 引自[相同链接](https://github.com/jcrocholl/pep8/issues/134#issuecomment-14952244):"我同意一般建议是cond:如果不是cond:,这就足够了对于95%的用例.但是有一些(罕见的)我们想要检查与布尔的身份......"(继续给出例子). (2认同)
  • **这个答案中反复呼吁 PEP8 和上面的评论过于敌对,可以说是居高临下,而且坦率地说是不必要的。** NumPy 开发人员自己已经公开承认,NumPy 未能利用标准 Python 标量类型是众所周知的(尽管是不可避免的) )设计缺陷,不存在实用的 NumPy 端解决方案:[“...如果我们有选择,我认为(*即,使用标准 Python 标量类型*)可能是我们会做的(或完全废除标量)有效地做同样的事情)。”](https://github.com/numpy/numpy/issues/12950#issuecomment-462800326) (2认同)
  • 顺便说一句,与“True”和“False”单例进行显式比较有“许多”有效的理由。隐式布尔比较会引发具有非布尔真实性的边缘情况(例如,将整数 0 和空字符串静默强制为“False”),因此违反了“显式优于隐式”的原则。[PEP 20](https://www.python.org/dev/peps/pep-0020) 的格言——在这方面可以说胜过 PEP 8。例如,当测试外部调用者定义的数据或来自可疑来源的输入时,假设合理的布尔真实性通常会增加攻击面。 (2认同)

Vee*_*rac 6

为什么numpy有自己的布尔类型

空间和速度。Numpy将事物存储在紧凑的数组中;如果它可以将布尔值放入单个字节,则将尝试。使用Python对象不容易做到这一点,因为您必须存储引用,这会大大降低计算速度。

在上面的示例中,我可以放弃编写if foo:以获得预期的行为,但是如果foo为True,我更严格:因为它从返回True排除了2和[2]之类的东西,有时显式类型检查是理想的。

好吧,不要那样做。