Подтвердить что ты не робот

Разблокирует ли один бит флагов с помощью целых чисел переменной длины Python?

В моей программе (написанной на Python 3.4) у меня есть переменная, которая содержит различные флаги, например:

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

Установка другого флага может быть легко выполнена с помощью

status |= FLAG_FOUR

Но что, если я явно хочу очистить флаг? Я бы сделал

status &= ~FLAG_THREE

Безопасен ли этот подход? Поскольку размер целого числа в Python не определен, что делать, если status и FLAG_THREE отличаются по размеру?

(status должно быть поле бит, потому что мне нужно это значение для аппаратного протокола.)

4b9b3361

Ответ 1

Вы должны быть в безопасности, используя этот подход, да.

~ в Python просто реализуется как -(x+1) (см. источник CPython), а отрицательные числа обрабатываются так, как будто они имеет любое требуемое количество 1s, заполняющее начало. Из Python Wiki:

Конечно, Python не использует 8-битные числа. Он ИСПОЛЬЗУЕТСЯ использовать, однако, многие биты были родными для вашей машины, но поскольку он был не переносимым, он недавно переключился на использование количества бит INFINITE. Таким образом, число -5 обрабатывается побитовыми операторами, как если бы оно было написано "... 1111111111111111111011".

Другими словами, с побитовым и & вам гарантировано, что эти 1s будут заполнять длину ~FLAG (отрицательное целое число) до длины status. Например:

  100000010000 # status
&       ~10000 # ~FLAG

рассматривается как

  100000010000
& 111111101111

= 100000000000 # new status 

Это поведение описано в комментарии в источнике здесь.

Ответ 2

Удаление флага выполняется с помощью

status &= ~FLAG_THREE

потому что Python обрабатывает эти отрицательные значения как отрицательные:

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

Таким образом, оператор & может действовать соответствующим образом и выводить желаемый результат независимо от длины операндов, поэтому 0b11111111111111111111111111111111111111111111111111111111111 & ~1 работает нормально, хотя левый операнд отличается от правого.

В другом направлении (RH длиннее LH), тем не менее, он работает, поскольку наличие избыточного количества битов 1 не имеет значения.