Hrvoje Niksic <[EMAIL PROTECTED]> writes: > Chris <[EMAIL PROTECTED]> writes: > >>> descr = GetAttrString(cls,"varname"); >>> offset = descr->d_member->offset; >>> slotvar = (PyObject*)(((char*)obj)+offset) >> >> Unfortunately, I am inexperienced at this kind of thing, so I wasn't >> able to get something working. Maybe someone could tell me what's >> wrong with the code below (it gives the error "'struct _object' has no >> member named 'd_member'")? > > You are getting that error because Carl forgot to cast the descriptor > to the appropriate C type, in this case PyMemberDescrObject. The last > line is also incorrect, I think. Try something like this: > > PyObject *descr = PyObject_GetAttrString(x,"attr_one");
Also note that x should be your object's type, i.e. o->ob_type cast to PyObject *. The complete incantation would be: // outside the loop PyObject *descr = PyObject_GetAttrString((PyObject *) obj->ob_type, "attr_one"); if (!descr) return NULL; int offset = ((PyMemberDescrObject *) descr)->d_member->offset; Py_DECREF(descr); // inside the loop PyObject *value = *(PyObject **)((char *)obj + offset); if (!value) { PyErr_SetString(PyExc_AttributeError, "attribute missing"); return NULL; } // Remember to Py_INCREF(value) before using it and Py_DECREF it after // using it. Otherwise if the object changes its slot to something // else, you might be using a dead object. With this code, accessing the value is practically free once the offset is calculated. Here is a bench3 function updated to use this strategy: static PyObject * bench3(PyObject *ignored, PyObject *obj) { PyObject *descr = PyObject_GetAttrString((PyObject *) obj->ob_type, "abcdef"); if (!descr) return NULL; // Here you should also assert that PyObject_TypeCheck(descr, // PyMemberDescr_Type) holds true. Since PyMemberDescr_Type is static, // you'll have to get it by stashing away ob_type of a value known to be // the descriptor. This is left as excercise to the reader. int offset = ((PyMemberDescrObject *) descr)->d_member->offset; Py_DECREF(descr); int i; PyObject *volatile attr; // 'volatile' for benchmarking, prevents gcc // from optimizing away the loop for (i = 0; i < 1000000; i++) { attr = *(PyObject **)((char *)obj + offset); } Py_INCREF(attr); return attr; // to prove that we retrieved the correct value } >>> t0 = time.time(); attr.bench3(o); t1 = time.time() 1 >>> t1-t0 0.00071597099304199219 # for 1,000,000 iterations, as cheap as it gets -- http://mail.python.org/mailman/listinfo/python-list