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 "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*/