Seemingly inconsistent behavior when converting numpy arrays to bool

前端 未结 1 866
[愿得一人]
[愿得一人] 2021-01-26 13:33

What is the rationale behind the seemingly inconsistent behaviour of the following lines of code?

import numpy as np

# standard list
print(bool([]))                     


        
相关标签:
1条回答
  • 2021-01-26 14:16

    For the first problem, the reason is that it's not at all clear what you want to do with if np.array([1, 2]):.

    This isn't a problem for if [1, 2]: because Python lists don't do element-wise anything. The only thing you can be asking is whether the list itself is truthy (non-empty).

    But Numpy arrays do everything element-wise that possibly could be element-wise. Notice that this is hardly the only place, or even the most common place, where element-wise semantics mean that arrays work differently from normal Python sequences. For example:

    >>> [1, 2] * 3
    [1, 2, 1, 2, 1, 2]
    >>> np.array([1, 2]) * 3
    array([3, 6])
    

    And, for this case in particular, boolean arrays are a very useful thing, especially since you can index with them:

    >>> 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])
    

    And once you have that feature, it becomes ambiguous what an array should mean in a boolean context. Normally, you want the bool array. But when you write if arr:, you could mean any of multiple things:

    • Do the body of the if for each element that's truthy. (Rewrite the body as an expression on arr indexed by the bool array.)
    • Do the body of the if if any element is truthy. (Use any.)
    • Do the body of the if if all elements are truthy. (Use any.)
    • A hybrid over some axis—e.g., do the body for each row where any element is truthy.
    • Do the body of the if if the array is nonempty—acting like a normal Python sequence but violating the usual element-wise semantics of an array. (Explicitly check for emptiness.)

    So, rather than guess, and be wrong more often than not, numpy gives you an error and forces you to be explicit.


    For the second problem, doesn't the warning text answer this for you? The truth value of a single element is obviously not ambiguous.

    And single-element arrays—especially 0D ones—are often used as pseudo-scalars, so being able to do this isn't just harmless, it's also sometimes useful.

    By contrast, asking "is this array empty" is rarely useful. A list is a variable-sized thing that you usually build up by adding one element at a time, zero or more times (possibly implicitly in a comprehension), so it's very often worth asking whether you added zero elements. But an array is a fixed-size thing, where you usually explicitly specified the size somewhere nearby in the code.

    That's why it's allowed. And why it operates on the single value, not on the size of the array.


    For empty arrays (which you didn't ask about, but did bring up): here, instead of there being multiple reasonable things you could mean, it's hard to think of anything reasonable you could mean. Which is probably why this is the only case that's changed recently (see issue 9583), rather than being the same since the days when Python added __nonzero__.

    0 讨论(0)
提交回复
热议问题