Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Python C-API中动态创建派生类型_Python_Derived Class_Python 2.x_Python C Api - Fatal编程技术网

如何在Python C-API中动态创建派生类型

如何在Python C-API中动态创建派生类型,python,derived-class,python-2.x,python-c-api,Python,Derived Class,Python 2.x,Python C Api,假设我们具有中定义的类型Noddy。现在我们要创建一个派生类型,只覆盖Noddy的\uuuuu new\uuuu()方法 目前我使用以下方法(检查可读性的错误): 这是可行的,但我不确定这样做是否正确。我也希望我必须设置标志,因为我在堆上动态分配type对象,但这样做会导致解释器中出现segfault 我还考虑过使用PyObject\u Call()或类似方法显式调用type(),但我放弃了这个想法。我需要将函数BrownNoddy\u new()包装在Python函数对象中,并创建一个映射到该

假设我们具有中定义的类型
Noddy
。现在我们要创建一个派生类型,只覆盖
Noddy
\uuuuu new\uuuu()
方法

目前我使用以下方法(检查可读性的错误):

这是可行的,但我不确定这样做是否正确。我也希望我必须设置标志,因为我在堆上动态分配type对象,但这样做会导致解释器中出现segfault

我还考虑过使用
PyObject\u Call()
或类似方法显式调用
type()
,但我放弃了这个想法。我需要将函数
BrownNoddy\u new()
包装在Python函数对象中,并创建一个映射到该函数对象的字典
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

最好的办法是什么?我的方法正确吗?有没有我错过的接口功能

更新
python开发人员邮件列表中有两个相关主题的线程。通过这些线程和一些实验,我推断我不应该设置
Py\u TPFLAGS\u HEAPTYPE
,除非通过调用
type()
来分配类型。无论是手动分配类型还是调用
type()
,这些线程中都有不同的建议。如果我知道在
tp_new
槽中包装C函数的推荐方法是什么,我会很高兴使用后者。对于常规方法,这一步很容易——我可以使用它来获得合适的包装器对象。我不知道如何为我的
\uu new\uuu()
方法创建这样一个包装器对象——也许我需要使用未记录的函数
PyCFunction\u new()
来创建这样一个包装器对象。

尝试并理解如何做到这一点的一种方法是使用SWIG创建它的一个版本。看看它产生了什么,看看它是否匹配或以不同的方式完成。我可以告诉一直在编写SWIG的人,他们对扩展Python有着深刻的理解。不管怎样,看看他们是怎么做的都无妨。这可能有助于您理解这个问题。

如果这个答案很糟糕,我很抱歉,但是您可以在中找到这个想法的实现,特别是我认为以下文件可能是有用的参考:

PythonQtClassWrapper_init中的这个片段让我觉得有点有趣:

static int PythonQtClassWrapper_init(PythonQtClassWrapper* self, PyObject* args, PyObject* kwds)
{
  // call the default type init
  if (PyType_Type.tp_init((PyObject *)self, args, kwds) < 0) {
    return -1;
  }

  // if we have no CPP class information, try our base class
  if (!self->classInfo()) {
    PyTypeObject*  superType = ((PyTypeObject *)self)->tp_base;

    if (!superType || (superType->ob_type != &PythonQtClassWrapper_Type)) {
      PyErr_Format(PyExc_TypeError, "type %s is not derived from PythonQtClassWrapper", ((PyTypeObject*)self)->tp_name);
      return -1;
    }

    // take the class info from the superType
    self->_classInfo = ((PythonQtClassWrapper*)superType)->classInfo();
  }

  return 0;
}
static int pythonqtclasswapper_init(pythonqtclasswapper*self,PyObject*args,PyObject*kwds)
{
//调用默认类型init
if(PyType_Type.tp_init((PyObject*)self,args,kwds)<0){
返回-1;
}
//如果没有CPP类信息,请尝试我们的基类
如果(!self->classInfo()){
PyTypeObject*超类型=((PyTypeObject*)self)->tp_基;
if(!superType | |(superType->ob_type!=&PythonQtClassWrapper_type)){
PyErr_格式(PyExc_TypeError,“类型%s不是从pythonqtclasswapper派生的”,((PyTypeObject*)self)->tp_名称);
返回-1;
}
//从超类型获取类信息
self->_classInfo=((PythonQtClassWrapper*)超类型)->classInfo();
}
返回0;
}
值得注意的是,PythonQt确实使用了一个包装生成器,因此它并不完全符合您的要求,但我个人认为,试图智胜vtable并不是最理想的设计。基本上,Python有许多不同的C++包装生成器,人们用它们来做一个很好的理由——它们被记录下来,在搜索结果和堆栈溢出中到处都有例子。如果你手推一个以前没人见过的解决方案,那么如果他们遇到问题,调试就会困难得多。即使它是封闭源代码,下一个必须维护它的人也会挠头,你必须向每个新来的人解释

< >一旦你得到一个代码生成器,你所需要做的就是维护底层C++代码,你不必手工更新或修改扩展代码。(这可能与您所采用的诱人解决方案相差不远)

建议的解决方案是打破新引入的类型安全的一个例子(当按照指示使用时)

因此,虽然这样实现派生类/子类可能不是最好的长期选择,但应该将代码包装起来,让vtable做它最擅长的事情,当新成员有问题时,您可以向他指出文档


不过这只是我的看法D

我在修改扩展以与Python 3兼容时遇到了相同的问题,并在尝试解决该问题时找到了此页面

我最终通过阅读Python解释器的源代码和

设置
Py\u TPFLAGS\u HEAPTYPE
标志会告诉解释器将
PyTypeObject
重新编译为
PyHeapTypeObject
,其中包含还必须分配的其他成员。在某个时刻,解释器试图引用这些额外的成员,如果您让它们未分配,则会导致segfault

Python 3.2引入了简化动态类型创建的C结构
PyType_Slot
PyType_Spec
以及C函数
PyType_FromSpec
。简而言之,您可以使用
PyType\u Slot
PyType\u Spec
来指定
PyTypeObject
tp*
成员,然后从Spec
调用
PyType\u来完成分配和初始化内存的繁琐工作

根据PEP 0384,我们有:

typedef struct{
  int slot;    /* slot id, see below */
  void *pfunc; /* function pointer */
} PyType_Slot;

typedef struct{
  const char* name;
  int basicsize;
  int itemsize;
  int flags;
  PyType_Slot *slots; /* terminated by slot==0. */
} PyType_Spec;

PyObject* PyType_FromSpec(PyType_Spec*);
(以上不是PEP 0384的文本副本,它还包括
const char*doc
作为
PyType_Spec
的成员。但该成员未出现在源代码中。)

typedef struct{
  int slot;    /* slot id, see below */
  void *pfunc; /* function pointer */
} PyType_Slot;

typedef struct{
  const char* name;
  int basicsize;
  int itemsize;
  int flags;
  PyType_Slot *slots; /* terminated by slot==0. */
} PyType_Spec;

PyObject* PyType_FromSpec(PyType_Spec*);
PyType_Slot slots[] = {
    { Py_tp_doc, "BrownNoddy objects" },
    { Py_tp_base, &NoddyType },
    { Py_tp_new, BrownNoddy_new },
    { 0 },
};
PyType_Spec spec = { "noddy.BrownNoddy", sizeof(BrownNoddy), 0,
                      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, slots };
PyTypeObject *BrownNoddyType = (PyTypeObject *)PyType_FromSpec(&spec);