From: Jeremy Hylton Date: Wed, 26 Apr 2000 20:39:20 +0000 (+0000) Subject: potentially useless optimization X-Git-Tag: v2.0b1~1927 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9e392e2412308c7923195f226510bb1f174be215;p=python potentially useless optimization The previous checkin (2.84) added a PyErr_Format call that made the cost of raising an AttributeError much more expensive. In general this doesn't matter, except that checks for __init__ and __del__ methods, where exceptions are caught and cleared in C, also got much more expensive. The fix is to split instance_getattr1 into two calls: instance_getattr2 checks the instance and the class for the attribute and returns it or returns NULL on error. It does not raise an exception. instance_getattr1 does rexec checks, then calls instance_getattr2. It raises an exception if instance_getattr2 returns NULL. PyInstance_New and instance_dealloc now call instance_getattr2 directly. --- diff --git a/Objects/classobject.c b/Objects/classobject.c index 4fb1167489..6c7dba5f4e 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -38,6 +38,7 @@ PERFORMANCE OF THIS SOFTWARE. static PyObject *class_lookup Py_PROTO((PyClassObject *, PyObject *, PyClassObject **)); static PyObject *instance_getattr1 Py_PROTO((PyInstanceObject *, PyObject *)); +static PyObject *instance_getattr2 Py_PROTO((PyInstanceObject *, PyObject *)); static PyObject *getattrstr, *setattrstr, *delattrstr; @@ -456,9 +457,8 @@ PyInstance_New(class, arg, kw) } if (initstr == NULL) initstr = PyString_InternFromString("__init__"); - init = instance_getattr1(inst, initstr); + init = instance_getattr2(inst, initstr); if (init == NULL) { - PyErr_Clear(); if ((arg != NULL && (!PyTuple_Check(arg) || PyTuple_Size(arg) != 0)) || (kw != NULL && (!PyDict_Check(kw) || @@ -515,7 +515,7 @@ instance_dealloc(inst) PyErr_Fetch(&error_type, &error_value, &error_traceback); if (delstr == NULL) delstr = PyString_InternFromString("__del__"); - if ((del = instance_getattr1(inst, delstr)) != NULL) { + if ((del = instance_getattr2(inst, delstr)) != NULL) { PyObject *res = PyEval_CallObject(del, (PyObject *)NULL); if (res == NULL) { PyObject *f, *t, *v, *tb; @@ -571,7 +571,6 @@ instance_getattr1(inst, name) { register PyObject *v; register char *sname = PyString_AsString(name); - PyClassObject *class; if (sname[0] == '_' && sname[1] == '_') { if (strcmp(sname, "__dict__") == 0) { if (PyEval_GetRestricted()) { @@ -587,17 +586,27 @@ instance_getattr1(inst, name) return (PyObject *)inst->in_class; } } + v = instance_getattr2(inst, name); + if (v == NULL) { + PyErr_Format(PyExc_AttributeError,"'%.50s' instance has no attribute '%.400s'", + PyString_AS_STRING(inst->in_class->cl_name), sname); + } + return v; +} + +static PyObject * +instance_getattr2(inst, name) + register PyInstanceObject *inst; + PyObject *name; +{ + register PyObject *v; + PyClassObject *class; class = NULL; v = PyDict_GetItem(inst->in_dict, name); if (v == NULL) { v = class_lookup(inst->in_class, name, &class); - if (v == NULL) { - PyErr_Format(PyExc_AttributeError, - "'%.50s' instance has no attribute '%.400s'", - PyString_AsString(inst->in_class->cl_name), - sname); - return NULL; - } + if (v == NULL) + return v; } Py_INCREF(v); if (class != NULL) {