In Python C API you cannot define a __getitem__ method; instead define a tp_as_mapping slot. See:<div><br></div><div><a href="http://docs.python.org/c-api/typeobj.html#tp_as_mapping">http://docs.python.org/c-api/typeobj.html#tp_as_mapping</a></div>
<div><br><br><div class="gmail_quote">2009/12/23 Anita A <span dir="ltr"><<a href="mailto:anitaa1981@gmail.com">anitaa1981@gmail.com</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Hi all,<br>
<br>
I am trying to implement a subscriptable type in c++ (equivalent to python<br>
dict), but I get a 'type is unsubscriptable' error. Here is a minimal<br>
code sample I tried:<br>
<br>
--------------------------------------------------------------------------<br>
#include <Python.h><br>
#include <iostream><br>
#include "pyerror.hpp"<br>
<br>
/////////////////////////////////////////////////////////<br>
PyObject* getitem(PyObject* self, PyObject* args)<br>
{<br>
std::cout << "getitem" << std::endl;<br>
return PyString_FromString("this is an item");<br>
}<br>
<br>
PyMethodDef method[] = {<br>
{"__getitem__", &getitem, METH_VARARGS, ""},<br>
{0, 0, 0, 0}<br>
};<br>
<br>
static PyMethodDef module_methods[] = {<br>
{ 0, 0, 0, 0 }<br>
};<br>
<br>
struct MyObject<br>
{<br>
PyObject_HEAD<br>
};<br>
<br>
extern const char* code;<br>
<br>
int main(int argc, char *argv[])<br>
{<br>
Py_InitializeEx(0);<br>
<br>
PyObject* myModule = Py_InitModule3("test", module_methods, "test module");<br>
assert(myModule);<br>
<br>
PyTypeObject myType;<br>
memset(&myType, 0, sizeof(PyTypeObject));<br>
<br>
myType.tp_name = "myType";<br>
myType.tp_basicsize = sizeof(MyObject);<br>
myType.tp_methods = method;<br>
if (PyType_Ready(&myType) < 0)<br>
{<br>
std::cout << "type error" << std::endl;<br>
return 1;<br>
}<br>
<br>
PyModule_AddObject(myModule, myType.tp_name, (PyObject*)&myType);<br>
<br>
PyObject* m = PyImport_AddModule("__main__");<br>
PyObject* d = PyModule_GetDict(m);<br>
MyObject* odef = PyObject_New(MyObject, &myType);<br>
PyDict_SetItemString(d, "obj", (PyObject*)odef);<br>
<br>
PyObject* rv = PyRun_String(code, Py_file_input, d, d);<br>
if(rv == 0)<br>
{<br>
std::cout << "run error" << std::endl;<br>
printException();<br>
return 1;<br>
}<br>
<br>
Py_Finalize();<br>
std::cout << "Done.\n";<br>
<br>
return 0;<br>
}<br>
<br>
const char* code =<br>
"print dir(obj)\n"<br>
"x = obj.__getitem__(1)\n"<br>
"print 'direct call:', x\n"<br>
"x = obj[1]\n"<br>
;<br>
<br>
--------------------------------------------------------------------------<br>
Compile and run session.<br>
--------------------------------------------------------------------------<br>
$ g++ -I/usr/include/python2.6 pymin.cpp -lpython2.6<br>
$ ./a.out<br>
['__class__', '__delattr__', '__doc__', '__format__',<br>
'__getattribute__', '__getitem__', '__hash__', '__init__', '__new__',<br>
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__',<br>
'__sizeof__', '__str__', '__subclasshook__']<br>
getitem<br>
direct call: this is an item<br>
run error<br>
Error in execution:<br>
Traceback (most recent call last):<br>
line 4, in ??<br>
<type 'exceptions.TypeError'>: 'myType' object is unsubscriptable<br>
--------------------------------------------------------------------------<br>
<br>
As you can see, when I call __getitem__() directly, it works, but when I<br>
call it as a subscriptable object, I get an error. What am I missing?<br>
<br>
A simple python equivalent class works as expected:<br>
--------------------------------------------------------------------------<br>
class Testi:<br>
def __getitem__(self, idx):<br>
return 10<br>
<br>
if __name__ == '__main__':<br>
x = Testi()<br>
print dir(x)<br>
print x['a']<br>
--------------------------------------------------------------------------<br>
Run session.<br>
--------------------------------------------------------------------------<br>
$ python tst.py<br>
['__doc__', '__getitem__', '__module__']<br>
10<br>
--------------------------------------------------------------------------<br>
<br>
I had tried using the PyMappingMethods structure as documented, but there<br>
is apparently no way to implement the __contains__() method, that is, to<br>
check if a key is present in the dict.<br>
<br>
Any help would be appreciated.<br>
_______________________________________________<br>
Cplusplus-sig mailing list<br>
<a href="mailto:Cplusplus-sig@python.org">Cplusplus-sig@python.org</a><br>
<a href="http://mail.python.org/mailman/listinfo/cplusplus-sig" target="_blank">http://mail.python.org/mailman/listinfo/cplusplus-sig</a><br>
</blockquote></div><br><br clear="all"><br>-- <br>Gustavo J. A. M. Carneiro<br>INESC Porto, Telecommunications and Multimedia Unit<br>"The universe is always one step beyond logic." -- Frank Herbert<br>
</div>