Как найти позицию нескольких бит в байте на python?

Всем привет. Есть число в hex 0x11. Мне необходимо перевести это число в bin и извлечь три флага. flag_1 7й бит, flag_2 4-6 биты, flag_3 0-3 биты. Понимаю как сделать через строки это, но не считаю это верным решением. Нужно применять битовые сдвиги и т.п., но не понимаю как. Прошу помощи. Пример как делаю через строки

num_hex = '11'
str_1 = bin(int(num_hex,16))
while len(str_1) < 8:
    str_1 = '0' + str_1
flag_2 = str_1[4:7]
flag_1 = str[7]
flag_2 = int(flag_2)
flag_1 = int(flag_1)

Ответы (2 шт):

Автор решения: CrazyElf

Например, так, хотя можно и наоборот сначала делать сдвиг, потом &, но так вроде нагляднее, какие биты берутся:

# flag_1 7й бит, flag_2 4-6 биты, flag_3 0-3 биты
num_hex = '11'
num = int(num_hex,16)
print(bin(num))
flag_1 = ((0b10000000) & num) >> 7
flag_2 = ((0b01110000) & num) >> 4
flag_3 = ((0b00001111) & num)
print(flag_1, flag_2, flag_3)

Вывод:

0b10001
0 1 1

Судя по выводу, вроде правильно.

Ну то есть суть в том, чтобы:

  • взять нужные биты по маске используя побитовое "и", т.е. &
  • убрать ненужные нули справа с помощью операции "сдвиг вправо", т.е. >>
→ Ссылка
Автор решения: eri
import ctypes
c_uint8 = ctypes.c_uint8

class Flags_bits(ctypes.BigEndianStructure):
    _fields_ = [
            ("flag_1", c_uint8, 1),
            ("flag_2", c_uint8, 3),
            ("flag_3", c_uint8, 4)
        ]

class Flags(ctypes.Union):
    _anonymous_ = ("b",)
    _fields_ = [("b", Flags_bits), ("asbyte", ctypes.c_char)]
    def __init__(self, hex=None):
        if hex:
            self.asbyte = bytes.fromhex(hex)
        else:
            self.asbyte = b'\x00'

flags = Flags('11')

print(flags.flag_1)
print(flags.flag_2)
print(flags.flag_3)

Если добавить низкоуровневых типов получается красивая высокоуровневая обертка. И сразу работает в обе стороны

flags.flag_3 = 3
print(flags.asbyte)

Flags_bits - структура которая режет байты на биты.

Flags - объединяет один байт со структурой

пс.байт можно заменить на число

Юнион можно не использовать чтоб не захламлять код тем чем не пользуетесь

flags = Flags_bits.from_buffer_copy(bytes.fromhex('11'))
print(flags.flag_1)
print(flags.flag_2)
print(flags.flag_3)
→ Ссылка