Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d85e102

Browse files
committed
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.
1 parent 564a6cc commit d85e102

2 files changed

Lines changed: 38 additions & 34 deletions

File tree

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ Core
4444
'x in y' and 'x not in y' (PySequence_Contains() in C API)
4545
operator.countOf() (PySequence_Count() in C API)
4646

47+
- Accessing module attributes is significantly faster (for example,
48+
random.random or os.path or yourPythonModule.yourAttribute).
49+
4750
- Comparing dictionary objects via == and != is faster, and now works even
4851
if the keys and values don't support comparisons other than ==.
4952

Objects/moduleobject.c

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,18 @@ module_repr(PyModuleObject *m)
162162
}
163163

164164
static PyObject *
165-
module_getattr(PyModuleObject *m, char *name)
165+
module_getattro(PyModuleObject *m, PyObject *name)
166166
{
167167
PyObject *res;
168-
char* modname;
169-
if (strcmp(name, "__dict__") == 0) {
168+
char *sname = PyString_AsString(name);
169+
170+
if (sname[0] == '_' && strcmp(sname, "__dict__") == 0) {
170171
Py_INCREF(m->md_dict);
171172
return m->md_dict;
172173
}
173-
res = PyDict_GetItemString(m->md_dict, name);
174+
res = PyDict_GetItem(m->md_dict, name);
174175
if (res == NULL) {
175-
modname = PyModule_GetName((PyObject *)m);
176+
char *modname = PyModule_GetName((PyObject *)m);
176177
if (modname == NULL) {
177178
PyErr_Clear();
178179
modname = "?";
@@ -187,30 +188,30 @@ module_getattr(PyModuleObject *m, char *name)
187188
}
188189

189190
static int
190-
module_setattr(PyModuleObject *m, char *name, PyObject *v)
191+
module_setattro(PyModuleObject *m, PyObject *name, PyObject *v)
191192
{
192-
char* modname;
193-
if (name[0] == '_' && strcmp(name, "__dict__") == 0) {
193+
char *sname = PyString_AsString(name);
194+
if (sname[0] == '_' && strcmp(sname, "__dict__") == 0) {
194195
PyErr_SetString(PyExc_TypeError,
195196
"read-only special attribute");
196197
return -1;
197198
}
198199
if (v == NULL) {
199-
int rv = PyDict_DelItemString(m->md_dict, name);
200+
int rv = PyDict_DelItem(m->md_dict, name);
200201
if (rv < 0) {
201-
modname = PyModule_GetName((PyObject *)m);
202+
char *modname = PyModule_GetName((PyObject *)m);
202203
if (modname == NULL) {
203204
PyErr_Clear();
204205
modname = "?";
205206
}
206207
PyErr_Format(PyExc_AttributeError,
207208
"'%.50s' module has no attribute '%.400s'",
208-
modname, name);
209+
modname, sname);
209210
}
210211
return rv;
211212
}
212213
else
213-
return PyDict_SetItemString(m->md_dict, name, v);
214+
return PyDict_SetItem(m->md_dict, name, v);
214215
}
215216

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

227228
PyTypeObject PyModule_Type = {
228229
PyObject_HEAD_INIT(&PyType_Type)
229-
0, /*ob_size*/
230-
"module", /*tp_name*/
231-
sizeof(PyModuleObject) + PyGC_HEAD_SIZE, /*tp_size*/
232-
0, /*tp_itemsize*/
233-
(destructor)module_dealloc, /*tp_dealloc*/
234-
0, /*tp_print*/
235-
(getattrfunc)module_getattr, /*tp_getattr*/
236-
(setattrfunc)module_setattr, /*tp_setattr*/
237-
0, /*tp_compare*/
238-
(reprfunc)module_repr, /*tp_repr*/
239-
0, /*tp_as_number*/
240-
0, /*tp_as_sequence*/
241-
0, /*tp_as_mapping*/
242-
0, /* tp_hash */
243-
0, /* tp_call */
244-
0, /* tp_str */
245-
0, /* tp_getattro */
246-
0, /* tp_setattro */
247-
0, /* tp_as_buffer */
248-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/
249-
0, /* tp_doc */
250-
(traverseproc)module_traverse, /* tp_traverse */
230+
0, /* ob_size */
231+
"module", /* tp_name */
232+
sizeof(PyModuleObject) + PyGC_HEAD_SIZE,/* tp_size */
233+
0, /* tp_itemsize */
234+
(destructor)module_dealloc, /* tp_dealloc */
235+
0, /* tp_print */
236+
0, /* tp_getattr */
237+
0, /* tp_setattr */
238+
0, /* tp_compare */
239+
(reprfunc)module_repr, /* tp_repr */
240+
0, /* tp_as_number */
241+
0, /* tp_as_sequence */
242+
0, /* tp_as_mapping */
243+
0, /* tp_hash */
244+
0, /* tp_call */
245+
0, /* tp_str */
246+
(getattrofunc)module_getattro, /* tp_getattro */
247+
(setattrofunc)module_setattro, /* tp_setattro */
248+
0, /* tp_as_buffer */
249+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
250+
0, /* tp_doc */
251+
(traverseproc)module_traverse, /* tp_traverse */
251252
};

0 commit comments

Comments
 (0)