[Python-Dev] A bit faster access to module attributes

Wiktor Sadowski Wiktor Sadowski" <art@wiktorsadowski.com
Tue, 1 Jul 2003 03:40:23 +0200


Python module calls PyObject_GenericGetAttr/PyObject_GenericSetAttr pair
to do attribute lookup. (moduleobject.c,object.c)

IMO it adds unnecessary overhead, and could be replaced with a bit
simplified functions.

[1] To get an object's dictionary _PyObject_GetDictPtr function is used
(inlined in PyObject_GenericGetAttr).
But in module case we can get the dictionary without any call:
PyObject *dict = ((PyModuleObject *)obj)->md_dict;

[2] If module(tp)->tp_dict == NULL PyType_Ready is called in
PyObject_GenericGetAttr.
Well , I am not sure if all this stuff added to module type with
PyType_Ready
is really necessary but instead of calling _PyType_Lookup machinery a
simple:

if (strcmp(PyString_AS_STRING(name/*attr*/),"__dict__")==0)
(+  PyErr_SetString(PyExc_TypeError, "readonly attribute") for setattr
function)

could be used to access readonly module  "__dict__" attribute.

The solution I am proposing is probably less elegant than
PyObject_GenericGetAttr/PyObject_GenericSetAttr
but if it could speed up Python a bit ?

If someone would like to test such modified modules,
binaries for Windows of my small C extension - modeler.pyd are available at:
http://www.wiktorsadowski.com/Python

Importing modeler will replace module
tp_getattro/ tp_setattro with new functions,
and will enable faster access to modules' attributes.
(if no other modeler features are used)

Regards
Wiktor Sadowski
___________________________________________________________________

A new getattr for module tp_getattro could look like this:
(the settattr could be simplified as well)

PyObject *
PyObject_ModuleGetAttr(PyObject *obj, PyObject *name)
{

PyObject *res = NULL;
PyTypeObject *tp = obj->ob_type;
PyObject *dict = ((PyModuleObject *)obj)->md_dict;

/*string check stuff - no changes*/

if (dict == NULL) {  /* it shouldn't happen! */
((PyModuleObject *)obj)->md_dict=Py_DictNew();/*?*/
}

if (strcmp(PyString_AS_STRING(name),"__dict__")==0){
        Py_INCREF(dict);
        return dict;
}

res = PyDict_GetItem(dict, name);
if (res != NULL) {
Py_INCREF(res);
Py_XDECREF(name);
return res;
}

PyErr_Format(PyExc_AttributeError,
       "'%.50s' object has no attribute '%.400s'",
       tp->tp_name, PyString_AS_STRING(name));

}