以下代码行看似不一致的行为背后的理由是什么?
import numpy as np
# standard list
print(bool([])) # False - expected
print(bool([0])) # True - expected
print(bool([1])) # True - expected
print(bool([0,0])) # True - expected
# numpy arrays
print(bool(np.array([]))) # False - expected, deprecation warning: The
# truth value of an empty array is ambiguous...
print(bool(np.array([0]))) # False - unexpected, no warning
print(bool(np.array([1]))) # True - unexpected, no warning
print(bool(np.array([0,0]))) # ValueError: The truth value of an array
# with more than one element is ambiguous...
我的观点中至少有两个不一致的地方:
bool(container)
。为什么numpy数组不遵循这种模式? (bool(np.array([0]))
收益False
)请注意,空numpy数组的弃用添加在numpy 1.11之间。和1.14。
答案 0 :(得分:3)
对于第一个问题,原因是你对if np.array([1, 2]):
想要做什么一点都不清楚。
这对if [1, 2]:
来说不是问题,因为Python列表不做任何元素。你可以问的唯一问题是列表本身是否真实(非空)。
但是Numpy数组在元素方面做了所有事情,可能是元素方面的。请注意,这不是唯一的地方,甚至是最常见的地方,元素方式语义意味着数组与普通Python序列的工作方式不同。例如:
>>> [1, 2] * 3
[1, 2, 1, 2, 1, 2]
>>> np.array([1, 2]) * 3
array([3, 6])
而且,特别是对于这种情况,布尔数组是一个非常有用的东西,特别是因为你可以使用它们进行索引:
>>> arr = np.array([1, 2, 3, 4])
>>> arr > 2 # all values > 2
array([False, False, True, True])
>>> arr[arr > 2] = 2 # clamp the values at <= 2
>>> arr
array([1, 2, 2, 2])
一旦你有了这个特性,一个数组在布尔上下文中应该意味着什么变得模棱两可。通常,您需要bool数组。但是当你写if arr:
时,你可能意味着任何一件事:
if
的正文。 (将主体重写为由bool数组索引的arr
上的表达式。)if
的身体是否有任何元素是真的。 (使用any
。)if
的正文。 (使用any
。)if
的主体,就像普通的Python序列一样,但违反了数组通常的元素方式语义。 (明确检查空虚。)所以,不是猜测,而是经常出错,numpy会给你一个错误并强迫你明白。
对于第二个问题,警告文本是否不适合您?单个元素的真值显然不是模棱两可的。
单元素数组 - 特别是0D数组 - 通常用作伪标量,因此能够做到这一点不仅无害,它有时也很有用。
相比之下,问“这个数组是空的”很少有用。列表是一个可变大小的东西,你通常通过一次添加一个元素,零次或多次(可能隐含在理解中)来构建,所以通常值得问你是否添加了零元素。但是数组是一个固定大小的东西,你通常会在代码中的某处明确指定大小。
这就是允许它的原因。为什么它在单个值上运行,而不是在阵列的大小上运行。
对于空阵列(你没有问过,但确实提出来了):在这里,你可能没有多少合理的东西,很难想到你可能意味着什么。这可能是为什么这是最近唯一更改的情况(参见issue 9583),而不是自Python添加__nonzero__
以来的相同情况。