[C++-sig] Trying to implement subscriptable type in c++.

Anita A anitaa1981 at gmail.com
Wed Dec 23 04:20:31 CET 2009


Hi all,

I am trying to implement a subscriptable type in c++ (equivalent to python
dict), but I get a 'type is unsubscriptable' error. Here is a minimal
code sample I tried:

--------------------------------------------------------------------------
#include <Python.h>
#include <iostream>
#include "pyerror.hpp"

/////////////////////////////////////////////////////////
PyObject* getitem(PyObject* self, PyObject* args)
{
    std::cout << "getitem" << std::endl;
    return PyString_FromString("this is an item");
}

PyMethodDef method[] = {
     {"__getitem__", &getitem, METH_VARARGS, ""},
     {0, 0, 0, 0}
};

static PyMethodDef module_methods[] = {
     { 0, 0, 0, 0 }
};

struct MyObject
{
    PyObject_HEAD
};

extern const char* code;

int main(int argc, char *argv[])
{
    Py_InitializeEx(0);

    PyObject* myModule = Py_InitModule3("test", module_methods, "test module");
    assert(myModule);

    PyTypeObject myType;
    memset(&myType, 0, sizeof(PyTypeObject));

    myType.tp_name = "myType";
    myType.tp_basicsize = sizeof(MyObject);
    myType.tp_methods = method;
    if (PyType_Ready(&myType) < 0)
    {
        std::cout << "type error" << std::endl;
        return 1;
    }

    PyModule_AddObject(myModule, myType.tp_name, (PyObject*)&myType);

    PyObject* m = PyImport_AddModule("__main__");
    PyObject* d = PyModule_GetDict(m);
    MyObject* odef = PyObject_New(MyObject, &myType);
    PyDict_SetItemString(d, "obj", (PyObject*)odef);

    PyObject* rv = PyRun_String(code, Py_file_input, d, d);
    if(rv == 0)
    {
        std::cout << "run error" << std::endl;
        printException();
        return 1;
    }

    Py_Finalize();
    std::cout << "Done.\n";

    return 0;
}

const char* code =
"print dir(obj)\n"
"x = obj.__getitem__(1)\n"
"print 'direct call:', x\n"
"x = obj[1]\n"
;

--------------------------------------------------------------------------
Compile and run session.
--------------------------------------------------------------------------
$ g++ -I/usr/include/python2.6 pymin.cpp -lpython2.6
$ ./a.out
['__class__', '__delattr__', '__doc__', '__format__',
'__getattribute__', '__getitem__', '__hash__', '__init__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__']
getitem
direct call: this is an item
run error
Error in execution:
Traceback (most recent call last):
line 4, in ??
<type 'exceptions.TypeError'>: 'myType' object is unsubscriptable
--------------------------------------------------------------------------

As you can see, when I call __getitem__() directly, it works, but when I
call it as a subscriptable object, I get an error. What am I missing?

A simple python equivalent class works as expected:
--------------------------------------------------------------------------
class Testi:
    def __getitem__(self, idx):
        return 10

if __name__ == '__main__':
    x = Testi()
    print dir(x)
    print x['a']
--------------------------------------------------------------------------
Run session.
--------------------------------------------------------------------------
$ python tst.py
['__doc__', '__getitem__', '__module__']
10
--------------------------------------------------------------------------

I had tried using the PyMappingMethods structure as documented, but there
is apparently no way to implement the __contains__() method, that is, to
check if a key is present in the dict.

Any help would be appreciated.


More information about the Cplusplus-sig mailing list