Mark Mark - 1 month ago 9
Python Question

ctypes.Structure Modify _fields_ at Run Time

Is it possible to modify the fields definition of the ctypes.Structure after it's been imported?

Something like:

from ctypes import *

class A_STRUCT(Structure):
_fields_ = [("one",c_int)]

A_STRUCT._fields_.append(("two",c_int))

x = A_STRUCT()
print x.one
print x.two


Not surprisingly this fails with:

0
Traceback (most recent call last):
File "structEnumTest.py", line 10, in <module>
print x.two
AttributeError: 'A_STRUCT' object has no attribute 'two'


EDITS

My use case is that I have two version of A_STRUCT. Version 2 is the same with additional fields appended to the end of version one. I was hoping to avoid having something like this. I do not know which version of the struct is needed until run-time.

class A_STRUCT_V1(Structure):
_fields_ = [("one",c_int)]

class A_STRUCT_V2(Structure):
_fields_ = [("one",c_int),("two",c_int)]

Answer

No, as you can see in the sources, PyCStructType_Type is a custom metaclass (see lines 327ff in the C code I just pointed to) and Structure (lines 4136ff) uses it (as exposed in 5532ff). The class statement (specifically when the __new__ from the custom metaclass gets called to make the new class which inherits from Structure) is when all C-accessible fields are actually defined (and it's nice of ctypes to make other "smuggled in" fields inaccessible from Python as well to avoid accidents;-).

What problem, exactly, are you trying to solve, that you couldn't solve by rebuilding A_STRUCT from scratch at the time you learn about the extra fields? For example, if your issue is that there are instances of the "old" A_STRUCT already around, well, obviously, those instances don't have the new fields you've just learned about, so modifying the class, even if through some incredible contortion it was feasible, wouldn't be all that useful;-).