wim*_*wim 21 python arrays types numpy truthiness
import numpy as np
a = np.array([0])
b = np.array([None])
c = np.array([''])
d = np.array([' '])
Run Code Online (Sandbox Code Playgroud)
为什么我们应该有这种不一致性:
>>> bool(a)
False
>>> bool(b)
False
>>> bool(c)
True
>>> bool(d)
False
Run Code Online (Sandbox Code Playgroud)
我非常肯定,正如Scalars所解释的那样,答案是:
数组标量与ndarrays具有相同的属性和方法.[1]这允许人们将阵列中的项目部分地放在与阵列相同的基础上,从而平滑混合标量和阵列操作时产生的粗糙边缘.
因此,如果调用bool标量是可以接受的,那么调用bool一个形状数组是可以接受的(1,),因为它们尽可能是相同的.
而且,虽然在我所知道的文档中并没有直接说出来,但从设计中可以明显看出NumPy的标量应该像本机Python对象一样.
所以,这解释了为什么np.array([0])是假的而不是真实的,这是你最初感到惊讶的.
所以,这解释了基础知识.但案件的具体情况又c如何呢?
首先,请注意您的数组np.array([''])不是一个Python object的数组,而是一个<U1长度为1的NumPy以空字符结尾的字符串的数组.固定长度字符串值与Python字符串不具有相同的真实性规则 - 它们确实不能; 对于固定长度字符串类型,"false if empty"没有任何意义,因为它们永远不会是空的.你可以争论NumPy是否应该以这种方式设计,但它显然确实遵循该规则,我认为相反的规则在这里不会混淆,只是不同.
但是字符串似乎还有其他奇怪的东西.考虑一下:
>>> np.array(['a', 'b']) != 0
True
Run Code Online (Sandbox Code Playgroud)
这不是将<U2字符串元素比较为0并返回array([True, True])(正如你得到的np.array(['a', 'b'], dtype=object)),它正在进行数组范围的比较,并确定没有字符串数组等于0,这看起来很奇怪......我不确定这是否值得一个单独的答案,甚至是一个完全独立的问题,但我很确定我不会成为那个写答案的人,因为我不知道这里发生了什么.:)
除了形状(1,)数组之外,形状数组的()处理方式相同,但其他任何东西都是a ValueError,因为否则很容易误用数组and和其他Python运算符,NumPy无法自动转换为元素运算.
我个人认为与其他数组保持一致比在这里与标量符合更有用 - 换句话说,只需要提高一个ValueError.我还认为,如果在这里与标量符号一致很重要,那么最好与未装箱的Python值保持一致.换句话说,如果bool(array([v]))和bool(array(v))将要被允许,它们应该总是返回完全相同的东西bool(v),即使这与它不一致np.nonzero.但我可以从另一个方面看到这个论点.
对于具有一个元素的数组,数组的真值由该元素的真值确定.
主点到使是,np.array([''])是不含有一个空Python字符串的数组.创建此数组以保存每个字符串恰好一个字节的字符串,并且NumPy填充的字符串与空字符相比太短.这意味着数组等于np.array(['\0']).
在这方面,NumPy与Python一致,评估bool('\0')为True.
实际上,FalseNumPy数组中唯一的字符串是不包含任何非空白字符的字符串('\0'不是空格字符).
该布尔评估的细节如下所示.
浏览NumPy的迷宫源代码并不总是很容易,但是我们可以找到控制不同数据类型中的值如何映射到arraytypes.c.src文件中的布尔值的代码.这将解释如何bool(a),bool(b),bool(c)和bool(d)被确定.
在我们到达该文件中的代码之前,我们可以看到调用bool()NumPy数组会调用内部_array_nonzero()函数.如果数组为空,我们得到False.如果有两个或更多元素,我们会收到错误.但是如果数组只有一个元素,那么我们就行了:
return PyArray_DESCR(mp)->f->nonzero(PyArray_DATA(mp), mp);
Run Code Online (Sandbox Code Playgroud)
现在,PyArray_DESCR是一个包含数组的各种属性的结构.f是指向另一个PyArray_ArrFuncs保存数组nonzero函数的结构的指针.换句话说,NumPy将调用数组自己的特殊nonzero函数来检查该元素的布尔值.
确定元素是否为非零显然取决于元素的数据类型.实现特定于类型的非零函数的代码可以在arraytypes.c.src文件的"非零"部分中找到.
正如我们所期望的那样,浮点数,整数和复数False是否等于零.这解释了bool(a).在对象数组的情况下,None类似地将被评估为False因为NumPy只是调用该PyObject_IsTrue函数.这解释了bool(b).
要了解的结果bool(c)和bool(d),我们看到,nonzero对于字符串类型数组功能被映射到STRING_nonzero函数:
static npy_bool
STRING_nonzero (char *ip, PyArrayObject *ap)
{
int len = PyArray_DESCR(ap)->elsize; // size of dtype (not string length)
int i;
npy_bool nonz = NPY_FALSE;
for (i = 0; i < len; i++) {
if (!Py_STRING_ISSPACE(*ip)) { // if it isn't whitespace, it's True
nonz = NPY_TRUE;
break;
}
ip++;
}
return nonz;
}
Run Code Online (Sandbox Code Playgroud)
(unicode案例或多或少是相同的想法.)
因此,在具有字符串或unicode数据类型的数组中,仅False当字符串仅包含空格字符时才是字符串:
>>> bool(np.array([' ']))
False
Run Code Online (Sandbox Code Playgroud)
在c问题中的数组的情况下,有一个真正的空字符\0填充看似空的字符串:
>>> np.array(['']) == np.array(['\0'])
array([ True], dtype=bool)
Run Code Online (Sandbox Code Playgroud)
该STRING_nonzero函数看到这个非空白字符等bool(c)是True.
正如本答案开头所述,这与Python对包含单个空字符的字符串的评估是一致的:bool('\0')也是True.
更新:Wim通过制作仅包含空字符的字符串或仅包含空格和空字符的字符串来修复 NumPy主分支中详述的行为False.这意味着,与NumPy 1.10+会看到bool(np.array(['']))是False,这是符合Python的治疗"空"的字符串得多.