Python tilde унарный оператор как отрицательный numpy bool array

Должен быть простой вопрос, но я не могу найти ответ нигде. Оператор ~ в python документируется как побитовый оператор инверсии. Хорошо. Я заметил, по-видимому, шизофреническое поведение, хотя и остроумие:

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

В первых 4 примерах я вижу, что python реализует (как документировано) ~x = -(x+1), причем вход обрабатывается как int, даже если он булеван. Следовательно, для скалярного булева ~ не рассматривается как логическое отрицание. Не то, чтобы поведение было одинаковым в массиве numpy, определенном с булевыми значениями, с помощью типа int.

Почему ~ затем работает как логический оператор отрицания в булевом массиве (также обратите внимание: ~numpy.isfinite(numpy.inf) -> True?)?

Очень обидно, что я должен использовать not() на скаляре, но not() не будет работать, чтобы свести на нет массив. Тогда для массива я должен использовать ~, но ~ не будет работать, чтобы свести на нет скаляр...

Ответ 1

not реализуется с помощью специального метода __nonzero__, который требуется для возврата либо True, либо False, поэтому он не может дать требуемый результат. Вместо этого используется оператор ~, который реализуется специальным методом __not__. По той же причине вместо and и or используются & и |.

PEP 335, направленный на то, чтобы разрешить перегрузку логических операторов, но был отклонен из-за чрезмерных издержек (это, например, усложняло инструкции if). PEP 225 предлагает общий синтаксис для "элементарных" операторов, который обеспечил бы более общее решение, но был отложен. Похоже, что нынешняя ситуация, хотя и неудобная, не является достаточно болезненной, чтобы заставить меняться.

np.isfinite при вызове скаляра возвращает значение типа np.bool_, а не bool. np.bool_ - это также тип, который вы получаете при извлечении скалярного значения из массива bool dtype. Если вы используете np.True_ и np.False_ вместо True и False, вы получите согласованное поведение в ~.