Iterable Ctypes Struct

Discussion in 'Python' started by mark.seagoe@gmail.com, Feb 11, 2009.

  1. Guest

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

    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:
    >>>for n in myStruct: <== gives error
    >>> print n


    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
     
    , Feb 11, 2009
    #1
    1. Advertising

  2. En Wed, 11 Feb 2009 00:31:26 -0200, <> escribió:

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

    > 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:
    >>>> for n in myStruct: <== gives error
    >>>> print n

    >
    > 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]

    --
    Gabriel Genellina
     
    Gabriel Genellina, Feb 11, 2009
    #2
    1. Advertising

  3. Guest

    On Feb 10, 9:52 pm, "Gabriel Genellina" <>
    wrote:
    > En Wed, 11 Feb 2009 00:31:26 -0200, <> escribió:
    >
    > > I like the ability to access elements of a struct such as with ctypes
    > > Structure:
    > >>>> myStruct.elementName1

    > > 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:
    > >>>> for n in myStruct:  <== gives error
    > >>>>    print n

    >
    > > 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]
    >
    > --
    > Gabriel Genellina


    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
     
    , Feb 11, 2009
    #3
  4. Guest

    On Feb 11, 9:01 am, wrote:
    > On Feb 10, 9:52 pm, "Gabriel Genellina" <>
    > wrote:
    >
    >
    >
    >
    >
    > > En Wed, 11 Feb 2009 00:31:26 -0200, <> escribió:

    >
    > > > I like the ability to access elements of a struct such as with ctypes
    > > > Structure:
    > > >>>> myStruct.elementName1
    > > > 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:
    > > >>>> for n in myStruct:  <== gives error
    > > >>>>    print n

    >
    > > > 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]

    >
    > > --
    > > Gabriel Genellina

    >
    > 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.

    >>> p._fields_.append(('z', c_int))
    >>> point.z = 30
    >>> print 'List:', list(p)

    List: [10, 20, 30]

    Awesome. Thanks!
     
    , Feb 11, 2009
    #4
  5. Guest

    In last post, I mixed code w/ 'p' and 'point'. Should be:

    >>> point._fields_.append(('z', c_int))
    >>> point.z = 30
    >>> print 'List:', list(point)


    List: [10, 20, 30]
     
    , Feb 11, 2009
    #5
  6. En Wed, 11 Feb 2009 16:32:41 -0200, <> escribió:
    > On Feb 11, 9:01 am, wrote:
    >> On Feb 10, 9:52 pm, "Gabriel Genellina" <>
    >> wrote:
    >> > En Wed, 11 Feb 2009 00:31:26 -0200, <> escribió:

    >>
    >> > > I like the ability to access elements of a struct such as with > >

    >> ctypes
    >> > > Structure:
    >> > > 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.


    [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.
    >
    >>>> p._fields_.append(('z', c_int))
    >>>> point.z = 30
    >>>> print 'List:', list(p)

    > 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.

    --
    Gabriel Genellina
     
    Gabriel Genellina, Feb 11, 2009
    #6
  7. Guest

    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
     
    , Feb 12, 2009
    #7
  8. On Wed, 11 Feb 2009 17:33:23 -0800, mark.seagoe wrote:

    > 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
     
    Marc 'BlackJack' Rintsch, Feb 12, 2009
    #8
  9. Guest

    On Feb 11, 5:51 pm, Marc 'BlackJack' Rintsch <> wrote:
    > On Wed, 11 Feb 2009 17:33:23 -0800, mark.seagoe wrote:
    > > 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


    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
     
    , Feb 12, 2009
    #9
  10. En Thu, 12 Feb 2009 00:02:12 -0200, <> escribió:
    > On Feb 11, 5:51 pm, Marc 'BlackJack' Rintsch <> wrote:
    >> On Wed, 11 Feb 2009 17:33:23 -0800, mark.seagoe wrote:


    >> > 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.

    >
    > 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')

    --
    Gabriel Genellina
     
    Gabriel Genellina, Feb 12, 2009
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris Fogelklou
    Replies:
    36
    Views:
    1,433
    Chris Fogelklou
    Apr 20, 2004
  2. Henk Punt
    Replies:
    0
    Views:
    418
    Henk Punt
    Jul 23, 2004
  3. Jack
    Replies:
    6
    Views:
    1,260
    sturlamolden
    Apr 25, 2008
  4. Replies:
    0
    Views:
    524
  5. Replies:
    2
    Views:
    383
    James Stroud
    Dec 10, 2008
Loading...

Share This Page