Iterable Ctypes Struct

M

mark.seagoe

I like the ability to access elements of a struct such as with ctypes
Structure:4

What I like about it is there are no quotes needed.

What I don't like about it is that it's not iterable:
I don't want to force the end user to have preknowledge of the element
names.
Has anyone subclassed ctypes Structure based class to be iterable?
Before a noob starts trying to do this, is it possible? How to
approach it?

Thx,
Mark
 
G

Gabriel Genellina

I like the ability to access elements of a struct such as with ctypes
Structure:
4

What I like about it is there are no quotes needed.

What I don't like about it is that it's not iterable:

I don't want to force the end user to have preknowledge of the element
names.

Note that those names are available as the _fields_ class attribute
Has anyone subclassed ctypes Structure based class to be iterable?
Before a noob starts trying to do this, is it possible? How to
approach it?

The easiest way would be to define __getitem__ accepting index 0, 1, 2...
until the last defined field.
See http://docs.python.org/reference/datamodel.html#object.__getitem__

<code>
from ctypes import Structure

class IterableStructure(Structure):
def __getitem__(self, i):
if not isinstance(i, int):
raise TypeError('subindices must be integers: %r' % i)
return getattr(self, self._fields_[0])

</code>

This was tested as much as you see here:

py> from ctypes import c_int
py>
py> class POINT(IterableStructure):
.... _fields_ = [("x", c_int),
.... ("y", c_int)]
....
py> point = POINT(10, 20)
py> print point.x, point.y
10 20
py> for field in point:
.... print field
....
10
20
py> print list(point)
[10, 20]
 
M

mark.seagoe

I like the ability to access elements of a struct such as with ctypes
Structure:

What I like about it is there are no quotes needed.
What I don't like about it is that it's not iterable:
I don't want to force the end user to have preknowledge of the element
names.

Note that those names are available as the _fields_ class attribute
Has anyone subclassed ctypes Structure based class to be iterable?
Before a noob starts trying to do this, is it possible?  How to
approach it?

The easiest way would be to define __getitem__ accepting index 0, 1, 2...  
until the last defined field.
Seehttp://docs.python.org/reference/datamodel.html#object.__getitem__

<code>
 from ctypes import Structure

class IterableStructure(Structure):
   def __getitem__(self, i):
     if not isinstance(i, int):
       raise TypeError('subindices must be integers: %r' % i)
     return getattr(self, self._fields_[0])

</code>

This was tested as much as you see here:

py> from ctypes import c_int
py>
py> class POINT(IterableStructure):
...     _fields_ = [("x", c_int),
...                 ("y", c_int)]
...
py> point = POINT(10, 20)
py> print point.x, point.y
10 20
py> for field in point:
...   print field
...
10
20
py> print list(point)
[10, 20]


Thanks very much, Gabriel. This is very good start for me.
This works for predefined class. How about a situation where the
fields are added dynamically (as from reading in from an xml file).
For example, if I were to now add another element:
point.z = 30
print list(point) [10, 20]
dir(point)
['__class__', '__ctypes_from_outparam__', '__delattr__', '__
dict__', '__doc__', '__getattribute__', '__getitem__', '__ha
sh__', '__init__', '__module__', '__new__', '__reduce__', '_
_reduce_ex__', '__repr__', '__setattr__', '__str__', '__weak
ref__', '_b_base_', '_b_needsfree_', '_fields_', '_objects',
'x', 'y', 'z']

I don't know why the iterator (where ever it is) didn't get
incremented. Thanks for any insight.

Mark
 
M

mark.seagoe

En Wed, 11 Feb 2009 00:31:26 -0200, <[email protected]> escribió:
Note that those names are available as the _fields_ class attribute
The easiest way would be to define __getitem__ accepting index 0, 1, 2....  
until the last defined field.
Seehttp://docs.python.org/reference/datamodel.html#object.__getitem__
<code>
 from ctypes import Structure
class IterableStructure(Structure):
   def __getitem__(self, i):
     if not isinstance(i, int):
       raise TypeError('subindices must be integers: %r' % i)
     return getattr(self, self._fields_[0])

This was tested as much as you see here:

py> from ctypes import c_int
py>
py> class POINT(IterableStructure):
...     _fields_ = [("x", c_int),
...                 ("y", c_int)]
...
py> point = POINT(10, 20)
py> print point.x, point.y
10 20
py> for field in point:
...   print field
...
10
20
py> print list(point)
[10, 20]

