Yet another version (by me) of __getattr__ etc.

This commit is contained in:
Guido van Rossum 1994-09-05 07:32:29 +00:00
parent e773754ae5
commit 52ca98a390
1 changed files with 51 additions and 174 deletions

View File

@ -29,6 +29,10 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "structmember.h" #include "structmember.h"
#include "ceval.h" #include "ceval.h"
/* Forward */
static object *class_lookup PROTO((classobject *, char *, classobject **));
static object *instance_getattr1 PROTO((instanceobject *, char *));
object * object *
newclassobject(bases, dict, name) newclassobject(bases, dict, name)
object *bases; /* NULL or tuple of classobjects! */ object *bases; /* NULL or tuple of classobjects! */
@ -37,7 +41,7 @@ newclassobject(bases, dict, name)
{ {
int pos; int pos;
object *key, *value; object *key, *value;
classobject *op; classobject *op, *dummy;
if (bases == NULL) { if (bases == NULL) {
bases = newtupleobject(0); bases = newtupleobject(0);
if (bases == NULL) if (bases == NULL)
@ -55,6 +59,12 @@ newclassobject(bases, dict, name)
op->cl_dict = dict; op->cl_dict = dict;
XINCREF(name); XINCREF(name);
op->cl_name = 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; pos = 0;
while (mappinggetnext(dict, &pos, &key, &value)) { while (mappinggetnext(dict, &pos, &key, &value)) {
if (is_accessobject(value)) if (is_accessobject(value))
@ -223,8 +233,6 @@ issubclass(class, base)
/* Instance objects */ /* Instance objects */
static object *instance_getattr PROTO((instanceobject *, char *));
static int static int
addaccess(class, inst) addaccess(class, inst)
classobject *class; classobject *class;
@ -285,7 +293,7 @@ newinstanceobject(class, arg)
DECREF(inst); DECREF(inst);
return NULL; return NULL;
} }
init = instance_getattr(inst, "__init__"); init = instance_getattr1(inst, "__init__");
if (init == NULL) { if (init == NULL) {
err_clear(); err_clear();
if (arg != NULL && !(is_tupleobject(arg) && if (arg != NULL && !(is_tupleobject(arg) &&
@ -328,7 +336,7 @@ instance_dealloc(inst)
revive the object and save the current exception, if any. */ revive the object and save the current exception, if any. */
INCREF(inst); INCREF(inst);
err_get(&error_type, &error_value); 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 *args = newtupleobject(0);
object *res = args; object *res = args;
if (res != NULL) if (res != NULL)
@ -348,76 +356,6 @@ instance_dealloc(inst)
free((ANY *)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 * static object *
instance_getattr1(inst, name) instance_getattr1(inst, name)
register instanceobject *inst; register instanceobject *inst;
@ -479,59 +417,23 @@ instance_getattr(inst, name)
register char *name; register char *name;
{ {
register object *func, *res; register object *func, *res;
if (name[0] == '_' && name[1] == '_') { res = instance_getattr1(inst, name);
/* Let's not compare the first "__": */ if (res == NULL && (func = inst->in_class->cl_getattr) != NULL) {
/* use &name[2] :-) */ object *args;
if (strcmp(&name[2], "setslot__") == 0) { #if 0
return newmethodobject(name, if (name[0] == '_' && name[1] == '_') {
(method)instance_setslot_meth, int n = strlen(name);
(object*)inst, if (name[n-1] == '_' && name[n-2] == '_') {
0); /* Don't mess with system attributes */
return NULL;
}
} }
if (strcmp(&name[2], "getslot__") == 0) { #endif
return newmethodobject(name, args = mkvalue("(Os)", inst, name);
(method)instance_getslot_meth, if (args == NULL)
(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);
return NULL; return NULL;
} res = call_object(func, args);
arg = newstringobject(name); DECREF(args);
/*... and call it */
res = call_object(func,arg);
DECREF(arg);
DECREF(func);
} }
return res; return res;
} }
@ -543,13 +445,6 @@ instance_setattr1(inst, name, v)
object *v; object *v;
{ {
object *ac; 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); ac = dictlookup(inst->in_dict, name);
if (ac != NULL && is_accessobject(ac)) if (ac != NULL && is_accessobject(ac))
return setaccessvalue(ac, getowner(), v); return setaccessvalue(ac, getowner(), v);
@ -570,49 +465,31 @@ instance_setattr(inst, name, v)
char *name; char *name;
object *v; object *v;
{ {
object *ac, *func; object *func, *args, *res;
classobject *class; if (name[0] == '_' && name[1] == '_') {
char* setattrname; int n = strlen(name);
/* I think I saw something in the news, that deletion of an attribute */ if (name[n-1] == '_' && name[n-2] == '_') {
/* is done by setattr with the value being NULL. */ err_setstr(TypeError, "read-only special attribute");
/* 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 :-( */
return -1; 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; return 0;
} }
@ -1107,7 +984,7 @@ static number_methods instance_as_number = {
(binaryfunc)instance_div, /*nb_divide*/ (binaryfunc)instance_div, /*nb_divide*/
(binaryfunc)instance_mod, /*nb_remainder*/ (binaryfunc)instance_mod, /*nb_remainder*/
(binaryfunc)instance_divmod, /*nb_divmod*/ (binaryfunc)instance_divmod, /*nb_divmod*/
(binaryfunc)instance_pow, /*nb_power*/ (ternaryfunc)instance_pow, /*nb_power*/
(unaryfunc)instance_neg, /*nb_negative*/ (unaryfunc)instance_neg, /*nb_negative*/
(unaryfunc)instance_pos, /*nb_positive*/ (unaryfunc)instance_pos, /*nb_positive*/
(unaryfunc)instance_abs, /*nb_absolute*/ (unaryfunc)instance_abs, /*nb_absolute*/