From e149fa2a1e34d18497579fff198c7ac2feb19096 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 12 Aug 1994 12:49:46 +0000 Subject: [PATCH] * Objects/classobject.c, Include/classobject.h: added __getattr__ and __setattr__ support to override getattr(x, name) and setattr(x, name, value) for class instances. This uses a special hack whereby the class is supposed to be static: the __getattr__ and __setattr__ methods are looked up only once and saved in the instance structure for speed --- Include/classobject.h | 12 +++++ Objects/classobject.c | 116 +++++++++++++++++++++++++++++++++++------- 2 files changed, 111 insertions(+), 17 deletions(-) diff --git a/Include/classobject.h b/Include/classobject.h index bd6cc1dffb5..6b1b85b44ee 100644 --- a/Include/classobject.h +++ b/Include/classobject.h @@ -30,6 +30,12 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* Class object interface */ +#ifdef WITH_THREAD +#include "thread.h" +#else +#define get_thread_ident() 1L +#endif + /* Revealing some structures (not for general use) */ typedef struct { @@ -43,6 +49,12 @@ typedef struct { OB_HEAD classobject *in_class; /* The class object */ object *in_dict; /* A dictionary */ + object *in_getattr; /* A method or NULL */ + object *in_setattr; /* A method or NULL */ + long in_ident; /* A thread ident or 0 */ +#ifdef WITH_THREAD + type_lock *in_lock; /* A lock or NULL */ +#endif } instanceobject; extern typeobject Classtype, Instancetype, Instancemethodtype; diff --git a/Objects/classobject.c b/Objects/classobject.c index 35ce0b17106..b8b72e9fd94 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -104,21 +104,23 @@ class_getattr(op, name) { register object *v; classobject *class; - if (strcmp(name, "__dict__") == 0) { - INCREF(op->cl_dict); - return op->cl_dict; - } - if (strcmp(name, "__bases__") == 0) { - INCREF(op->cl_bases); - return op->cl_bases; - } - if (strcmp(name, "__name__") == 0) { - if (op->cl_name == NULL) - v = None; - else - v = op->cl_name; - INCREF(v); - return v; + if (name[0] == '_' && name[1] == '_') { + if (strcmp(name, "__dict__") == 0) { + INCREF(op->cl_dict); + return op->cl_dict; + } + if (strcmp(name, "__bases__") == 0) { + INCREF(op->cl_bases); + return op->cl_bases; + } + if (strcmp(name, "__name__") == 0) { + if (op->cl_name == NULL) + v = None; + else + v = op->cl_name; + INCREF(v); + return v; + } } v = class_lookup(op, name, &class); if (v == NULL) { @@ -280,11 +282,25 @@ newinstanceobject(class, arg) INCREF(class); inst->in_class = (classobject *)class; inst->in_dict = newdictobject(); + inst->in_getattr = NULL; + inst->in_setattr = NULL; +#ifdef WITH_THREAD + inst->in_lock = NULL; + inst->in_ident = 0; +#endif if (inst->in_dict == NULL || addaccess((classobject *)class, inst) != 0) { DECREF(inst); return NULL; } + inst->in_setattr = instance_getattr(inst, "__setattr__"); + err_clear(); + inst->in_getattr = instance_getattr(inst, "__getattr__"); + err_clear(); +#ifdef WITH_THREAD + if (inst->in_getattr != NULL) + inst->in_lock = allocate_lock(); +#endif init = instance_getattr(inst, "__init__"); if (init == NULL) { err_clear(); @@ -345,6 +361,12 @@ instance_dealloc(inst) return; /* __del__ added a reference; don't delete now */ DECREF(inst->in_class); XDECREF(inst->in_dict); + XDECREF(inst->in_getattr); + XDECREF(inst->in_setattr); +#ifdef WITH_THREAD + if (inst->in_lock != NULL) + free_lock(inst->in_lock); +#endif free((ANY *)inst); } @@ -370,6 +392,32 @@ instance_getattr(inst, name) if (v == NULL) { v = class_lookup(inst->in_class, name, &class); if (v == NULL) { + object *func; + long ident; + if ((func = inst->in_getattr) != NULL && + inst->in_ident != (ident = get_thread_ident())) { + object *args; +#ifdef WITH_THREAD + type_lock lock = inst->in_lock; + if (lock != NULL) { + BGN_SAVE + acquire_lock(lock, 0); + END_SAVE + } +#endif + inst->in_ident = ident; + args = mkvalue("(s)", name); + if (args != NULL) { + v = call_object(func, args); + DECREF(args); + } + inst->in_ident = 0; +#ifdef WITH_THREAD + if (lock != NULL) + release_lock(lock); +#endif + return v; + } err_setstr(AttributeError, name); return NULL; } @@ -410,6 +458,18 @@ instance_setattr(inst, name, v) object *v; { object *ac; + if (inst->in_setattr != NULL) { + object *args = mkvalue("(sO)", name, v); + if (args != NULL) { + object *res = call_object(inst->in_setattr, args); + DECREF(args); + if (res != NULL) { + DECREF(res); + return 0; + } + } + return -1; + } if (name[0] == '_' && name[1] == '_') { int n = strlen(name); if (name[n-1] == '_' && name[n-2] == '_') { @@ -824,11 +884,33 @@ BINARY(instance_mul, "__mul__") BINARY(instance_div, "__div__") BINARY(instance_mod, "__mod__") BINARY(instance_divmod, "__divmod__") -BINARY(instance_pow, "__pow__") UNARY(instance_neg, "__neg__") UNARY(instance_pos, "__pos__") UNARY(instance_abs, "__abs__") +static object * +instance_pow(self, other, modulus) + instanceobject *self; + object *other, *modulus; +{ + object *func, *arg, *res; + + if ((func = instance_getattr(self, "__pow__")) == NULL) + return NULL; + if (modulus == None) + arg = mkvalue("O", other); + else + arg = mkvalue("(OO)", other, modulus); + if (arg == NULL) { + DECREF(func); + return NULL; + } + res = call_object(func, arg); + DECREF(func); + DECREF(arg); + return res; +} + static int instance_nonzero(self) instanceobject *self; @@ -922,7 +1004,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*/