Enmascaramiento de bits en Python

Tengo un byte (de otro proveedor) donde las posibles máscaras de bits son las siguientes:

value1 = 0x01 value2 = 0x02 value3 = 0x03 value4 = 0x04 value5 = 0x05 value6 = 0x06 value7 = 0x40 value8 = 0x80

Puedo contar con UNO de value1 a value6 estando presente. Y entonces value7 puede o no puede ser establecido. value8 puede o no puede ser establecido.

Así que esto es legal: value2 | valor7 | value8 Esto no es legal: value1 | valor3 | valor7

Necesito averiguar si el valor 7 está establecido, el valor 8 está establecido y cuál es el valor restante.

Tengo el siguiente código de python. ¿Hay una manera más elegante de hacer esto?

value1 = 0x01 value2 = 0x02 value3 = 0x03 value4 = 0x04 value5 = 0x05 value6 = 0x06 value7 = 0x40 value8 = 0x80 def format_byte_as_bits(value): return format(value,'b').zfill(8) def mask_bits_on_byte(byte,mask): inverse_of_mask = mask ^ 0b11111111 return byte & inverse_of_mask def parse_byte(byte): value7_set = byte & value7 == value7 value8_set = byte & value8 == value8 byte = mask_bits_on_byte(byte,value7) byte = mask_bits_on_byte(byte,value8) base_value = byte return value7_set,value8_set,base_value # Example 1 byte = value3 | value7 value7_set,value8_set,base_value = parse_byte(byte) print("base_value = "+str(base_value)) print("value7_set = "+str(value7_set)) print("value8_set = "+str(value8_set)) print() # Output: # base_value = 3 # value7_set = True # value8_set = False # Example 2 byte = value5 value7_set,value8_set,base_value = parse_byte(byte) print("base_value = "+str(base_value)) print("value7_set = "+str(value7_set)) print("value8_set = "+str(value8_set)) print() # Output: # base_value = 5 # value7_set = False # value8_set = False # Example 3 byte = value1 | value7 | value8 value7_set,value8_set,base_value = parse_byte(byte) print("base_value = "+str(base_value)) print("value7_set = "+str(value7_set)) print("value8_set = "+str(value8_set)) # Output: # base_value = 1 # value7_set = True # value8_set = True 

EDITAR – I LOVE stackoverflow. Tantas respuestas útiles, tan rápido! ¡Ustedes son increíbles! Ojalá pudiera marcar todas las respuestas. ¡Pero al menos daré a todos un voto positivo!

EDIT2 – Basado en las respuestas a continuación, el código se simplifica a lo siguiente:

 value1 = 0x01 value2 = 0x02 value3 = 0x03 value4 = 0x04 value5 = 0x05 value6 = 0x06 value7 = 0x40 value8 = 0x80 def parse_byte(byte): return byte & value7, byte & 0x80, byte & 7 # Example 1 byte = value3 | value7 value7_set,value8_set,base_value = parse_byte(byte) print("base_value = "+str(base_value)) if value7_set: print("value7_set") if value8_set: print("value8_set") print() # Example 2 byte = value5 value7_set,value8_set,base_value = parse_byte(byte) print("base_value = "+str(base_value)) if value7_set: print("value7_set") if value8_set: print("value8_set") print() # Example 3 byte = value1 | value7 | value8 value7_set,value8_set,base_value = parse_byte(byte) print("base_value = "+str(base_value)) if value7_set: print("value7_set") if value8_set: print("value8_set") print() 

La mayoría de sus constantes de value* no son en realidad máscaras de bits, solo lo son value7 y value8 . Definiría otra máscara de bits para extraer los bits inferiores, por lo que tendría un total de tres máscaras de bits:

 mask0 = 0x07 mask1 = 0x40 mask2 = 0x80 

Ahora tu función se convierte en

 def parse_byte(byte): return byte & mask2, byte & mask1, byte & mask0 

No convertí los resultados a bool , no veo por qué debería ser necesario. Al verificar el valor devuelto con if , se convertirá implícitamente a bool todos modos.

También tenga en cuenta que

 format(value,'b').zfill(8) 

se puede simplificar a

 format(value,'08b') 

Dado un valor tal como:

 >>> x = 0b10001000 

Puedes averiguar si los bits superiores están configurados con:

 >>> bit8 = bool(x & 0b10000000) >>> bit7 = bool(x & 0b01000000) 

Para encontrar qué bit inferior está configurado, use un diccionario:

 >>> bdict = dict((1<>> bdict[x & 0b00111111] 4 

No necesitas las otras dos funciones:

 def parse_byte(byte): value7_set = byte & value7 == value7 value8_set = byte & value8 == value8 base_value = byte & 7 return value7_set,value8_set,base_value 

Es un poco verboso pero perfectamente bien. El único cambio que haría es simplificar parse_byte:

 def parse_byte(byte): value7_set = byte & value7 == value7 value8_set = byte & value8 == value8 base_value = mask_bits_on_byte(byte,value7 | value8) return value7_set,value8_set,base_value