如何从 Python C 扩展访问子类的对象结构字段?

How to access object struct fields of subclasses from a Python C extension?

我正在编写一个 Python 包装外部 C 库的 C 扩展。在原始库中有结构(为了便于讨论,类型为 T),所以我的扩展 class 看起来像这样:

typedef struct {
  PyObject_HEAD
  T *cdata;
} TWrapperBase;

我也时不时要查一下Python中的指针,所以暴露了一个只读字段_cdata是一个cdata指针作为unsigned long long(是的,我知道它不是很便携,但现在超出了范围)。

然后,我希望能够在 Python 中添加更多方法,但我不能将它们附加到 C 中声明的 class 中,所以我 subclass 它并添加我的新方法:

class TWrapper(TWrapperBase):
    ...

现在,在我的 C 扩展代码中,我需要一种访问 cdata 字段的方法,这样我就可以将它传递给库函数。我知道 self 不会是 TWrapperBase 的实例,而是 TWrapper(这个 Python 版本)。 正确的做法是什么?

static PyObject * doStuff(PyObject *self)
{
  T *cdata_ptr;
  // How to get a pointer to cdata?
  //
  // This looks very unsafe to me, do I have any guarantee of
  // the subclass memory layout?
  // 1. cdata_ptr = ((TWrapperBase*)self)->cdata
  //
  // This is probably safe, but it seems to be a bit of a hassle
  // to query it with a string key
  // 2. cdata_ptr = PyLong_AsVoidPtr(PyObject_GetAttrString(self, "_cdata"))
  do_important_library_stuff(cdata_ptr);
  Py_INCREF(self);
  return self;
}

谢谢!

  // This looks very unsafe to me, do I have any guarantee of
  // the subclass memory layout?
  // 1. cdata_ptr = ((TWrapperBase*)self)->cdata

是的,行得通。您可以查看 Python's built-in types 的所有实现,发现它们做的事情几乎相同,通常无需检查它们是否在子类实例上运行。