Commit e325d70b authored by Tim Peters's avatar Tim Peters

Variant of patch #423262: Change module attribute get & set

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.
parent 8af5a167
...@@ -44,6 +44,9 @@ Core ...@@ -44,6 +44,9 @@ Core
'x in y' and 'x not in y' (PySequence_Contains() in C API) 'x in y' and 'x not in y' (PySequence_Contains() in C API)
operator.countOf() (PySequence_Count() 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 - Comparing dictionary objects via == and != is faster, and now works even
if the keys and values don't support comparisons other than ==. if the keys and values don't support comparisons other than ==.
......
...@@ -162,17 +162,18 @@ module_repr(PyModuleObject *m) ...@@ -162,17 +162,18 @@ module_repr(PyModuleObject *m)
} }
static PyObject * static PyObject *
module_getattr(PyModuleObject *m, char *name) module_getattro(PyModuleObject *m, PyObject *name)
{ {
PyObject *res; PyObject *res;
char* modname; char *sname = PyString_AsString(name);
if (strcmp(name, "__dict__") == 0) {
if (sname[0] == '_' && strcmp(sname, "__dict__") == 0) {
Py_INCREF(m->md_dict); Py_INCREF(m->md_dict);
return m->md_dict; return m->md_dict;
} }
res = PyDict_GetItemString(m->md_dict, name); res = PyDict_GetItem(m->md_dict, name);
if (res == NULL) { if (res == NULL) {
modname = PyModule_GetName((PyObject *)m); char *modname = PyModule_GetName((PyObject *)m);
if (modname == NULL) { if (modname == NULL) {
PyErr_Clear(); PyErr_Clear();
modname = "?"; modname = "?";
...@@ -187,30 +188,30 @@ module_getattr(PyModuleObject *m, char *name) ...@@ -187,30 +188,30 @@ module_getattr(PyModuleObject *m, char *name)
} }
static int static int
module_setattr(PyModuleObject *m, char *name, PyObject *v) module_setattro(PyModuleObject *m, PyObject *name, PyObject *v)
{ {
char* modname; char *sname = PyString_AsString(name);
if (name[0] == '_' && strcmp(name, "__dict__") == 0) { if (sname[0] == '_' && strcmp(sname, "__dict__") == 0) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"read-only special attribute"); "read-only special attribute");
return -1; return -1;
} }
if (v == NULL) { if (v == NULL) {
int rv = PyDict_DelItemString(m->md_dict, name); int rv = PyDict_DelItem(m->md_dict, name);
if (rv < 0) { if (rv < 0) {
modname = PyModule_GetName((PyObject *)m); char *modname = PyModule_GetName((PyObject *)m);
if (modname == NULL) { if (modname == NULL) {
PyErr_Clear(); PyErr_Clear();
modname = "?"; modname = "?";
} }
PyErr_Format(PyExc_AttributeError, PyErr_Format(PyExc_AttributeError,
"'%.50s' module has no attribute '%.400s'", "'%.50s' module has no attribute '%.400s'",
modname, name); modname, sname);
} }
return rv; return rv;
} }
else 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 /* We only need a traverse function, no clear function: If the module
...@@ -226,26 +227,26 @@ module_traverse(PyModuleObject *m, visitproc visit, void *arg) ...@@ -226,26 +227,26 @@ module_traverse(PyModuleObject *m, visitproc visit, void *arg)
PyTypeObject PyModule_Type = { PyTypeObject PyModule_Type = {
PyObject_HEAD_INIT(&PyType_Type) PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/ 0, /* ob_size */
"module", /*tp_name*/ "module", /* tp_name */
sizeof(PyModuleObject) + PyGC_HEAD_SIZE, /*tp_size*/ sizeof(PyModuleObject) + PyGC_HEAD_SIZE,/* tp_size */
0, /*tp_itemsize*/ 0, /* tp_itemsize */
(destructor)module_dealloc, /*tp_dealloc*/ (destructor)module_dealloc, /* tp_dealloc */
0, /*tp_print*/ 0, /* tp_print */
(getattrfunc)module_getattr, /*tp_getattr*/ 0, /* tp_getattr */
(setattrfunc)module_setattr, /*tp_setattr*/ 0, /* tp_setattr */
0, /*tp_compare*/ 0, /* tp_compare */
(reprfunc)module_repr, /*tp_repr*/ (reprfunc)module_repr, /* tp_repr */
0, /*tp_as_number*/ 0, /* tp_as_number */
0, /*tp_as_sequence*/ 0, /* tp_as_sequence */
0, /*tp_as_mapping*/ 0, /* tp_as_mapping */
0, /* tp_hash */ 0, /* tp_hash */
0, /* tp_call */ 0, /* tp_call */
0, /* tp_str */ 0, /* tp_str */
0, /* tp_getattro */ (getattrofunc)module_getattro, /* tp_getattro */
0, /* tp_setattro */ (setattrofunc)module_setattro, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
(traverseproc)module_traverse, /* tp_traverse */ (traverseproc)module_traverse, /* tp_traverse */
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment