In Python C API you cannot define a __getitem__ method; instead define a tp_as_mapping slot.  See:

http://docs.python.org/c-api/typeobj.html#tp_as_mapping


2009/12/23 Anita A <anitaa1981@gmail.com>
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.
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig



--
Gustavo J. A. M. Carneiro
INESC Porto, Telecommunications and Multimedia Unit
"The universe is always one step beyond logic." -- Frank Herbert