1

I have created getsetters for a public variable number_bananas I have in my Box class. number_bananas is public because the box is unlocked, anyone can eat bananas or put more in the box.

Here is my PyBox type:

typedef struct 
{
    PyObject_HEAD
    Box *bx;
} PyBox;

In my Box class I have defined:

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;       
}

and here are the get/setters I have defined:

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}
};

The constructor I have used to instantiate the Box class is defined by:

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;
}

The module compiles successfully. However, I cannot find how to access the property number_bananas from Python.

The following results in Fatal error (segfault):

import adventureIsland

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

print(bo.number_bananas)

So... my question is how do I access/set the number_bananas from Python?

Thanks!

1 Answer 1

1

self->bx->number_bananas is not a PyObject* so can't be increfed or decrefed. Instead you want to be converting it to/from a PyObject*. In Python3 you do this with various PyLong_* functions.

Some untested code would be:

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;
}

Potentially there might be problems with too large numbers if int (number_of_bananas) and long (the result of PyLong_AsLong) aren't the same size, which it might be worth you trying to identify and raise an exception.


You were having further issues due to a constructor problem:

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

This sets bx to point to a temporary Box that stops existing almost as soon as it is created. What you should be doing is allocating a Box on the heap using the new operator. (What's happening now is that the memory you're pointing to is being reused in other functions so the "value" is changing in confusing ways).

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

You should then make sure you delete this in the destructor (to avoid a memory leak).

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks! However, when I run print(bo.number_bananas) i get a random negative number. In my Box::box() i have defined number_bananas = 11; Why is it not getting the value of number_bananas right?
The big bit of code you haven't included is the constructor for PyBox. At a guess you haven't set PyBox->bx to point at a valid Box (or you've possibly set it to point at a local variable or something like that).
Thanks! I have updated my question with the constructor. It is weird because i cannot access the attirbutes of PyBox, but I can exercise its methods.
I will create a new question for this, as my question is getting a bit messy!
@PintoDoido See edit - it's a constructor problem (as I guessed). It's easily fixed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.