ctypes.Structure 运行时修改 _fields_

2 投票
2 回答
2830 浏览
提问于 2025-04-16 02:35

可以在导入后修改ctypes.Structure_fields_定义吗?

类似于:

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

这显然会失败,错误信息是:

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

编辑

我的使用场景是我有两个版本的A_STRUCT。版本2和版本1相同,只是在版本1的末尾添加了一些字段。我希望能避免像这样的情况。我在运行时才知道需要哪个版本的结构体。

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

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

2 个回答

3

我知道这个问题很老套,但你可以通过子类化轻松解决你的问题:

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

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

对于类型为 A_STRUCT_V2 的对象,'two' 会紧接着 'one' 存储在内存中。

如果子类的 字段 名称和父类的 字段 成员重复,父类的 字段 并不会被替换,它仍然占用相同的内存(虽然用类似 child.two 的语句无法访问到父类的字段),而第二个成员会放在它之后。

5

不,正如你在这个链接中看到的,PyCStructType_Type 是一个自定义的元类(你可以在我刚提到的C代码的327行及之后找到)。而Structure(4136行及之后)使用了这个元类(在5532行及之后有说明)。当你使用class语句时,特别是当自定义元类的__new__被调用来创建一个继承自Structure的新类时,所有可以通过C访问的字段才会被真正定义(而且ctypes很贴心地让其他“偷偷引入”的字段在Python中不可访问,以避免意外发生;-)。

你到底想解决什么问题呢?是那种在你了解到额外字段时,无法通过从头开始重建A_STRUCT来解决的问题吗?比如说,如果你的问题是已经存在一些“旧版”的A_STRUCT实例,那么显然这些实例并没有你刚刚了解到的新字段。所以,即使通过某种不可思议的方式修改这个类也是没什么用的;-)。

撰写回答