working with ctypes and complex data structures

eryk sun eryksun at gmail.com
Mon Oct 3 22:48:35 EDT 2016


On Mon, Oct 3, 2016 at 9:27 PM, Michael Felt <michael at felt.demon.nl> wrote:
>
> int perfstat_subsystem_total(
>    perfstat_id_t *name,
>    perfstat_subsystem_total_t *userbuff,
>    int sizeof_struct,
>    int desired_number);
> ...
>    +79  class cpu_total:
>    +80      def __init__(self):
>    +81          __perfstat__ = CDLL("libperfstat.a(shr_64.o)")

Move loading the library and defining function prototypes to either
the module or class body. Also, don't use dunder names. The convention
for a private attribute is a single underscore. For type safety,
define each function's argtypes (and restype where required, the
default is c_int). For a more Pythonic interface, define a ctypes
errcheck function that encapsulates raising an appropriate exception
when a C call fails. For example:

    import ctypes

    # If the following types are used generally, define them at
    # the module level, else define them in the class namespace
    # that uses them.

    perfstat = ctypes.CDLL("libperfstat.a(shr_64.o)")

    class perfstat_id_t(ctypes.Structure):
        pass

    IDENTIFIER_LENGTH = 64

    class time64_t(ctypes._SimpleCData):
        _type_ = ctypes.c_int64._type_

    time_t = time64_t

    class perfstat_cpu_total_t(ctypes.Structure):
        _fields_ = (("ncpus",       ctypes.c_int),
                    ("ncpus_cfg",   ctypes.c_int),
                    ("description", ctypes.c_char * IDENTIFIER_LENGTH),
                    ("buffer1",     ctypes.c_ulonglong * 15),
                    ("lbolt",       time_t),
                    ("loadavg",     ctypes.c_ulonglong * 3),
                    ("buffer2",     ctypes.c_ulonglong * 29),
                    ("ncpus_high",  ctypes.c_int),
                    ("puser",       ctypes.c_ulonglong),
                    ("psys",        ctypes.c_ulonglong),
                    ("pidle",       ctypes.c_ulonglong),
                    ("pwait",       ctypes.c_ulonglong),
                    ("buffer3",     ctypes.c_ulonglong * 12))

    def _perfstat_errcheck(result, func, args):
        if result == -1:
            # get error info and
            raise SomeException()
        return args

    class CPUTotal(object):
        # These may be defined here or just referenced here.
        _perfstat = perfstat
        _perfstat_id_t = perfstat_id_t
        _perfstat_cpu_total_t = perfstat_cpu_total_t

        _cpu_total = _perfstat.perfstat_cpu_total
        _cpu_total.errcheck = _perfstat_errcheck
        _cpu_total.argtypes = (
            ctypes.POINTER(_perfstat_id_t),
            ctypes.POINTER(_perfstat_cpu_total_t),
            ctypes.c_int, ctypes.c_int)

        def __init__(self):
            self._tcpu = self._perfstat_cpu_total_t()
            self._cpu_total(None,
                            ctypes.byref(self._tcpu),
                            ctypes.sizeof(self._tcpu), 1)



More information about the Python-list mailing list