python tilde unary operator as negation numpy bool array
Should be a simple question, but I'm unable to find an answer anywhere. The ~
operator in python is a documented as a bitwise inversion operator. Fine. I have noticed seemingly schizophrenic behavior though, to wit:
~True -> -2
~1 -> -2
~False -> -1
~0 -> -1
~numpy.array([True,False],dtype=int) -> array([-2,-1])
~numpy.array([True,False],dtype=bool) -> array([False,True])
In the first 4 examples, I can see that python is implementing (as documented) ~x = -(x+1)
, with the input treated as an int even if it's boolean. Hence, for a scalar boolean, ~
is not treated as a logical negation. Not that the behavior is identical on a numpy array defined with boolean values by with an int type.
Why does ~
then work as a logical negation operator on a boolean array (Also notice: ~numpy.isfinite(numpy.inf) -> True
?)?
It is extremely annoying that I must use not()
on a scalar, but not()
won't work to negate an array. Then for an array, I must use ~
, but ~
won't work to negate a scalar...
Solution 1:
not
is implemented through the __nonzero__
special method, which is required to return either True
or False
, so it can't give the required result. Instead the ~
operator is used, which is implemented through the __not__
special method. For the same reason, &
and |
are used in place of and
and or
.
PEP 335 aimed to allow overloading of boolean operators but was rejected because of excessive overhead (it would e.g. complicate if
statements). PEP 225 suggests a general syntax for "elementwise" operators, which would provide a more general solution, but has been deferred. It appears that the current situation, while awkward, is not painful enough to force change.
np.isfinite
when called on a scalar returns a value of type np.bool_
, not bool
. np.bool_
is also the type you get when extracting a scalar value from an array of bool dtype. If you use np.True_
and np.False_
in place of True
and False
you will get consistent behaviour under ~
.