Я пытаюсь создать объект в python, который состоит из меньших объектов. Каждый из объектов имеет свой собственный смысл - каждый из меньших объектов и всего объекта в целом. Проблема в том, что я хочу, чтобы каждый из трех объектов был, по-видимому, независимо адресуемым и работал как автономные объекты, и этого довольно сложно достичь. Эту проблему можно было бы легко решить в C с помощью указателей, но мне сложно имитировать это поведение в Python.
Пример ситуации, о которой я говорю, можно увидеть в управляющем слове конечного автомата: управляющее слово (2 байта) имеет смысл в целом и должно быть доступно (или передано) в качестве объекта, но каждый из байтов в управляющем слове имеет свой собственный смысл и должен быть установлен и доступен независимо.
В C я бы сделал что-то вроде:
unsigned short control_word_memory;
unsigned short *control_word = &control_word_memory;
unsigned char *low_byte = &control_word_memory;
unsigned char *high_byte = low_byte + 1;
И, таким образом, я мог бы легко получить доступ к каждому *control_word
и не будет вынужден поддерживать сложную логику, чтобы синхронизировать все 3 объекта - назначение в *control_word
одновременно обновляло как low_byte
и high_byte
, и любое обновление для объектов байта будет влиять на control_word
.
Есть ли простой способ добиться такого поведения в Python?
Две альтернативы:
Вы можете использовать C и оболочку CPython... Или вы можете использовать свойства:
class Control(object):
def __init__(self, word=0):
self.word = word
def get_low(self):
return self.word & 0xFF
def set_low(self, x):
self.word &= 0xFF00
self.word |= x & 0xFF
def get_high(self):
return (self.word >> 8) & 0xFF
def set_high(self, x):
self.word &= 0x00FF
self.word |= (x & 0xFF) << 8
low = property(get_low, set_low)
high = property(get_high, set_high)
теперь вы можете использовать его как:
In [3]: c = Control(0x1234)
In [4]: hex(c.low)
Out[4]: '0x34'
In [5]: hex(c.high)
Out[5]: '0x12'
In [6]: c.low=56
In [7]: hex(c.word)
Out[7]: '0x1238'
In [8]: c.low=0x56
In [9]: hex(c.word)
Out[9]: '0x1256'
In [10]: c.high = 0x78
In [11]: hex(c.word)
Out[11]: '0x7856'
In [12]: c.word = 0xFE0A
In [13]: c.low
Out[13]: 10
In [14]: c.high
Out[14]: 254
с учетом дальнейшего объяснения из комментариев:
Я хотел бы иметь возможность делать что-то вроде
c = Control(); device_control = dict(device_control = c.word, device_read_permissions = c.low, device_write_permissions = c.high)
c = Control(); device_control = dict(device_control = c.word, device_read_permissions = c.low, device_write_permissions = c.high)
а затем доступ к каждому компоненту через dict...
вам совсем не нужен словарь, вы можете заставить наш класс Control
вести себя как словарь, реализующий dict
протокол (у него есть довольно много методов, вы можете оставить те, которые вы не используете, если хотите):
class DictControl(Control):
def __len__(self):
return 3
def __getitem__(self, k):
if k == 'device_control':
return self.word
elif k == 'device_read_permissions':
return self.low
elif k == 'device_write_permissions':
return self.high
else: raise KeyError
def __setitem__(self, k, v):
if k == 'device_control':
self.word = v
elif k == 'device_read_permissions':
self.low = v
elif k == 'device_write_permissions':
self.high = v
else: raise KeyError
и затем используйте его следующим образом:
In [2]: c = DictControl()
In [3]: c.word = 0x1234
In [4]: hex(c['device_control'])
Out[4]: '0x1234'
In [5]: c['device_read_permissions'] = 0xFF
In [6]: c.low
Out[6]: 255
In [7]: c.high = 0xAA
In [8]: c['device_write_permissions']
Out[8]: 170
In [9]: hex(c.word)
Out[9]: '0xaaff'
Чтобы получить доступ к частям и для извлечения объектов, вы должны создать некоторые "объекты-части".
class Part(object):
def __init__(self, ref, bitstart, bitlen):
self.ref = ref
self.bitstart = bitstart
self.bitlen = bitlen
self.mask = ((1 << bitlen) - 1) << bitstart
def set(self, value):
self.ref.word = self.ref.word & ~self.mask | ((value << self.bitstart) & self.mask)
def get(self):
return (self.ref.word & self.mask) >> self.bitstart
class Control(object):
def __init__(self, word=0):
self.word = word
self.low = Part(self, 0, 8)
self.high = Part(self, 8, 8)
Непроверенный, но должен дать вам представление о том, как действовать.
Если я правильно вас понимаю, это очень легко достичь в Python.
my_obj1 = Object1()
my_obj2 = Object2()
my_parent_obj = Object3()
my_parent_obj.obj1 = my_obj1
my_parent_obj.obj2 = my_obj2
Теперь экземпляры object1 и object2 адресуются независимо друг от друга как my_obj1
и как часть родительского объекта как my_parent_obj.obj1
. Любое изменение, которое вы делаете на один, повлияет на другое.
property
( docs.python.org/library/functions.html#property )?
low
иhigh
как самостоятельный объект? То есть извлечь их из класса? Или я должен просто воссоздать свойство из класса, предоставив связанные методы для функции свойства?Control
? Боюсь, что нет, если вы не оберните их в другой изменяемый объект.