Python 我的PyCFunction第一次工作,但在连续迭代后会导致segfault

Python 我的PyCFunction第一次工作,但在连续迭代后会导致segfault,python,numpy,python-extensions,Python,Numpy,Python Extensions,我想用c编写一个python对象,其中包含一个numpy向量(实际上有两个,但在这个最小的示例中只有一个) 首先,我只想创建一个具有numpy数组的对象,并查看是否可以将其添加到循环中的所有数组元素中。但即使这样,也会导致奇怪的(可复制的)行为和错误 以下是发生的情况(回复): 我可以这样解决这个问题: ... r2 = r.add() >>> r3 = r2.add() >>> r4 = r3.add() >>> r4.runs array

我想用c编写一个python对象,其中包含一个numpy向量(实际上有两个,但在这个最小的示例中只有一个)

首先,我只想创建一个具有numpy数组的对象,并查看是否可以将其添加到循环中的所有数组元素中。但即使这样,也会导致奇怪的(可复制的)行为和错误

以下是发生的情况(回复):

我可以这样解决这个问题:

... r2 = r.add()
>>> r3 = r2.add()
>>> r4 = r3.add()
>>> r4.runs
array([ 4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.])
我怀疑这与参考计数有关?我是一个完全的新手,对此一无所知。谢谢你的帮助。此功能(或我对它的使用)很可能是罪犯:

static PyObject * Rle_add(Rle* self)
{
  int N = (int)PyArray_DIM(self->runs, 0);
  double *x = (double*)PyArray_DATA(self->runs);
  add(x, N);
  return (PyObject *)self;
}
它会在适当的位置更改阵列以提高速度,但这不会导致错误,正如您在上面的工作中看到的那样

下面是我的代码,所以这是可复制的

我有以下文件:

测试步骤c:

#include <Python.h>
#include <numpy/arrayobject.h>
#include "structmember.h"
#include "add.h"

/* static PyObject *add(PyObject *self, PyObject *args); */

typedef struct {
    PyObject_HEAD
    PyObject *runs; /* run lengths */
} Rle;


static void
Rle_dealloc(Rle* self)
{
    Py_XDECREF(self->runs);
    Py_TYPE(self)->tp_free((PyObject*)self);
}


static PyObject *
Rle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{

  printf("New was called! New was called! New was called!\n");
    Rle *self;
    PyObject *rs, *vs;

    import_array();

    if (!PyArg_ParseTuple(args, "O", &rs))
      return NULL;

    PyObject *runs = PyArray_FROM_OTF(rs, NPY_DOUBLE, NPY_IN_ARRAY);

    self = (Rle *)type->tp_alloc(type, 0);
    if (self != NULL) {

        self->runs = runs;
        if (self->runs == NULL) {
            Py_DECREF(self);
            return NULL;
        }
    }

    printf("Reference count after new: %d\n", Py_REFCNT(self));
    return (PyObject *)self;
}

static int
Rle_init(Rle *self, PyObject *args, PyObject *kwds)
{
  printf("Init was called! Init was called! Init was called!\n");

  printf("Reference count after init: %d\n", Py_REFCNT(self));
    return 0;
}


static PyMemberDef Rle_members[] = {
    {"runs", T_OBJECT_EX, offsetof(Rle, runs), 0,
     "Run lengths"},
    {NULL}  /* Sentinel */
};

static PyObject * Rle_add(Rle* self)
{
  int N = (int)PyArray_DIM(self->runs, 0);
  double *x = (double*)PyArray_DATA(self->runs);
  add(x, N);
  return (PyObject *)self;
}


static PyMethodDef Rle_methods[] = {
    {"add", (PyCFunction)Rle_add, METH_NOARGS,
     "Add 1 to the runs"
    },
    {NULL}  /* Sentinel */
};

static PyTypeObject RleType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "rle.Rle",             /* tp_name */
    sizeof(Rle),             /* tp_basicsize */
    0,                         /* tp_itemsize */
    (destructor)Rle_dealloc, /* tp_dealloc */
    0,                         /* tp_print */
    0,                         /* tp_getattr */
    0,                         /* tp_setattr */
    0,                         /* tp_reserved */
    0,                         /* tp_repr */
    0,                         /* tp_as_number */
    0,                         /* tp_as_sequence */
    0,                         /* tp_as_mapping */
    0,                         /* tp_hash  */
    0,                         /* tp_call */
    0,                         /* tp_str */
    0,                         /* tp_getattro */
    0,                         /* tp_setattro */
    0,                         /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT |
        Py_TPFLAGS_BASETYPE,   /* tp_flags */
    "Rle objects",           /* tp_doc */
    0,                         /* tp_traverse */
    0,                         /* tp_clear */
    0,                         /* tp_richcompare */
    0,                         /* tp_weaklistoffset */
    0,                         /* tp_iter */
    0,                         /* tp_iternext */
    Rle_methods,             /* tp_methods */
    Rle_members,             /* tp_members */
    0,                         /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    (initproc)Rle_init,      /* tp_init */
    0,                         /* tp_alloc */
    Rle_new,                 /* tp_new */
};

static PyModuleDef rletestmodule = {
    PyModuleDef_HEAD_INIT,
    "rletest",
    "Example module that creates an extension type.",
    -1,
    NULL, NULL, NULL, NULL, NULL
};

PyMODINIT_FUNC
PyInit_rletest(void)
{
    PyObject* m;

    if (PyType_Ready(&RleType) < 0)
        return NULL;

    m = PyModule_Create(&rletestmodule);
    if (m == NULL)
        return NULL;

    Py_INCREF(&RleType);
    PyModule_AddObject(m, "Rle", (PyObject *)&RleType);
    return m;
}
add.h

add.c:

#include <stdio.h>

void add(double *x, int N) {
  int n;

  for (n = 0; n < N; n++) {
    x[n] += 1.0;
  }
}
建造它

return (PyObject *)self;
您现在有了一个对
self
的额外引用,因此需要
incref
它。实际上,您不分配返回值,因此Python会立即
减少它,并且
r
不再存在

(您的工作区避免了立即执行
decref
,但我很惊讶它只是在以后导致分段错误。)

您现在有了一个对
self
的额外引用,因此需要
incref
它。实际上,您不分配返回值,因此Python会立即
减少它,并且
r
不再存在

(您的工作区避免了立即执行
decref
,但我很惊讶它只是在以后导致分段错误。)

void add(double *x, int N);
#include <stdio.h>

void add(double *x, int N) {
  int n;

  for (n = 0; n < N; n++) {
    x[n] += 1.0;
  }
}
python setup.py build_ext --inplace
return (PyObject *)self;