为什么没有链接(间隔)比较在numpy数组上工作?

Jas*_*n S 6 numpy python-2.7

a < b < c是Python中的链式表达式,看起来它适用于定义了适当比较运算符的对象,但它不适用于numpy数组.为什么?

import numpy as np

class ContrarianContainer(object):
    def __init__(self, x):
        self.x = x
    def __le__(self, y):
        return not self.x <= y
    def __lt__(self, y):
        return not self.x < y
    def __ge__(self, y):
        return not self.x >= y
    def __gt__(self, y):
        return not self.x > y
    def __eq__(self, y):
        return not self.x == y
    def __ne__(self, y):
        return not self.x != y

numlist = np.array([1,2,3,4])
for n in numlist:
    print 0 < n < 3.5
for n in numlist:
    print 0 > ContrarianContainer(n) > 3.5
print 0 < numlist < 3.5
Run Code Online (Sandbox Code Playgroud)

这打印:

True
True
True
False
True
True
True
False
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-187-277da7750148> in <module>()
      4 for n in numlist:
      5     print 0 < n < 3.5
----> 6 print 0 < numlist < 3.5

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Run Code Online (Sandbox Code Playgroud)

Joh*_*ooy 6

0 < numlist < 3.5
Run Code Online (Sandbox Code Playgroud)

相当于:

(0 < numlist) and (numlist < 3.5)
Run Code Online (Sandbox Code Playgroud)

除了numlist只评估一次.

and两个结果之间的隐含导致错误


hpa*_*ulj 4

所以文档说:

形式上,如果 a, b, c, ..., y, z 是表达式,op1, op2, ..., opN 是比较运算符,则 a op1 b op2 c ... y opN z 等价于 a op1 b b op2 c 和 ... y opN z,不同之处在于每个表达式最多计算一次。

(但在这两种情况下,当发现 x < y 为假时,根本不会计算 z)。

对于标量

In [20]: x=5
In [21]: 0<x<10
Out[21]: True
In [22]: 0<x and x<10
Out[22]: True
Run Code Online (Sandbox Code Playgroud)

但是用数组

In [24]: x=np.array([4,5,6])    
In [25]: 0<x and x<10
...
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Run Code Online (Sandbox Code Playgroud)

当在需要标量布尔值的上下文中使用 numpy 布尔值时,会出现此 ValueError 。

In [26]: (0<x)
Out[26]: array([ True,  True,  True], dtype=bool)

In [30]: np.array([True, False]) or True
...
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
In [33]: if np.array([True, False]): print('yes')
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Run Code Online (Sandbox Code Playgroud)

它评估0<x,但甚至不评估x<10,因为它无法在or/and上下文中使用生成的布尔数组。numpy定义了|&,但没有or定义 或and

In [34]: (0<x) & x<10
Out[34]: array([ True,  True,  True], dtype=bool)
Run Code Online (Sandbox Code Playgroud)

当我们使用时,0 < x <10我们隐含地期望计算标量链式表达式的矢量化版本。

In [35]: f = np.vectorize(lambda x: 0<x<10, otypes=[bool])
In [36]: f(x)
Out[36]: array([ True,  True,  True], dtype=bool)
In [37]: f([-1,5,11])
Out[37]: array([False,  True, False], dtype=bool)
Run Code Online (Sandbox Code Playgroud)

请注意,尝试将链接应用于列表甚至不会超过第一个<

In [39]: 0 < [-1,5,11]
TypeError: unorderable types: int() < list()
Run Code Online (Sandbox Code Playgroud)

这组表达式表明该&运算符的优先级高于该<运算符:

In [44]: 0 < x & x<10
ValueError ...

In [45]: (0 < x) & x<10
Out[45]: array([ True,  True,  True], dtype=bool)

In [46]: 0 < x & (x<10)
Out[46]: array([False,  True, False], dtype=bool)

In [47]: 0 < (x & x)<10
ValueError...
Run Code Online (Sandbox Code Playgroud)

因此,安全的版本是 (0 < x) & (x<10),确保所有内容都<&.

编辑

这是证实快捷and评估的另一个示例:

In [53]: x=2
In [54]: 3<x<np.arange(4)
Out[54]: False
In [55]: 1<x<np.arange(4)
Out[55]: array([False, False, False,  True])
Run Code Online (Sandbox Code Playgroud)

3<xis 时False,它返回该值,而不进行进一步评估。

当它是 时True,它继续计算x<np.arange(4),返回一个 4 元素布尔值。

<或者使用一个根本不支持的列表:

In [56]: 3<x<[1,2,3]
Out[56]: False
In [57]: 1<x<[1,2,3]
Traceback (most recent call last):
  File "<ipython-input-57-e7430e03ad55>", line 1, in <module>
    1<x<[1,2,3]
TypeError: '<' not supported between instances of 'int' and 'list'
Run Code Online (Sandbox Code Playgroud)