Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ctypes variable length structures

Ever since I read Dave Beazley's post on binary I/O handling (http://dabeaz.blogspot.com/2009/08/python-binary-io-handling.html) I've wanted to create a Python library for a certain wire protocol. However, I can't find the best solution for variable length structures. Here's what I want to do:

import ctypes as c

class Point(c.Structure):
    _fields_ = [
        ('x',c.c_double),
        ('y',c.c_double),
        ('z',c.c_double)
        ]

class Points(c.Structure):
    _fields_ = [
        ('num_points', c.c_uint32),
        ('points', Point*num_points) # num_points not yet defined!
        ]

The class Points won't work since num_points isn't defined yet. I could redefine the _fields_ variable later once num_points is known, but since it's a class variable it would effect all of the other Points instances.

What is a pythonic solution to this problem?

like image 571
Jake Avatar asked Aug 10 '11 17:08

Jake


People also ask

What is the Ctypes module?

ctypes is a foreign function library for Python. It provides C compatible data types, and allows calling functions in DLLs or shared libraries. It can be used to wrap these libraries in pure Python.

What is C_char_p?

c_char_p is a subclass of _SimpleCData , with _type_ == 'z' . The __init__ method calls the type's setfunc , which for simple type 'z' is z_set . In Python 2, the z_set function (2.7. 7) is written to handle both str and unicode strings.


1 Answers

The most straightforward way, with the example you gave is to define the structure just when you have the information you need.

A simple way of doing that is creating the class at the point you will use it, not at module root - you can, for example, just put the class body inside a function, that will act as a factory - I think that is the most readable way.

import ctypes as c



class Point(c.Structure):
    _fields_ = [
        ('x',c.c_double),
        ('y',c.c_double),
        ('z',c.c_double)
        ]

def points_factory(num_points):
    class Points(c.Structure):
        _fields_ = [
            ('num_points', c.c_uint32),
            ('points', Point*num_points) 
            ]
    return Points

#and when you need it in the code:
Points = points_factory(5)

Sorry - It is the C code that will "fill in" the values for you - that is not the answer them. WIll post another way.

like image 129
jsbueno Avatar answered Oct 05 '22 20:10

jsbueno