Answering my own follow-on question which sort of answers the original.
To recap / generalize:
The OP is asking "Why is the lambda applied to the numpy array as a whole object when I expected it to be applied element-wise?"
My followup asks "Why are some lambda applied as a whole while others are applied element_wise?"
The TL;DR answer is that the lambda always treats the numpy array as a whole object - a regular argument to a regular function - but the operator used inside the body of the lambda (or function, or wherever) may be overridden by numpy ndarray to work element-wise, and the == operator is such and operator.
In my example it's the == operator. I tracked down the override for this and unfortunately the official numpy documentation of the override is not much help:
numpy.ndarray.eq method
ndarray.eq(value, /) Return self==value.
(fwiw, I know this is the documenation for == because the equivalency of operators to special method names is defined in this python reference)
The correct answer required more digging - I found it in the numpy documentation of the numpy.equal function:
numpy.equal numpy.equal(x1, x2, /, out=None, *, where=True,
casting='same_kind', order='K', dtype=None, subok=True[, signature,
extobj]) = <ufunc 'equal'>
Return (x1 == x2) element-wise.
The == operator is applied element-wise!
Hence in my first lambda
lambda x: x == "ccc", x does indeed hold the entire ndarray, but the == is applied to each element returning a new ndarray
Again the numpy.equal doc makes this clear:
Returns: out: ndarray or scalar
Output array, element-wise comparison
of x1 and x2. Typically of type bool, unless dtype=object is passed.
This is a scalar if both x1 and x2 are scalars.
x1 and x2 are the args, so that we're comparing x1 == x2. In our case, x1 is x so the full ndarray - not scalar - so the result is an ndarray.
You may be wondering why how it treats "ccc" (which is assigned to the x2 parameter), the doc says:
Parameters
x1, x2 array_like
Input arrays. If x1.shape != x2.shape,
they must be broadcastable to a common shape (which becomes the shape
of the output).
So x2 (our "ccc") is supposed to be array_like, but numpy will, if it can, broadcast it to the same shape as x1. And it will, because it can, as is documented in Numpy Broadcasting:
The simplest broadcasting example occurs when an array and a scalar
value are combined in an operation...
The result is equivalent to the previous example where b was an array.
We can think of the scalar b being stretched during the arithmetic
operation into an array with the same shape as a.
QED.
np.array([[-0.5, 0.2, 0.0], [4.2, 3.14, -2.7]]) < 0to be? Python doesn't know how to handle that kind of comparison.A < 0. This makes no sense. I think you want smth likeB = [assign(a) for a in x for x in A]or anything else.A<0produces a boolean array the same size asA. Pythonifonly works with a scalar boolean True/False. It's a simple either/or action. It can't work with multiple boolean values.