15

Я только что открыл bitwise complement unary operation в Python через this question и пытался создать для него фактическое приложение, а если нет, определить, безопасно ли вообще перегружать оператора (путем переопределения метода __invert__) для других целей. Пример, приведенный в вопросе, терпит неудачу с TypeError, а предоставленный link кажется довольно устрашающим. Вот некоторые пустячный вокруг, чтобы увидеть ~ в использовании:Приложения оператора '~' (tilde) в Python

from bitstring import BitArray 

x = 7 

print(~x) 
# -8 

print(BitArray(int=x, length=4).bin) 
# '0111' 

print(BitArray(int=~x, length=4).bin) 
# '1000' 

print(~~True, ~~False) 
# 1 0 

for i in range(-100, 100): 
    assert i + ~i == -1 
    assert i^~i == -1 
    assert bool(i) == ~~bool(i) 

Есть ли какие-либо примеры допустимых сценариев использования для этого оператора, что я должен быть в курсе? И даже если есть, допустимо ли вообще переопределять этот оператор для типов, отличных от int?

+6

В Numpy/панд, он используется для поэлементно сравнение массивов. Например, если 'arr = [True, False, True]', '~ arr' возвращает' [False, True, False] '. – ayhan

+0

@ Айхан, это круто, поэтому оно применяет правило кастинга? Похоже, он работает и для массивов ints, но разбивается при объединении 'int' и 'bool': '~ np.array ([1, 0, -1, True, False]) -> array ([ -2, -1, 0, -2, -1]). Может использоваться как фанковый трюк для преобразования значений 'bool' в значения' int', хотя: '~~ (np.array ([True, False] + [1])) [: - 1] -> array ([1 , 0]) ' – Alec

+1

@Alec Либо у вас есть массив' bool 'или массив' int '. Смешивание 'bool' и 'int' дает массив 'int'. – Bakuriu

ответ

12

Стандартные случаи использования для побитового NOT оператора являются битовые операции, так же, как побитовое И &, побитового ИЛИ |, побитового XOR ^ и побитового сдвига << и >>. Хотя они редко используются в приложениях более высокого уровня, все же есть моменты, когда вам нужно выполнять побитовые манипуляции, поэтому они есть.

Конечно, вы можете перезаписать их для пользовательских типов, и в целом вы не обязаны следовать какой-либо определенной семантике при этом. Просто выберите то, что имеет смысл для вашего типа и что по-прежнему подходит для оператора.

Если операция неясна и лучше объясняется словом или двумя, тогда вместо этого вы должны использовать стандартный метод. Но есть некоторые ситуации, особенно при работе с числовыми типами, которые могут иметь некоторые математические операции, которые соответствуют побитовым операторам, и, как таковые, могут их использовать.

Как и для стандартных операторов, таких как + и - только для значимых операций, вы должны попытаться сделать то же самое для побитовых операторов.


~~True, ~~False Причина дает (1, 0) потому, что bool тип не определяет свою собственную __invert__ операции. Однако int делает; и bool на самом деле является подтипом int. Таким образом, bool фактически наследует логику всех побитовых и арифметических операторов. Вот почему True + True == 2 и т.д.

+0

Это имеет смысл! Так что '' 'имеет какое-либо сходство с ключевым словом' not'? Мои первоначальные исследования привели меня к мысли, что 'not' не сопоставляется с' ~ 'и только действительно относится к логическим значениям. – Alec

+1

Да, ты прав. 'not' является логическим оператором NOT, а' ~ 'является побитовым оператором NOT. Реализация побитового '~' не повлияет на результат использования ключевого слова 'not'. 'not x' в общем случае эквивалентен' not bool (x) ', который вместо этого вызывает специальный метод' __bool__' (который должен вернуть bool btw.). – poke

6

Are there any examples of valid use-cases for this operator that I should be aware of? And even if there are, is it generally acceptable to override this operator for types other than int?

Как правило, вы не хотели бы перегружать оператор ~ только потому, что это весело. Это затрудняет чтение. Но иногда такая перегрузка для типов, отличных от int, имеет смысл. Take a look at how SQLAlchemy puts it to good use.

+0

Это интересно, поэтому SQLAlchemy использует его как замену для операции «NOT IN» на столбцах? – Alec

+3

Это оператор 'NOT', а не оператор' NOT IN'. – SuperSaiyan

+1

Ах, я не читал ссылку достаточно внимательно. Спасибо за исправление! – Alec

2

Вы можете использовать этот оператор в сочетании с оператором отрицания (-) для увеличения числа на 1. Например:

x = 5 
assert -~x == 6 

Это единственный практический способ, которым я когда-либо использовал оператор ~. Любой другой способ, который он использует для чего угодно, кроме чисел, обычно зависит от контекста и часто добавляет уровень сложности в понимание кода. Для языков, таких как C++, Swift, Ruby, и т.д., вы можете перегрузить этот оператор, чтобы означать все, что иногда делает код труднее переваривается быстро

+4

'- ~ x' (или его друг' ~ -x') должно быть одним из наименее полезных применений. – harold

+0

@harold это, пожалуй, правда, но я никогда не использовал другой вариант, который более полезен, чем то, что я опубликовал , Можете ли вы предложить любой другой? – smac89

+0

И здесь я думал, что приращение на месте было против правил в python :) Я действительно думаю, что я видел это в примерах гольфа для кода до этого момента, когда вы упомянули об этом (не то, чтобы случай использования его в читаемом коде улучшался наблюдение!) – Alec

2

Это обычно используется в code golf в качестве ярлыка для нескольких вещей, таких как использование ~x, а не -x-1 или ~my_bool, а не not my_bool.

0

Как уже упоминалось, он может быть очень аккуратным при переходе по спискам.

for i in range(n): 
    mylist[~i] 
    #much prettier than mylist[-i-1] 

Посмотрите на пример, который вращает матрицу по часовой стрелке на 90 градусов:

def rotate(A): 
    n = len(A) 
    for i in range(n/2): 
     for j in range(n-n/2): 
      A[i][j], A[~j][i], A[~i][~j], A[j][~i] = \\ 
        A[~j][i], A[~i][~j], A[j][~i], A[i][j] 

(Этот фрагмент был взят из here)

Смежные вопросы