15

Właśnie odkryłem bitwise complement unary operation w Pythonie poprzez this question i próbowałem wymyślić dla niego konkretną aplikację, a jeśli nie, aby określić, czy ogólnie jest bezpieczne przeciążenie operator (poprzez przesłanianie metody __invert__) do innych zastosowań. Przykład podany w pytaniu kończy się niepowodzeniem z TypeError, a dostarczony link wydaje się być dość onieśmielający. Oto niektóre fiddling zobaczyć ~ użytkowej:Zastosowania operatora '~' (tyldy) w Pythonie

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) 

Czy istnieją jakieśprzykłady poprawnych przypadków użycia dla tego operatora, który powinien być świadomy? A nawet jeśli tak jest, czy ogólnie dopuszczalne jest zastąpienie tego operatora typami innymi niż int?

+6

W NumPy/pand, jest on stosowany do elementwise porównanie tablic. Na przykład, jeśli 'arr = [True, False, True]', '~ arr' zwraca' [False, True, False] '. – ayhan

+0

@ayhan to fajne, więc stosuje regułę castingu? Wygląda na to, że działa także dla tablic ints, ale zrywa się, gdy łączymy 'int's i' bool's: '~ np.array ([1, 0, -1, prawda, fałsz]) -> array ([ -2, -1, 0, -2, -1]) '. Może być użyta jako funkowa sztuczka do konwersji wartości 'bool' na' int' wartości: '~~ (np.array ([prawda, fałsz] + [1])) [: - 1] -> tablica ([1 , 0]) ' – Alec

+1

@Alec Albo masz tablicę' bool's lub tablicę 'int's. Mieszanie 'bool's i' int's daje tablicę 'int'. – Bakuriu

Odpowiedz

12

Standardowe przypadki użycia dla NOT bitowego operatora są operacje bitowe, podobnie jak bitowego AND &, bitowe OR |, XOR mnożenie ^ i bitowe zmieniającym << i >>. Chociaż są rzadko używane w aplikacjach na wyższym poziomie, wciąż istnieją pewne sytuacje, w których trzeba wykonywać operacje bitowe, dlatego właśnie one tam są.

Oczywiście można je zastąpić dla typów niestandardowych, a generalnie nie musisz przestrzegać żadnej konkretnej semantyki. Po prostu wybierz, co ma sens dla Twojego typu i co jeszcze pasuje do operatora w jakiś sposób.

Jeśli operacja jest niejasna i lepiej wyjaśniona słowem lub dwoma, należy zamiast tego użyć standardowej metody. Ale są pewne sytuacje, szczególnie podczas pracy z typami powiązanymi z liczbami, które mogą mieć pewne operacje matematyczne, które pasują do operatorów bitowych i jako takie są w porządku, aby z nich korzystać.

Tak samo, jak nadpisanie standardowych operatorów, takich jak + i -, tylko w celu wykonywania sensownych operacji, należy spróbować zrobić to samo dla operatorów bitowych.


Powodem ~~True, ~~False daje (1, 0) dlatego typ bool nie definiuje własną __invert__ operację. Jednak robi to int; i bool jest faktycznie podtypem int. Tak więc bool faktycznie dziedziczy logikę wszystkich operatorów bitowych i arytmetycznych. Dlatego True + True == 2 itp

+0

To ma sens! Czy też "~" ma jakiekolwiek podobieństwo do słowa kluczowego 'not'? Moje wstępne badania doprowadziły mnie do przekonania, że ​​'not' nie mapuje na' ~ 'i odnosi się tylko do wartości logicznych. – Alec

+1

Tak, masz rację. 'not' jest boolowskim operatorem NOT, podczas gdy' ~ 'jest bitowym operatorem NOT. Implementacja bitowego '~' nie wpłynie na wynik użycia słowa kluczowego 'not'. 'not x' w ogóle jest równoważne' not bool (x) ', które wywołuje zamiast tego specjalną metodę' __bool__' (która musi zwrócić wartość 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?

Zazwyczaj nie chcą przeciążać operatora ~ tylko dlatego, że to jest zabawa. To utrudnia czytanie. Ale czasami takie przeciążenie dla typów innych niż int ma sens. Take a look at how SQLAlchemy puts it to good use.

+0

To interesujące, więc SQLAlchemy używa go jako zamiennika dla operacji "NOT IN" w kolumnach? – Alec

+3

Jest to operator "NOT", a nie operator "NOT IN". – SuperSaiyan

+1

Ach, nie przeczytałem linku wystarczająco uważnie. Dzięki za poprawienie! – Alec

2

Można użyć tego operatora w połączeniu z operatorem negacji (-), aby zwiększyć liczbę o 1. Na przykład:

x = 5 
assert -~x == 6 

jest to jedyny praktyczny sposób, jaki kiedykolwiek użył operatora ~. Jakikolwiek inny sposób, w jaki jest używany do niczego oprócz liczb, jest na ogół zależny od kontekstu i często dodaje poziom złożoności do zrozumienia kodu. W przypadku języków takich jak C++, Swift, Ruby itd. Można przeciążać ten operator, co oznacza cokolwiek, co czasami powoduje, że kod jest trudny do strawienia.

+4

'- ~ x' (lub jego przyjaciel' ~ -x') musi być jednym z najmniej użytecznych zastosowań – harold

+0

@harold jest to prawdopodobnie prawda, ale nigdy nie użyłem żadnego innego wariantu, który jest bardziej przydatny niż to, co napisałem . Czy możesz zaproponować coś innego? – smac89

+0

I tutaj myślałem, że inkrementacja jest niezgodna z regułami w pythonie :) Właściwie myślę, że widziałem to w przykładach z kodem golfowym, zanim o tym wspomniałeś (nie, że poprawiono to w przypadku użycia go w czytelnym kodzie) obserwacja!) – Alec

2

Jest powszechnie używany w code golf jako skrót do kilku rzeczy, takich jak używanie ~x zamiast -x-1 lub ~my_bool zamiast not my_bool.

0

Jak wspominali inni, może być naprawdę niezła w przypadku przechodzenia list.

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

Spójrz na przykład, w którym obraca się w kierunku ruchu wskazówek zegara matrycowy o 90 stopni:

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] 

(ten fragment został wzięty z here)