#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
Для форматирования строго требуется целое число. Не используйте это, если ваш тип не является фактическим целым числом.