From 52ca98a39003cf977200cb5011bbde5271b1b1c0 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 5 Sep 1994 07:32:29 +0000 Subject: [PATCH] Yet another version (by me) of __getattr__ etc. --- Objects/classobject.c | 225 ++++++++++-------------------------------- 1 file changed, 51 insertions(+), 174 deletions(-) diff --git a/Objects/classobject.c b/Objects/classobject.c index 96011810e08..8b7e4dad649 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -29,6 +29,10 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "structmember.h" #include "ceval.h" +/* Forward */ +static object *class_lookup PROTO((classobject *, char *, classobject **)); +static object *instance_getattr1 PROTO((instanceobject *, char *)); + object * newclassobject(bases, dict, name) object *bases; /* NULL or tuple of classobjects! */ @@ -37,7 +41,7 @@ newclassobject(bases, dict, name) { int pos; object *key, *value; - classobject *op; + classobject *op, *dummy; if (bases == NULL) { bases = newtupleobject(0); if (bases == NULL) @@ -55,6 +59,12 @@ newclassobject(bases, dict, name) op->cl_dict = dict; XINCREF(name); op->cl_name = name; + op->cl_getattr = class_lookup(op, "__getattr__", &dummy); + op->cl_setattr = class_lookup(op, "__setattr__", &dummy); + op->cl_delattr = class_lookup(op, "__delattr__", &dummy); + XINCREF(op->cl_getattr); + XINCREF(op->cl_setattr); + XINCREF(op->cl_delattr); pos = 0; while (mappinggetnext(dict, &pos, &key, &value)) { if (is_accessobject(value)) @@ -223,8 +233,6 @@ issubclass(class, base) /* Instance objects */ -static object *instance_getattr PROTO((instanceobject *, char *)); - static int addaccess(class, inst) classobject *class; @@ -285,7 +293,7 @@ newinstanceobject(class, arg) DECREF(inst); return NULL; } - init = instance_getattr(inst, "__init__"); + init = instance_getattr1(inst, "__init__"); if (init == NULL) { err_clear(); if (arg != NULL && !(is_tupleobject(arg) && @@ -328,7 +336,7 @@ instance_dealloc(inst) revive the object and save the current exception, if any. */ INCREF(inst); err_get(&error_type, &error_value); - if ((del = instance_getattr(inst, "__del__")) != NULL) { + if ((del = instance_getattr1(inst, "__del__")) != NULL) { object *args = newtupleobject(0); object *res = args; if (res != NULL) @@ -348,76 +356,6 @@ instance_dealloc(inst) free((ANY *)inst); } -static object *instance_getattr1(); -static int instance_setattr1(); - -static object * -instance_getslot_meth(self, args) - instanceobject *self; - object *args; -{ - object *v; - char *name; - if (!getargs(args, "s", &name)) - return NULL; - return instance_getattr1(self, name); -} - -static object * -instance_hasslot_meth(self, args) - instanceobject *self; - object *args; -{ - object *v; - char *name; - if (!getargs(args, "s", &name)) - return NULL; - v = instance_getattr1(self, name); - if (v == NULL) { - err_clear(); - return newintobject(0L); - } - DECREF(v); - return newintobject(1L); -} - -static object * -instance_setslot_meth(self, args) - instanceobject *self; - object *args; -{ - char*name; - object*value; - value = NULL; - if (!getargs(args, "s", &name)) { - err_clear(); - if (!getargs(args, "(sO)", &name, &value)) - return NULL; - } - if(instance_setattr1(self, name, value)<0) { - return NULL; - } - INCREF(None); - return None; -} - -static object * -instance_delslot_meth(self, args) - instanceobject *self; - object *args; -{ - char*name; - if (!getargs(args, "s", &name)) { - return NULL; - } - if(instance_setattr1(self, name, 0)<0) { - return NULL; - } - INCREF(None); - return None; -} - - static object * instance_getattr1(inst, name) register instanceobject *inst; @@ -479,59 +417,23 @@ instance_getattr(inst, name) register char *name; { register object *func, *res; - if (name[0] == '_' && name[1] == '_') { - /* Let's not compare the first "__": */ - /* use &name[2] :-) */ - if (strcmp(&name[2], "setslot__") == 0) { - return newmethodobject(name, - (method)instance_setslot_meth, - (object*)inst, - 0); + res = instance_getattr1(inst, name); + if (res == NULL && (func = inst->in_class->cl_getattr) != NULL) { + object *args; +#if 0 + if (name[0] == '_' && name[1] == '_') { + int n = strlen(name); + if (name[n-1] == '_' && name[n-2] == '_') { + /* Don't mess with system attributes */ + return NULL; + } } - if (strcmp(&name[2], "getslot__") == 0) { - return newmethodobject(name, - (method)instance_getslot_meth, - (object*)inst, - 0); - } - if (strcmp(&name[2], "hasslot__") == 0) { - return newmethodobject(name, - (method)instance_hasslot_meth, - (object*)inst, - 0); - } - if (strcmp(&name[2], "delslot__") == 0) { - return newmethodobject(name, - (method)instance_delslot_meth, - (object*)inst, - 0); - } - /* The following methods should not be forwarded! */ - if ( strcmp(&name[2], "init__") == 0 - || strcmp(&name[2], "del__") == 0) { - return instance_getattr1(inst,name); - } - } - res=instance_getattr1(inst,name); - if (res == NULL) { - /* Self doesn't have this attribute, */ - /* so let's try to call self.__getattr__(name) */ - object* func; - object *arg; - /* Well, lets get a funcobject for __getattr__ ...*/ - func = instance_getattr1(inst,"__getattr__"); - if (func == NULL) { - /* OOPS, we don't have a __getattr__. */ - /* Set the error ... */ - err_clear(); - err_setstr(AttributeError, name); +#endif + args = mkvalue("(Os)", inst, name); + if (args == NULL) return NULL; - } - arg = newstringobject(name); - /*... and call it */ - res = call_object(func,arg); - DECREF(arg); - DECREF(func); + res = call_object(func, args); + DECREF(args); } return res; } @@ -543,13 +445,6 @@ instance_setattr1(inst, name, v) object *v; { object *ac; - if (name[0] == '_' && name[1] == '_') { - int n = strlen(name); - if (name[n-1] == '_' && name[n-2] == '_') { - err_setstr(TypeError, "read-only special attribute"); - return -1; - } - } ac = dictlookup(inst->in_dict, name); if (ac != NULL && is_accessobject(ac)) return setaccessvalue(ac, getowner(), v); @@ -570,49 +465,31 @@ instance_setattr(inst, name, v) char *name; object *v; { - object *ac, *func; - classobject *class; - char* setattrname; - /* I think I saw something in the news, that deletion of an attribute */ - /* is done by setattr with the value being NULL. */ - /* Let's be prepared for this case :-)*/ - if (v != NULL) - setattrname = "__setattr__"; - else - setattrname = "__delattr__"; - - /* Here is the only performance loss: */ - /* We have to check if there is a method __setattr__.*/ - /* Only class can have a __setattr__ because it's forbidden to */ - /* assign to self.__setattr__.*/ - /* So, lets do a class_lookup which is (hopefully) cheap */ - class = NULL; - func = class_lookup(inst->in_class, setattrname, &class); - if (func == NULL) { - /* Call the original instance_setattr */ - return instance_setattr1(inst,name,v); - } else { - object *arg, *res; - /* class_lookup did'nt REF(func) - so we won't UNREF(func). */ - /* Let's get the function (could be optimized....) */ - func = instance_getattr(inst,setattrname); - if (func == 0) - return -1; - /* Deleting an attribute is done by v==NULL */ - if (v == NULL) - /* __delattr__ has only one argument: the name */ - arg = mkvalue("s",name); - else - arg = mkvalue("(sO)",name,v); - res = call_object(func,arg); - DECREF(func); - DECREF(arg); - if (res == NULL) { - /* Oops, something went wrong :-( */ + object *func, *args, *res; + if (name[0] == '_' && name[1] == '_') { + int n = strlen(name); + if (name[n-1] == '_' && name[n-2] == '_') { + err_setstr(TypeError, "read-only special attribute"); return -1; } - DECREF(res); } + if (v == NULL) + func = inst->in_class->cl_delattr; + else + func = inst->in_class->cl_setattr; + if (func == NULL) + return instance_setattr1(inst, name, v); + if (v == NULL) + args = mkvalue("(Os)", inst, name); + else + args = mkvalue("(OsO)", inst, name, v); + if (args == NULL) + return -1; + res = call_object(func, args); + DECREF(args); + if (res == NULL) + return -1; + DECREF(res); return 0; } @@ -1107,7 +984,7 @@ static number_methods instance_as_number = { (binaryfunc)instance_div, /*nb_divide*/ (binaryfunc)instance_mod, /*nb_remainder*/ (binaryfunc)instance_divmod, /*nb_divmod*/ - (binaryfunc)instance_pow, /*nb_power*/ + (ternaryfunc)instance_pow, /*nb_power*/ (unaryfunc)instance_neg, /*nb_negative*/ (unaryfunc)instance_pos, /*nb_positive*/ (unaryfunc)instance_abs, /*nb_absolute*/