immortal
immortal

Reputation: 3188

Creating pythonic objects that share memory

I'm trying to create an object in python which is composed of smaller objects. Each of the objects has its own meaning - each of the smaller objects and the entire object as a whole. The problem is that I want each of the 3 objects to be seemingly independently addressable and to operate as standalone objects and this is rather difficult to achieve. This problem would be easy to solve in C using pointers but I find it difficult to simulate this behavior in Python.

An example to the situation I'm talking about could be seen in a control word of a state machine: The control word (2 bytes) has a meaning as a whole and needs to be accesses (or transferred) as an object, but each of the bytes in the control word has its own meaning and needs to be set and accessed independently.

In C I'd do something like:

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;

And thus I'd be able to access each of the elements easily and not be forced to maintain complex logic to keep all 3 objects in sync - an assignment into *control_word would update both low_byte and high_byte simultaneously, and any update to the byte objects will influence the control_word.

Is there a simple way to achieve this behavior in Python?

Upvotes: 1

Views: 147

Answers (3)

fortran
fortran

Reputation: 76057

Two alternatives:

You can use C and a CPython wrapper... Or you can use properties:

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)

now you can use it as:

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

given the further explanation from the comments:

I'd want to be able to do something like c = Control(); device_control = dict(device_control = c.word, device_read_permissions = c.low, device_write_permissions = c.high) and then access each component through the dict...

you don't need the dictionary at all, you can make our Control class to behave like a dictionary implementing the dict protocol (it has quite a few methods, you can leave out those that you are not using if you want):

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

and then use it like this:

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'

Upvotes: 4

glglgl
glglgl

Reputation: 91028

To access parts AND to extract the objects, you should create some "part objects".

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)

Untested, but should give you an idea how to proceed.

Upvotes: 1

Daniel Roseman
Daniel Roseman

Reputation: 599600

If I understand you correctly, this is extremely easy to achieve in Python.

my_obj1 = Object1()
my_obj2 = Object2()
my_parent_obj = Object3()
my_parent_obj.obj1 = my_obj1
my_parent_obj.obj2 = my_obj2

Now the object1 and object2 instances are addressable both independently as my_obj1 and as part of the parent object as my_parent_obj.obj1. Any change you make to one will affect the other.

Upvotes: -1

Related Questions