A Class for C structures in Python

Thomas Gagne tgagne at ix.netcom.com
Tue Aug 8 22:04:53 EDT 2000


Donn Cave wrote:

> Quoth Thomas Gagne <tgagne at ix.netcom.com>:
> ...
> | It would seem the pack and unpack methods are great for creating a structure a
> | once, but not so great at accessing members of a structure for purposes of
> | manipulation.  I've decided to create a class that uses a dictionary to mainta
> | values for the members.  It uses a method called asBytes() to return the strin
> | by struct.pack().  I should probably call it asString() since I'll document th
> | arguments to send and recv and string arguments.
>
> That looks good.  You could also call it __str__, though there is some
> difference of opinion on this.  __str__ supports the str() function.
> For some people, this should be a ``friendly'' text representation,
> i.e. I guess readable.  For me, it's the object qua string, and if that's
> readable, fine.  (This is particularly in contrast to __repr__, which
> I think everyone agrees should be text.)  Anyway, I guess the most
> likely advantage of calling it __str__ is that it would be invoked
> automatically in %s formatting.

The only problem I see here is if programmers went through the trouble of creating
a C-like structure that contained binary data, they probably intended there to be
binary data that would screw-up __str__, no?  I have problems calling the functions
returning the characters "asString" or any such derivative name, because the
intention is to return an array of bytes, living next to each other in memory.
When I think of a string I usually think of printable characters in sequential
memory addresses terminated by a \0.

> | Of course, right not its all buried inside my IsdHeader class, but I'm thinkin
> | create a more general class called CStructure that defines all the methods for
> | things, then subclassing it to create IsdHeader.
>
> Well, it sounds like you're having fun.  From a practical point of view
> it sounds like we're approaching overkill, but that's a judgement call.

Overkill, maybe.  The lofty goal here is to create a class that any python
programmer could subclass from with something ala

class LittleStructure(CStructure):
    def __init__(self):
        CStructure.__init__(self, {
            'firstValue':'l',
            'nextValue':'l',
            'someShortValue':h
        }

and would then be able to modify members of the structure with:
    myLittleStructure.setMember('firstValue', someIntegerValue)
    myLittleStructure.setMember('nextValue', anotherIntegerValue)
ultimately calling something like
    myLittleStructure.asString()
to return the string of bytes representing (in this case) two longs and a short.

> Speaking of overkill, I think you are probably finding that your read/write
> accessor overloading isn't working.  Unlike C++, Python doesn't support
> different functions with the same name but different signature.  You can
> simulate it with a kind of varargs feature (try a parameter declared with
> a leading "*"), or with default arguments, but it's not commonly done and
> for me it isn't idiomatic Python.  Might as well say getstatus()/setstatus().

You're correct.  Actually I hadn't discovered it in the structure stuff (yet) but I
did in the middleware routines that define multiple version of the 'send(..)'
function.  I was wondering what was wrong.  Hmm.  Interesting polymorphic
implementation details...

> Now, for a really intrusive accessor feature that is occasionally used
> in Python code (I think usually to the sorrow of everyone concerned, but
> others might disagree), consider this:
>
>     class T:
>         def __init__(self):
>             self.__dict__ = {'x': 0, 'y': 0}
>         def __getattr__(self, name):
>             print 'getattr', repr(name)
>             if name == 'xy':
>                 return self.x * self.y
>             else:
>                 raise AttributeError, name
>         def __setattr__(self, name, value):
>             print 'setattr', repr(name), repr(value)
>             if self.__dict__.has_key(name):
>                 self.__dict__[name] = value
>             else:
>                 raise AttributeError, name

Isn't this kinda of what I want to use in my CStructure class???

> I think the most useful thing about this is that since you know it's
> there in case you need it, you can relax and just code direct access
> to class instance attributes and avoid the probably pointless hassle
> of a pair of accessor functions dedicated to each attribute.  Then if
> changes to the class mean you need to calculate a value on access, you
> can use these functions to do it -- in this extremely unlikely case,
> and 99 out of 100 classes you write will never need any such thing.
> Note that __getattr__ is called for only those attributes that don't
> already appear in the instance's __dict__.




More information about the Python-list mailing list