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

时间:2013-09-20 17:19:41

标签: python numpy boolean pep8

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

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)

经过一番探讨(即this question,特别是this answer)之后,我明白了原因: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]之类的内容{1}},有时需要明确的类型检查。

2 个答案:

答案 0 :(得分:16)

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

  

不要使用==。

将布尔值与True或False进行比较
Yes:   if greeting:
No:    if greeting == True:
Worse: if greeting is True:

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


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

你特别不想在这里:

>>> np.True_ == True
True
>>> np.True_ is True
False

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


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


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

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

答案 1 :(得分:4)

  

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

空间和速度。 Numpy将东西存储在紧凑的数组中;如果它可以将布尔值拟合为单个字节,那么它将尝试。您不能轻易地使用Python对象执行此操作,因为您必须存储明显减慢计算速度的引用。

  

如果foo:我可以在上面的例子中得到预期的行为,但我喜欢更严格,如果foo是True:因为它排除了返回True的2和[2]之类的东西,有时是明确的类型检查是可取的。

好吧,不要那样做。