Dynamically defining/updating ctypes structure in Python
Question:
I have created subtructure and structure in ctypes as below where I am defining a array of substructure inside structure with some predefined size. (As per requirement SIZE
may be set to 0
initially and can varies based on user input).
from ctypes import *
class MySubStructure(Structure):
_fields_ = [
("sub_field1", c_uint32),
("sub_field2", c_uint32)
]
class MyStructure(Structure):
SIZE = 2
_fields_ = [
("field1", c_uint32),
("field2", c_uint32),
("sub_structure_field", ARRAY(SubStructure, SIZE)),
]
My goal is to modify this substructure based on user input.
For achieving the same I have tried below options but had no success:
-
Defining a __init__
method and updating _fields_
while initializing the instance
-
Updating _fields_
after initializing instance
For both of those options I tried to appending sub_structure_field
, updating only size value by accessing through index.
Finally I just want a workaround so that I can use array of structure inside another structure either initializing at runtime or modifying at runtime.
Answers:
Mentioning [Python.Docs]: ctypes – A foreign function library for Python.
The array size must be known at the moment _fields_ is defined.
You could have a factory function which defines the class and returns it.
code00.py:
#!/usr/bin/env python
import ctypes as cts
import sys
class SubStructure(cts.Structure):
_fields_ = (
("sub_field1", cts.c_uint32),
("sub_field2", cts.c_uint32),
)
def structure_factory(size):
class DynamicStructure(cts.Structure):
_fields_ = (
("field1", cts.c_uint32),
("field2", cts.c_uint32),
("sub_structure_field", SubStructure * size), # Equivalent to: cts.ARRAY(SubStructure, size)
)
return DynamicStructure
def main(*argv):
Struct2 = structure_factory(2) # DynamicStructure type NOT instance
Struct5 = structure_factory(5) # -- // --
print(Struct2.sub_structure_field)
print(Struct5.sub_structure_field)
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}n".format(" ".join(item.strip() for item in sys.version.split("n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("nDone.n")
sys.exit(rc)
Output:
[cfati@CFATI-5510-0:e:WorkDevStackOverflowq057417435]> "e:WorkDevVEnvspy_064_03.07.03_test0Scriptspython.exe" code00.py
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 064bit on win32
<Field type=SubStructure_Array_2, ofs=8, size=16>
<Field type=SubStructure_Array_5, ofs=8, size=40>
Done.
You could also take a look at [SO]: Setting _fields_ dynamically in ctypes.Structure (@CristiFati’s answer).
I have created subtructure and structure in ctypes as below where I am defining a array of substructure inside structure with some predefined size. (As per requirement SIZE
may be set to 0
initially and can varies based on user input).
from ctypes import *
class MySubStructure(Structure):
_fields_ = [
("sub_field1", c_uint32),
("sub_field2", c_uint32)
]
class MyStructure(Structure):
SIZE = 2
_fields_ = [
("field1", c_uint32),
("field2", c_uint32),
("sub_structure_field", ARRAY(SubStructure, SIZE)),
]
My goal is to modify this substructure based on user input.
For achieving the same I have tried below options but had no success:
-
Defining a
__init__
method and updating_fields_
while initializing the instance -
Updating
_fields_
after initializing instance
For both of those options I tried to appending sub_structure_field
, updating only size value by accessing through index.
Finally I just want a workaround so that I can use array of structure inside another structure either initializing at runtime or modifying at runtime.
Mentioning [Python.Docs]: ctypes – A foreign function library for Python.
The array size must be known at the moment _fields_ is defined.
You could have a factory function which defines the class and returns it.
code00.py:
#!/usr/bin/env python
import ctypes as cts
import sys
class SubStructure(cts.Structure):
_fields_ = (
("sub_field1", cts.c_uint32),
("sub_field2", cts.c_uint32),
)
def structure_factory(size):
class DynamicStructure(cts.Structure):
_fields_ = (
("field1", cts.c_uint32),
("field2", cts.c_uint32),
("sub_structure_field", SubStructure * size), # Equivalent to: cts.ARRAY(SubStructure, size)
)
return DynamicStructure
def main(*argv):
Struct2 = structure_factory(2) # DynamicStructure type NOT instance
Struct5 = structure_factory(5) # -- // --
print(Struct2.sub_structure_field)
print(Struct5.sub_structure_field)
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}n".format(" ".join(item.strip() for item in sys.version.split("n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("nDone.n")
sys.exit(rc)
Output:
[cfati@CFATI-5510-0:e:WorkDevStackOverflowq057417435]> "e:WorkDevVEnvspy_064_03.07.03_test0Scriptspython.exe" code00.py Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 064bit on win32 <Field type=SubStructure_Array_2, ofs=8, size=16> <Field type=SubStructure_Array_5, ofs=8, size=40> Done.
You could also take a look at [SO]: Setting _fields_ dynamically in ctypes.Structure (@CristiFati’s answer).