Python 将numpy数组转换为bool时的行为似乎不一致

Python 将numpy数组转换为bool时的行为似乎不一致,python,numpy,Python,Numpy,以下代码行看似不一致的行为背后的基本原理是什么 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 -

以下代码行看似不一致的行为背后的基本原理是什么

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...
我的观点至少有两个不一致之处:

  • 可以测试标准python容器的空性
    bool(容器)
    。为什么numpy数组不遵循这种模式?(
    bool(np.array([0]))
    产生
    False
  • 为什么在转换空numpy数组或长度大于1的数组时会出现异常/弃用警告,但在numpy数组仅包含一个元素时可以这样做

请注意,对空numpy数组的弃用是在numpy 1.11之间添加的。对于第一个问题,原因是对于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])
arr=np.array([1,2,3,4]) >>>arr>2#所有值均>2 数组([False,False,True,True]) >>>arr[arr>2]=2#钳制>>arr处的值 数组([1,2,2,2])
一旦有了这个特性,数组在布尔上下文中的含义就变得模糊不清了。通常,您需要布尔数组。但是,当您编写
if arr:
时,您可能指的是多种事物中的任何一种:

  • 对每个真实的元素执行
    if
    的主体。(将主体重写为布尔数组索引的
    arr
    上的表达式。)
  • 如果有任何元素是真实的,则执行
    的主体。(使用
    any
  • 如果所有元素都是真实的,则执行
    的主体。(使用
    any
  • 某个轴上的混合体,例如,在任何元素都真实的情况下,为每行绘制主体
  • 如果数组是非空的,则执行
    if
    的主体,该数组的行为类似于普通的Python序列,但违反了数组通常的元素语义。(明确检查是否为空。)
因此,numpy给了你一个错误,迫使你直言不讳,而不是猜测


对于第二个问题,警告文本不是为您解答了这个问题吗?单个元素的真值显然并不含糊

而单元素数组,尤其是0D数组,通常被用作伪标量,因此能够这样做不仅无害,有时也很有用

相比之下,询问“此数组是否为空”很少有用。列表是一个可变大小的东西,通常通过一次添加一个元素来构建,每次添加0个或多个元素(可能在理解中是隐式的),因此经常值得询问是否添加了0个元素。但是数组是一个固定大小的东西,通常在代码中的某个地方显式指定大小

这就是为什么它是被允许的。以及为什么它对单个值而不是数组的大小进行操作



对于空数组(您没有询问,但确实提到了):在这里,您可能指的不是多个合理的内容,而是很难想到任何合理的内容。这可能就是为什么这是最近唯一发生变化的情况(请参阅),而不是自Python为第一个问题添加
\uuuuu nonzero\uuuuu>

以来的情况。原因是,对于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])
arr=np.array([1,2,3,4]) >>>arr>2#所有值均>2 数组([False,False,True,True]) >>>arr[arr>2]=2#钳制>>arr处的值 数组([1,2,2,2])
一旦有了这个特性,数组在布尔上下文中的含义就变得模糊不清了。通常,您需要布尔数组。但是,当您编写
if arr:
时,您可能指的是多种事物中的任何一种:

  • 对每个真实的元素执行
    if
    的主体。(将主体重写为布尔数组索引的
    arr
    上的表达式。)
  • 如果有任何元素是真实的,则执行
    的主体。(使用
    any
  • 如果所有元素都是真实的,则执行
    的主体。(使用
    any
  • 某个轴上的混合体,例如,在任何元素都真实的情况下,为每行绘制主体
  • 如果数组是非空的,则执行
    if
    的主体,该数组的行为类似于普通的Python序列,但违反了数组通常的元素语义。(明确检查是否为空。)
因此,numpy给了你一个错误,迫使你直言不讳,而不是猜测


对于第二个问题,警告文本不是为您解答了这个问题吗?单个元素的真值显然并不含糊

而单元素数组,尤其是0D数组,经常被用作伪标量,所以能够这样做不仅是无害的,而且是有益的