Python C ++ API-如何从Python访问/设置类属性?

时间:2019-05-10 16:52:44

标签: python-c-api

我为我的 Box 类中的公共变量 number_bananas 创建了getsetter。 number_bananas 是公开的,因为盒子已解锁,任何人都可以吃香蕉或在盒子中放更多东西。

这是我的PyBox类型:

typedef struct 
{
    PyObject_HEAD
    Box *bx;
} PyBox;

在Box类中,我定义了:

class Box {
   public:
      Box(double l, double b, double h);
      int number_bananas;
   ...

Box::Box(double l, double b, double h)
{
        number_bananas = 11;
        length         = l;
        breadth        = b;
        height         = h;       
}

这是我定义的get / setter:

static PyObject *pyBox_getBananas(PyBox *self, void *closure)
{
    Py_INCREF(self->bx->number_bananas);
    return self->bx->number_bananas;
}

static int pyBox_setBananas(PyBox *self, PyObject *value, void *closure)
{
    if (value == NULL) {
        PyErr_SetString(PyExc_TypeError, "You're trying to put something that is not a banana!!");
        return -1;
    }

    Py_DECREF(self->bx->number_bananas);
    Py_INCREF(value);
    self->bx->number_bananas = value;

    return 0;
}

static PyGetSetDef pyBox_getseters[] = {
    {"number_bananas", (getter)pyBox_getBananas, (setter)pyBox_setBananas, "number of bananas", NULL},
    {NULL}
};

我用来实例化Box类的构造函数由以下方式定义:

static int pyBox_init(PyObject *self, PyObject *args, PyObject *kwds)
{
    static char* nams[] = {"length","breadth","height", NULL};
    int l, b, h;
    if(!PyArg_ParseTupleAndKeywords(args, kwds, "iii", nams, &l, &b, &h))
        return -1;

    ((PyBox *)self)->bx = &(Box::Box(l,b,h));

    return 0;
}

static PyObject *pyBox_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    PyBox *self;
    self = (PyBox *) type->tp_alloc(type, 0);

    return (PyObject *)self;
}

模块编译成功。但是,我找不到如何从Python访问属性 number_bananas

以下结果将导致致命错误(段错误):

import adventureIsland

bo = adventureIsland.box(1,1,1)

print(bo.number_bananas)

所以...我的问题是如何从Python访问/设置 number_bananas

谢谢!

1 个答案:

答案 0 :(得分:1)

self->bx->number_bananas不是PyObject*,因此不能增加或减少。相反,您想将其与PyObject*之间进行转换。在Python3中,您可以使用various PyLong_* functions进行此操作。

一些未经测试的代码是:

static PyObject *pyBox_getBananas(PyBox *self, void *closure)
{
    return PyLong_FromLong(self->bx->number_bananas);
}

static int pyBox_setBananas(PyBox *self, PyObject *value, void *closure)
{
    if (value == NULL) {
        PyErr_SetString(PyExc_TypeError, "You're trying delete the attribute!!");
        return -1;
    }

    int valuei = PyLong_AsLong(value);
    if (valuei==-1 and PyErr_Occurrred()) {
        return -1;
    }

    self->bx->number_bananas = valuei;

    return 0;
}

如果intnumber_of_bananas)和longPyLong_AsLong的结果)的大小不同,则可能存在太大的数字问题。可能值得您尝试识别并引发异常。


由于构造函数问题,您还有其他问题:

((PyBox *)self)->bx = &(Box::Box(l,b,h));

这会将bx设置为指向临时Box,该临时{几乎立即在创建后就停止存在。您应该做的是使用Box运算符在堆上分配new。 (现在发生的事情是,您指向的内存正在其他功能中重用,因此“值”以令人困惑的方式发生了变化。)

((PyBox *)self)->bx = new Box::Box(l,b,h);

然后,请确保在析构函数中delete(以避免内存泄漏)。