2016-01-18 5 views
30

Nel mio programma (scritto in Python 3.4) Ho una variabile che contiene diverse bandiere, così per esempio:Si sta disabilitando un singolo bit in flags con gli interi Python di lunghezza variabile?

FLAG_ONE = 0b1 
FLAG_TWO = 0b10 
FLAG_THREE = 0b100 
status = FLAG_ONE | FLAG_TWO | FLAG_THREE 

Impostazione un'altra bandiera può facilmente essere fatto con

status |= FLAG_FOUR 

Ma cosa succede se io vuoi esplicitamente cancellare una bandiera? Lo farei

status &= ~FLAG_THREE 

Questo approccio è sicuro? Poiché la dimensione di un intero in Python non è definita, cosa succede se status e FLAG_THREE differiscono nelle dimensioni?

(status ha bisogno di essere un campo di bit, perché ho bisogno di questo valore per un protocollo hardware.)

risposta

14

Si dovrebbe essere sicuri utilizzando tale approccio, sì.

~ in Python è semplicemente implementato come -(x+1) (cfr la CPython source) ei numeri negativi sono trattati come se hanno qualsiasi numero di 1s imbottitura dall'inizio. Da Python Wiki:

Ovviamente, Python non utilizza numeri a 8 bit. USATO per usare comunque molti bit erano nativi per la vostra macchina, ma dal momento che era non portatile, è passato di recente a usare un numero INFINITO di bit. Quindi il numero -5 viene trattato da operatori bit a bit come se fosse scritto "... 1111111111111111111011".

In altre parole, con bit-e & avrete la garanzia che questi 1s sarà pad la lunghezza del ~FLAG (un numero intero negativo) alla lunghezza di status. Ad esempio:

100000010000 # status 
&  ~10000 # ~FLAG 

è trattato come

100000010000 
& 111111101111 

= 100000000000 # new status 

Questo comportamento è descritto in un commento nel sorgente here.

+0

Hai provato a trovare dove questo comportamento è definito nei documenti Python ufficiali? – jfs

+0

Ho dato un'occhiata alle pagine della documentazione ma non ho trovato il punto principale sul comportamento delineato chiaramente come nelle pagine wiki. È molto probabile che abbia trascurato qualcosa, ovviamente. –

11

Cancellazione di una bandiera funziona con

status &= ~FLAG_THREE 

perché Python tratta tali valori negati come negativa:

>>> ~1L 
-2L 
>>> ~1 
-2 
>>> ~2 
-3 

Così l'operatore & può agire in modo appropriato e fornire il risultato desiderato indipendentemente dalla lunghezza degli operandi, quindi 0b11111111111111111111111111111111111111111111111111111111111 & ~1 funziona bene anche se l'operando della mano sinistra è più grande di quello della mano destra.

Nella direzione opposta (RH più lunga di LH), funziona comunque, perché non è importante avere un numero in eccesso di 1 bit.

Problemi correlati