Python: как установить значение подкласса int с помощью __setitem__

#python #immutability #subclassing

#python #неизменяемость #создание подклассов

Вопрос:

Я борюсь с реализацией setitem в подклассовом классе int.

Я хочу выполнять операции с битовыми фрагментами этого int (ограничено 32 битами). Я знаю, что существует доступный класс ‘BitVector’, но это работает не так, как можно было бы ожидать. Например:

 from BitVector import BitVector
foo = BitVector(intVal = 0x87654321)
print(f'[0:3] expected value = 0x1 returned value = {hex(int(foo[0:3]))}')
print(f'[4:7] expected value = 0x2 returned value = {hex(int(foo[4:7]))}')
print(f'[24:31] expected value = 0x87 returned value = {hex(int(foo[24:31]))}')
  

Вывод:

 [0:3] expected value = 0x1 returned value = 0x4
[4:7] expected value = 0x2 returned value = 0x3
[24:31] expected value = 0x87 returned value = 0x10
  

Проблема с BitVector заключается в том, что порядок битов меняется на противоположный (LSB слева, MSB справа), а также конечный бит не включен в срез ([0:3] возвращает три бита вместо четырех бит).

Поэтому я решил создать свой собственный класс для такого рода операций. (Я изменил порядок начала и окончания, чтобы написать [3:0] вместо [0:3], что является более распространенным обозначением) Getitem работает как ожидалось, но я не могу установить новое значение с помощью setitem.

 class bitfield(int):
def __str__(self):
    return "%d" % int(self)

def __repr__(self):
    return "bitfield(%d)" % int(self)

def __getitem__(self, sliceobj):
    if not isinstance( sliceobj, slice ): return (selfamp;(1<<sliceobj))>>sliceobj
    if(sliceobj.start < sliceobj.stop): raise ValueError( "slice error: start must be >= end" )
    if(sliceobj.start > 31): raise ValueError( "slice error: start > 31" )
    if(sliceobj.stop   > 31): raise ValueError( "slice error: end > 31" )
    start = sliceobj.start
    stop   = sliceobj.stop
    mask = (1<<((start 1) - stop))-1
    val = self amp; ( mask << stop)
    val = val>>stop
    return val
def __new__(cls, value):
    return int.__new__(bitfield, value)
def __setitem__(self, sliceobj, item):
    self.__int__ = 0x1234
    self = 0x1234
    #self.__int__ = int.__new__(bitfield, 0x1234)
    self = int.__new__(bitfield, 0x1234)
    self = self.__new__(bitfield, 0x1234)


# test __getitem__ 
a = bitfield(0xB2)
print(f'       {bin(a)}'     )
print(f'[0]    {bin(a[0  ])}')
print(f'[1]    {bin(a[1  ])}')
print(f'[1:0]  {bin(a[1:0])}')
print(f'[4:0]  {bin(a[4:0])}')
print(f'[7:1]  {bin(a[7:1])}')
print(f'[8:0]  {bin(a[8:0])}')
a = bitfield(0xbefa55aa)
print(f'       {hex(a)}'       )
print(f'[7:0]  {hex(a[ 7:0] )}')
print(f'[15:8] {hex(a[15:8] )}')
print(f'[23:16]{hex(a[23:16])}')
print(f'[31:24]{hex(a[31:24])}')

# test __setitem__
a = bitfield(0)
a[1] = 1
print(hex(a))
  

Вывод:

        0b10110010
[0]    0b0
[1]    0b1
[1:0]  0b10
[4:0]  0b10010
[7:1]  0b1011001
[8:0]  0b10110010
       0xbefa55aa
[7:0]  0xaa
[15:8] 0x55
[23:16]0xfa
[31:24]0xbe
       0b0   <-- expected 0x1234 !!!
  

Может ли кто-нибудь дать мне подсказку, как установить новое значение?

Ответ №1:

Может ли кто-нибудь дать мне подсказку, как установить новое значение?

Не наследуйте от int. Целые числа неизменяемы, вы не можете обновить их значение на месте.

Проблема с BitVector заключается в том, что порядок битов меняется на противоположный (LSB слева, MSB справа), а также конечный бит не включен в срез ([0:3] возвращает три бита вместо четырех бит).

Итак, вы говорите, что bitvector ведет себя как sequence бит? вместо того, чтобы вести себя, по сути, как ничто другое в языке?

Комментарии:

1. Можно ли сделать класс интерпретируемым как целое число, если он не наследуется от integer ? При попытке распечатать значение я получаю следующую ошибку: TypeError: 'bitfield' object cannot be interpreted as an integer . Ну, тот факт, что [0:1] совпадает с [0] в python, немного причудливый и нелогичный, вам не кажется?

2. «Возможно ли сделать класс интерпретируемым как целое число, если он не наследуется от integer ?» невозможно сделать его полностью взаимозаменяемым с целым числом, хотя его можно контекстуально преобразовать в целое число, используя __int__ и __index__ .

3. «Ну, тот факт, что [0:1] совпадает с [0] в python, немного причудливый и нелогичный, вам не кажется?» Обычно это не так, поэтому не факт, так что нет (во встроенных, я думаю, это происходит только с str тем, что несколько особенное и не в хорошем смысле)

4. «При попытке распечатать значение я получаю следующую ошибку: TypeError: 'bitfield' object cannot be interpreted as an integer. » %d Для форматирования строго требуется целое число. Не используйте это, если ваш тип не является фактическим целым числом.