Yet another version (by me) of __getattr__ etc.
This commit is contained in:
parent
e773754ae5
commit
52ca98a390
|
@ -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*/
|
||||
|
|
Loading…
Reference in New Issue