Thanks very much, Gabriel.  This is very good start for me.
This works for predefined class.  How about a situation where the
fields are added dynamically (as from reading in from an xml file).
For example, if I were to now add another element:
point.z = 30
print list(point) [10, 20]
dir(point)

['__class__', '__ctypes_from_outparam__', '__delattr__', '__
dict__', '__doc__', '__getattribute__', '__getitem__', '__ha
sh__', '__init__', '__module__', '__new__', '__reduce__', '_
_reduce_ex__', '__repr__', '__setattr__', '__str__', '__weak
ref__', '_b_base_', '_b_needsfree_', '_fields_', '_objects',
 'x', 'y', 'z']

I don't know why the iterator (where ever it is) didn't get
incremented.  Thanks for any insight.

Mark- Hide quoted text -

- Show quoted text -


I tinkered with it and think I have viable solution.
I need to append a new member to _fields_ before writing it,
then it seems to work.
List: [10, 20, 30]

Awesome. Thanks!
 
G

Gabriel Genellina

[recipe using _fields_]
Thanks very much, Gabriel.  This is very good start for me.
This works for predefined class.  How about a situation where the
fields are added dynamically (as from reading in from an xml file).
I tinkered with it and think I have viable solution.
I need to append a new member to _fields_ before writing it,
then it seems to work.
List: [10, 20, 30]

Yes, that's the way to add a new field -- but you have to do that before
creating the first instance. Anywy, this is somewhat strange for a ctypes
Structure. Usually its memory layout is fixed and mandated by the
library/format/whatever you're trying to bind to.
You are not using it as a generic attribute container, are you? There are
better alternatives in that case.
 
M

mark.seagoe

Hi Gabriel;

Not sure what generic attribute container is. I am reading in from
xml file
all reg names for a chip. So then I'd be able to use python scripts
to
access the regs. So eventually this class will get subclassed w/ hw
access
instead of just saving in int. So I want to call this module
something like
"CHIP" which contains a struct. I add the "REG" struct objects as I
read
them in from xml file. The "REG" struct would have info about
address, # of
bits, type (RO, RW, etc).

Thx,
Mark
 
M

Marc 'BlackJack' Rintsch

Not sure what generic attribute container is. I am reading in from xml
file all reg names for a chip.

Are you using instances of that class to interface C code or to read/
write data intended to be read or written by a C program? If not then
`ctypes` might be the wrong tool.

Ciao,
Marc 'BlackJack' Rintsch
 
M

mark.seagoe

Are you using instances of that class to interface C code or to read/
write data intended to be read or written by a C program?  If not then
`ctypes` might be the wrong tool.

Ciao,
        Marc 'BlackJack' Rintsch

It's accessing through USB so I'm also interfacing to Win32 drivers.
But at this higher level, since I'm somewhat new to Python so I'm not
aware of other classes which exist to allow accessing in the format
desired (without quotes and using dot notation):
classname.elementname1, instead of something like classname
["elementname1"]. It's just cosmetic, but I'd prefer the dot notation
without quotes for the end user experience of script writing later.
Is there something besides ctypes.Structure that would do that?

Thx,
Mark
 
G

Gabriel Genellina

xml file all reg names for a chip.

Are you using instances of that class to interface C code or to read/
write data intended to be read or written by a C program?  If not then
`ctypes` might be the wrong tool.

It's accessing through USB so I'm also interfacing to Win32 drivers.
But at this higher level, since I'm somewhat new to Python so I'm not
aware of other classes which exist to allow accessing in the format
desired (without quotes and using dot notation):
classname.elementname1, instead of something like classname
["elementname1"]. It's just cosmetic, but I'd prefer the dot notation
without quotes for the end user experience of script writing later.
Is there something besides ctypes.Structure that would do that?

You don't need *anything* special to add attributes to an object in
Python. Even an empty class is enough:

py> class Struct(object):
.... pass # an empty class
....
py> s = Struct()
py> s.x = 10
py> s.y = 20
py> print s.x, s.y
10 20
py>

But since this thread started asking how to iterate over the attributes,
let's use a named tuple:

py> from collections import namedtuple
py> StructWithNames = namedtuple("StructWithNames", "x,y,z")
py> s = StructWithNames(10, 20, 30)
py> s.z
30
py> s
StructWithNames(x=10, y=20, z=30)
py> list(s)
[10, 20, 30]
py> for item in s: print item
....
10
20
30
py> s._fields
('x', 'y', 'z')
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,160
Latest member
CollinStri
Top