0

I am creating an Python extension in C, for having a friendly structure and efficient usage on it. So there is a lot of source code for certain heavy operations which should be in C. And a lot of internal fields are referenced.

Now, I was going to do some aesthetic improvements: mainly the tp_repr and tp_str slots. Must I do them in C? I am thinking that doing them in Python should be easy, but coding it in C seems to be a nightmare and useless.

I have internal fields like encoded binary strings, a dictionary, and so on. Using Python features seems straightforward:

def repr_func(obj):
    return "MyObject(name='%s'.encode('utf-16-be'), id=%d, map=%s)"
            % (obj.name.decode("utf-16-be"), obj.id, repr(obj.map))

I know I could do this in C, but it seems cleaner to do it in Python. I do not need performance, those will be used for debugging and testing, so I need them to be useful and clean.

Is there some way to do this without deep changes in the C source?

MariusSiuram
  • 3,380
  • 1
  • 21
  • 40

1 Answers1

2

Like so often in programming, there are different ways to get things done.

What you're doing in Python, can be achieved in C (Pyhton 2.*) by doing something like

static PyObject * repr (Obj *self) {
    PyObject *map = PyObject_Repr(self->map);
    if (!map) return NULL;
    char *map_repr = PyString_AsString(map);
    PyObject *repr = PyString_FromFormat(
        "MyObject(name='%s'.encode('utf-16-be'), id=%d, map=%s)",
            self->name, self->id, map_repr);
    Py_DECREF(map);
    return repr;
}

and assuming the typedef of your Object is Obj and the name is of char *. If it's of PyObeject *, you could do the decoding with PyString_AsDecodedObject. In Python 3.* you might need to use the the PyUnicode_* or PyBytes_* functions.

If you want to use the functions definied in pure Python, you can do it by just importing the module, which defines these like

static PyObject * repr (Obj *self) {
    PyObject *module = PyImport_ImportModule("repr_mod");
    if (!module) return NULL;
    PyObject *repr = PyObject_CallMethod(module, "repr_func", "(O)", self);
    Py_DECREF(module);
    return repr;
}

where repr_mod would be the name of the modules.

At the end, you just need to set tp_repr to (reprfunc) repr while initialising the type.

Both ways I wouldn't consider deep changes in the C source, so maybe just what you're looking for.

tynn
  • 38,113
  • 8
  • 108
  • 143
  • whoa, I had completely missed the `PyString_FromFormat` call, and it is nice to use it in this scenario. I suppose that managing the encoding and the representation through those Python helpers seems not so nightmarish --still, `name` is not a `char *`, it is a binary utf16 string, but Python has some utility functions in C for that. – MariusSiuram Feb 01 '15 at 19:58