1

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?

3 Answers 3

4

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'
Sign up to request clarification or add additional context in comments.

7 Comments

This seems pretty nice, but can I get the low and high out as an independent object? That is extract them from out of the class? Or should I just recreate the property out of the class giving bound methods to the property function?
You mean to pass them by reference so others can update them without having a reference to the whole Control object? I am afraid not, unless you wrap them into another mutable object.
That's a problem for me... 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...
@immortal: That would require mutable integers in any case, and can't work (postably) with the GC's bookeeping and the current object layout. Also, unless you radically altered Python's semantics or avoided plain assignment, you'd need cooperation from the dictionary. In short, it's not really possible. Don't try to program as in Python as if it was C. Tell us what you're actually trying to do.
@delnan I've pretty much told you what I want. I have several "words" which are named each, and each byte of these words has a name of its own. I wanted to create a dict that would allow me access directly to the requested byte without addressing it through the word that contains it. I wondered if there's a Python class that might have similar behavior so I came here.
|
1

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.

Comments

-1

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.

2 Comments

The problem here is that the parent object isn't continuous in memory and this solution isn't truly simulating my given example. It will NOT work for integers, not without overloading the assignment operator of the parent object to split the input between the child objects and working something out when you try to retrieve the value to connect the two child objects into one again... I updated my question to emphasize this.
Maybe you are looking for property (docs.python.org/library/functions.html#property) ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.