""" Thomas, Ouch ouch I must have misunderstood what you meant by "use the dynamic nature of Python, and (re-)define the data type after the required size is already known, on a case by case basis".
Do you have an example of what you meant? I searched but did not find. Are those your words? Yes, to declare strings of strings in Python would be to express a familiar idea that I don't know how to say well in C. These are standard structs that I exchange with third parties, e.g., me editing Class files read later by a Java interpreter, so I can't avoid having to deal with this complexity designed into them. For discussion I've simplified the problem: back in real life I have a few dozen variations of structs like this to deal with. The following Python mostly works, but only at the cost of rewriting the small part of CTypes that I need for this app. """ import binascii import struct class Struct: def __init__(self, declarations = []): """Add initial values to self and list the names declared.""" names = [] for (initial, name) in declarations: names += [name] python = ' '.join(['self.' + name, '=', 'initial']) exec python self._names_ = names def _fields_(self): """List the fields.""" fields = [] for name in self._names_: python = 'self.' + name fields += [eval(python)] return fields def _pack_(self): """Pack a copy of the fields.""" packs = '' for field in self._fields_(): packs += field._pack_() return packs def _size_(self, bytes = None): """Count the bytes of the fields.""" return len(self._pack_()) def _unpack_(self, bytes): """Count the bytes of a copy of the fields.""" offset = 0 for field in self._fields_(): size = field._size_(bytes[offset:]) field._unpack_(bytes[offset:][:size]) offset += size if offset != len(bytes): why = ('_unpack_ requires a string argument' 'of length %d' % offset) raise struct.error(why) class Field(Struct): """Contain one value.""" def __init__(self, value = 0): self._value_ = value def _pack_(self): raise AttributeError('abstract') def _unpack_(self, bytes): raise AttributeError('abstract') class Byte(Field): """Contain one byte.""" def _pack_(self): return struct.pack('B', self._value_) def _unpack_(self, bytes): self._value_ = struct.unpack('B', bytes)[0] class ByteArray(Field): """Contain the same nonnegative number of bytes always.""" def _pack_(self): return self._value_ def _unpack_(self, bytes): if len(bytes) == len(self._value_): self._value_ = bytes else: why = ('_unpack_ requires a string argument' 'of length %d' % len(self._value_)) raise struct.error(why) class Symbol(Struct): """Contain a count of bytes.""" def __init__(self, value = ''): Struct.__init__(self, [ (Byte(), 'length'), (ByteArray(value), 'bytes')]) self._pack_() def _size_(self, bytes = None): return ord(bytes[0]) def _pack_(self): self.length = Byte(self.length._size_() + self.bytes._size_()) return Struct._pack_(self) class TwoSymbols(Struct): """Contain two Symbols.""" def __init__(self, values = ['', '']): Struct.__init__(self, [ (Symbol(values[0]), 'first'), (Symbol(values[1]), 'second')]) zz = Symbol() print binascii.hexlify(zz._pack_()).upper() # 01 zz = Symbol() zz.bytes = ByteArray('left') zz._unpack_(zz._pack_()) ; print repr(zz._pack_()) # '\x05left' zz = Symbol() zz.bytes = ByteArray('right') zz._unpack_(zz._pack_()) ; print repr(zz._pack_()) # '\x06right' zz = TwoSymbols() zz.first.bytes = ByteArray('hi') zz.second.bytes = ByteArray('bye') zz._unpack_(zz._pack_()) ; print repr(zz._pack_()) # '\x03hi\x04bye' print zz._size_() # 7 yy = ''' def yyFunc(self): return [self.length, self.bytes] ''' exec yy Symbol._fields_ = yyFunc zz = TwoSymbols(['alef', 'bet']) zz._unpack_(zz._pack_()) ; print repr(zz._pack_()) -- http://mail.python.org/mailman/listinfo/python-list