Приложения оператора ~ ~ (тильда) в Python

Я только что обнаружил поразрядное дополнение унарной операции в Python через этот вопрос и пытался с фактическим приложением для него, а если нет, определить, безопасно ли вообще перегружать оператора (путем переопределения метода __invert__) для других целей. Пример, приведенный в вопросе, терпит неудачу с TypeError, а ссылка кажется довольно запугивающей. Здесь некоторые возились, чтобы увидеть ~ в использовании:

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?

Ответы

Ответ 1

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

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

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

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


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

Ответ 2

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

Как правило, вы не хотите перегружать оператор ~ только потому, что это весело. Это затрудняет чтение. Но иногда такая перегрузка для типов, отличных от int, имеет смысл. Посмотрите, как SQLAlchemy хорошо использует его.

Ответ 3

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

x = 5
assert -~x == 6

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

Ответ 4

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

Ответ 5

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

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]

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