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 "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*/
|
||||||
|
|
Loading…
Reference in New Issue