2016-07-08 109 views
15

Ho appena scoperto il bitwise complement unary operation in Python tramite this question e ho cercato di creare un'applicazione vera e propria, e in caso contrario, per determinare se è generalmente sicuro sovraccaricare il operatore (ignorando il metodo __invert__) per altri usi. L'esempio fornito nella domanda non riesce con un TypeError e il link fornito sembra piuttosto intimidatorio. Ecco alcuni giocherellare in giro per vedere ~ in uso:Applicazioni di '~' (tilde) operator in 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) 

Esistono eventuali esempi di validi casi d'uso di questo operatore che dovrei essere a conoscenza? E anche se ci sono, è generalmente accettabile ignorare questo operatore per tipi diversi da int?

+6

In NumPy/panda, viene utilizzato per elementwise confronto di array. Ad esempio, se "arr = [True, False, True]', '~ arr' restituisce' [False, True, False] '. – ayhan

+0

@ayhan è bello, quindi applica una regola di casting? Sembra che funzioni anche per gli array di interi, ma si scompone quando si combinano 'int's e' bool's: '~ np.array ([1, 0, -1, True, False]) -> array ([ -2, -1, 0, -2, -1]) '. Potrebbe essere usato come un trucco funky per convertire i valori di 'bool' in valori' int' però: '~~ (np.array ([True, False] + [1])) [: - 1] -> array ([1 , 0]) ' – Alec

+1

@Alec O avete una matrice di' bool's o un array di 'int's. Mescolando 'bool's e' int's si ottiene una matrice 'int'. – Bakuriu

risposta

12

I casi di utilizzo standard per il bit NOT sono operazioni bit per bit, come AND bit a bit &, l'OR bit a bit |, il bit XOR ^ e bitwise spostando << e >>. Sebbene siano usati raramente in applicazioni di livello superiore, ci sono ancora alcune volte in cui è necessario eseguire manipolazioni bit a bit, ecco perché sono lì.

Ovviamente, è possibile sovrascriverli per i tipi personalizzati e, in generale, non è necessario seguire alcuna semantica specifica quando lo si fa. Basta scegliere ciò che ha senso per il tuo tipo e ciò che ancora si adatta in qualche modo all'operatore.

Se l'operazione è oscura e meglio spiegata con una o due parole, è necessario utilizzare un metodo standard. Ma ci sono alcune situazioni, specialmente quando si lavora con tipi correlati al numero, che potrebbero avere alcune operazioni di tipo matematico che si adattano agli operatori bit a bit, e come tali vanno bene per utilizzarle.

Proprio come si sovrascriveranno gli operatori standard come + e - solo per operazioni significative, si dovrebbe provare a fare lo stesso per gli operatori bit a bit.


Il motivo ~~True, ~~False ti dà (1, 0) è perché il tipo bool non definisce la propria __invert__ funzionamento. Tuttavia, lo int sì; e bool è in realtà un sottotipo di int. Pertanto, bool eredita effettivamente la logica di tutti gli operatori bit a bit e aritmetici. Ecco perché True + True == 2 ecc

+0

Questo ha senso! Quindi '' 'ha qualche somiglianza con la parola chiave' not'? Le mie indagini iniziali mi portano a credere che 'not' non sia mappato a' ~ 'e si applica solo ai valori booleani. – Alec

+1

Sì, hai ragione. 'not' è un operatore booleano NOT mentre' ~ 'è un operatore NOT bit a bit. L'implementazione del bitwise '~' non influirà sul risultato dall'uso della parola chiave 'not'. 'not x' in generale è equivalente a' not bool (x) 'che chiama invece il metodo speciale' __bool__' (che deve restituire un 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?

In genere, non si vuole sovraccaricare l'operatore ~ solo perché è divertente. Rende difficile la lettura. Ma a volte, tale sovraccarico per tipi diversi da int ha senso. Take a look at how SQLAlchemy puts it to good use.

+0

È interessante, quindi SQLAlchemy lo usa come sostituto dell'operazione 'NOT IN' sulle colonne? – Alec

+3

È un operatore 'NOT', non un operatore' NOT IN'. – SuperSaiyan

+1

Ah, non avevo letto abbastanza attentamente il link. Grazie per la correzione! – Alec

2

È possibile utilizzare l'operatore in combinazione con l'operatore di negazione (-) per incrementare un numero per 1. Ad esempio:

x = 5 
assert -~x == 6 

Questo è l'unico modo pratico che abbia mai utilizzato l'operatore ~. Qualsiasi altro modo è usato per qualsiasi cosa al di fuori dei numeri, è generalmente dipendente dal contesto e spesso aggiunge un livello di complessità alla comprensione del codice. Per le lingue come C++, Swift, Ruby, ecc. È possibile sovraccaricare questo operatore per indicare qualsiasi cosa che a volte rende il codice più difficile da digerire rapidamente

+4

'- ~ x' (o il suo amico' ~ -x') deve essere uno degli usi meno utili – harold

+0

@harold questo è forse vero, ma non ho mai usato alcuna altra variante che è più utile di quello che ho postato . Puoi suggerire un altro? – smac89

+0

E qui pensavo che l'incremento sul posto fosse contro le regole in python :) In realtà penso di averlo già visto in esempi di golf in codice prima di menzionarlo (non che il caso di utilizzarlo in codice leggibile sia migliorato da quello osservazione!) – Alec

2

È comunemente utilizzato in code golf come collegamento per alcune cose, come l'utilizzo ~x anziché -x-1 o ~my_bool anziché not my_bool.

0

Come altri hanno già detto, può essere davvero bello quando si attraversano le liste.

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

Date un'occhiata a un esempio che ruota una matrice senso orario di 90 gradi:

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] 

(Questo frammento è stato preso da here)