Skip to content

Commit

Permalink
Variant of patch #423262: Change module attribute get & set
Browse files Browse the repository at this point in the history
Allow module getattr and setattr to exploit string interning, via the
previously null module object tp_getattro and tp_setattro slots.   Yields
a very nice speedup for things like random.random and os.path etc.
  • Loading branch information
tim-one committed May 11, 2001
1 parent 564a6cc commit d85e102
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 34 deletions.
3 changes: 3 additions & 0 deletions Misc/NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ Core
'x in y' and 'x not in y' (PySequence_Contains() in C API)
operator.countOf() (PySequence_Count() in C API)

- Accessing module attributes is significantly faster (for example,
random.random or os.path or yourPythonModule.yourAttribute).

- Comparing dictionary objects via == and != is faster, and now works even
if the keys and values don't support comparisons other than ==.

Expand Down
69 changes: 35 additions & 34 deletions Objects/moduleobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,17 +162,18 @@ module_repr(PyModuleObject *m)
}

static PyObject *
module_getattr(PyModuleObject *m, char *name)
module_getattro(PyModuleObject *m, PyObject *name)
{
PyObject *res;
char* modname;
if (strcmp(name, "__dict__") == 0) {
char *sname = PyString_AsString(name);

if (sname[0] == '_' && strcmp(sname, "__dict__") == 0) {
Py_INCREF(m->md_dict);
return m->md_dict;
}
res = PyDict_GetItemString(m->md_dict, name);
res = PyDict_GetItem(m->md_dict, name);
if (res == NULL) {
modname = PyModule_GetName((PyObject *)m);
char *modname = PyModule_GetName((PyObject *)m);
if (modname == NULL) {
PyErr_Clear();
modname = "?";
Expand All @@ -187,30 +188,30 @@ module_getattr(PyModuleObject *m, char *name)
}

static int
module_setattr(PyModuleObject *m, char *name, PyObject *v)
module_setattro(PyModuleObject *m, PyObject *name, PyObject *v)
{
char* modname;
if (name[0] == '_' && strcmp(name, "__dict__") == 0) {
char *sname = PyString_AsString(name);
if (sname[0] == '_' && strcmp(sname, "__dict__") == 0) {
PyErr_SetString(PyExc_TypeError,
"read-only special attribute");
return -1;
}
if (v == NULL) {
int rv = PyDict_DelItemString(m->md_dict, name);
int rv = PyDict_DelItem(m->md_dict, name);
if (rv < 0) {
modname = PyModule_GetName((PyObject *)m);
char *modname = PyModule_GetName((PyObject *)m);
if (modname == NULL) {
PyErr_Clear();
modname = "?";
}
PyErr_Format(PyExc_AttributeError,
"'%.50s' module has no attribute '%.400s'",
modname, name);
modname, sname);
}
return rv;
}
else
return PyDict_SetItemString(m->md_dict, name, v);
return PyDict_SetItem(m->md_dict, name, v);
}

/* We only need a traverse function, no clear function: If the module
Expand All @@ -226,26 +227,26 @@ module_traverse(PyModuleObject *m, visitproc visit, void *arg)

PyTypeObject PyModule_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"module", /*tp_name*/
sizeof(PyModuleObject) + PyGC_HEAD_SIZE, /*tp_size*/
0, /*tp_itemsize*/
(destructor)module_dealloc, /*tp_dealloc*/
0, /*tp_print*/
(getattrfunc)module_getattr, /*tp_getattr*/
(setattrfunc)module_setattr, /*tp_setattr*/
0, /*tp_compare*/
(reprfunc)module_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/
0, /* tp_doc */
(traverseproc)module_traverse, /* tp_traverse */
0, /* ob_size */
"module", /* tp_name */
sizeof(PyModuleObject) + PyGC_HEAD_SIZE,/* tp_size */
0, /* tp_itemsize */
(destructor)module_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)module_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
(getattrofunc)module_getattro, /* tp_getattro */
(setattrofunc)module_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
0, /* tp_doc */
(traverseproc)module_traverse, /* tp_traverse */
};

0 comments on commit d85e102

Please sign in to comment.