Reputation: 1021
>>> from ctypes import *
>>> class A(Structure):
... _fields_ = [('a', c_int), ('b', c_int)]
... def __init__(self, x):
... self.a = x + 1
... self.b = x + 2
...
>>> a = A(1)
>>> a.a
2
>>> a.b
3
>>> b = (A * 2)(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: expected A instance, got int
I am trying to construct an array of C structures in python and want the constructor to be called for each element in the array. How can I accomplish this?
Upvotes: 5
Views: 2380
Reputation: 14614
The error explains exactly the problem, but in a slightly convoluted manner:
The correct way to initialize such an array is as follows:
structs = [A(1, 2), A(1, 2)]
array = (A * 2)(*structs)
Or, if you can define them all during the array constructor, as follows:
array = (A * 2)(A(1, 2), A(1, 2))
Now, why does this work and your solution not? Since I am passing an instance of A
for each argument to the constructor of A * 2
, which is an array of A
. The array requires an instance of A
for each argument passed, which is precisely the error message. It does not expect to convert arguments into A
, it expects an instance of A
itself.
The step-by-step way is as follows:
from ctypes import *
class A(Structure):
_fields_ = [('a', c_int), ('b', c_int)]
# this create a class which expects 2 A instances
a_array_factory = A * 2
# our first A instance
struct_1 = A(1, 2)
# our second A instance
struct_2 = A(2, 3)
# initialize our array
array = a_array_factory(struct_1, struct_2)
EDIT:
Since a structure does not have a native Python type, there is no solution, to my knowledge, without creating intermediary structs. According to the Python documentation, the only native types with C primitives are the following:
ctypes type C type Python type
c_bool _Bool bool (1)
c_char char 1-character string
c_wchar wchar_t 1-character unicode string
c_byte char int/long
c_ubyte unsigned char int/long
c_short short int/long
c_ushort unsigned short int/long
c_int int int/long
c_uint unsigned int int/long
c_long long int/long
c_ulong unsigned long int/long
c_longlong __int64 or long long int/long
c_ulonglong unsigned __int64 or unsigned long long int/long
c_float float float
c_double double float
c_longdouble long double float
c_char_p char * (NUL terminated) string or None
c_wchar_p wchar_t * (NUL terminated) unicode or None
c_void_p void * int/long or Nonee or None
Upvotes: 8