Geoffrey
Geoffrey

Reputation: 11354

How to specify union value at construction

I am trying to pass an array of unions via ctypes to my C++ DLL and I am fairly new to Python. Is there a shorthand way of constructing them, for example:

class MyValue(Union):
  _fields_ = [
    ("ftNone"  , c_void_p),
    ("ftString", c_char_p),
    ("ftInt"   , c_int   ),
    ("ftBigInt", c_long  ),
    ("ftFloat" , c_char_p)
  ]
MyValues = MyValue * 20

CMethod(MyValues(
 ('ftInt'    = 12),
 ('ftString' = 'testing')
))

Or is there a better way of doing this?. I basically want to pass an array of mixed types to my DLL.

Upvotes: 0

Views: 196

Answers (1)

Eryk Sun
Eryk Sun

Reputation: 34260

A ctypes array is initialized with positional arguments. An initial value can be a ctypes data object, a Python object compatible with a simple data type (for an array of simple types such as c_int * 20), or a tuple of positional arguments used to create a temporary instance of the array's data type to be copied (memcpy) into the array.

Since you need a keyword argument to select the proper converter, you'll have to either call MyValue to manually create the temporary instance, or call setattr on each item of an unitialized array. For the former, you can use a generator expression combined with * and ** unpacking (see the tutorial):

values = [
    ('ftInt', 12),
    ('ftString', 'testing'),
]

arr = MyValues(*(MyValue(**{k: v}) for k, v in values))

And here's an alternative using setattr to update the array in a loop:

arr = MyValues()
for item, value in zip(arr, values):
    setattr(item, *value) # note the * unpacking

It would be nice to add support for a keyword argument dict in _PyCData_set (Modules/ctypes/_ctypes.c).

Upvotes: 1

Related Questions