True
has a value of 1 in Python. Bit-inverting (~) a binary 1 (...0001) gives you ...1110. Since negative integers are represented by two's compliment, that's a value of -2.
Logical and
returns its left operand if it's false, the right operand otherwise. (True
is never false, obviously.)
Bitwise &
, on the other hand, works on the individual bits. ...0001 & ...1110 have no 1 bits in the same position so they're all zeros in the result.
I was just surprised that a numpy array with dtype=bool acts differently with literal bool
Each Python type can implement an operator's methods with special method names. (Like .__invert__()
for ~
). But and
, or
, and not
don't have these hooks, so often &
, |
, and ~
are used instead. For int
s the implementation is bitwise, but other types can interpret operators however they want.
Note that bool
is a subclass of int
in Python, so it has the same operators as int
. But you were operating on a numpy.ndarray
, not on its individual components, so Python uses the ndarray
implementation of the operators, which are not the same as bool
when dtype=bool
.