2016-01-18 1 views
30

In meinem Programm (geschrieben in Python 3.4) Ich habe eine Variable, die verschiedenen Flags enthält, so zum Beispiel:Schaltet ein einzelnes Bit in Flags sicher mit Python-Ganzzahlen mit variabler Länge?

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

andere Flagge Einstellung leicht mit

status |= FLAG_FOUR 

Aber was, wenn ich getan werden kann, explizit eine Flagge löschen wollen? Ich würde tun

status &= ~FLAG_THREE 

Ist dieser Ansatz sicher? Da die Größe einer Ganzzahl in Python nicht definiert ist, was ist, wenn status und FLAG_THREE sich in der Größe unterscheiden?

(status Bedürfnisse ein Bit-Feld sein, weil ich diesen Wert für ein Hardware-Protokoll benötigen.)

Antwort

14

Sie sollten mit diesem Ansatz sicher sein, ja.

~ in Python wird einfach als -(x+1) (vgl der CPython source) umgesetzt und negative Zahlen behandelt werden, als ob sie irgendeine erforderliche Anzahl von 1s haben den Start Polsterung. Von der Python Wiki:

Natürlich verwendet Python keine 8-Bit-Nummern. Es BENUTZTE, um zu verwenden, aber viele Bits waren nativ zu Ihrer Maschine, aber da das nicht tragbar war, ist es vor kurzem zu der Verwendung einer INFINITE Zahl der Bits gewechselt. Somit wird die Zahl -5 durch bitweise Operatoren behandelt, als ob sie geschrieben wäre "... 1111111111111111111011".

Mit anderen Worten, mit bitweise und & Sie garantiert sind, dass dieser 1s polstern wird die Länge der ~FLAG (eine negative ganze Zahl) auf die Länge der status. Zum Beispiel:

100000010000 # status 
&  ~10000 # ~FLAG 

als

100000010000 
& 111111101111 

= 100000000000 # new status 
behandelt

Dieses Verhalten in einem Kommentar in der Quelle here beschrieben.

+0

Haben Sie versucht zu finden, wo dieses Verhalten in den offiziellen Python-Dokumenten definiert ist? – jfs

+0

Ich habe die Dokumentationsseiten durchgesehen, konnte aber den Hauptpunkt über das skizzierte Verhalten nicht so klar finden wie auf den Wiki-Seiten. Es ist sehr wahrscheinlich, dass ich etwas übersehen habe, natürlich. –

11

ein Flag Räumungsarbeiten mit

status &= ~FLAG_THREE 

weil Python diese negiert Werte als negativ behandelt:

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

So kann der & Operator entsprechend handeln und das gewünschte Ergebnis unabhängig von der Länge der Operanden liefern, also 0b11111111111111111111111111111111111111111111111111111111111 & ~1 funktioniert gut, obwohl der linke Operand bifier ist als der rechte.

In der anderen Richtung (RH länger als LH), funktioniert es trotzdem, denn eine Überzahl von 1 Bits spielt keine Rolle.