]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
* Objects/classobject.c, Include/classobject.h: added __getattr__
authorGuido van Rossum <guido@python.org>
Fri, 12 Aug 1994 12:49:46 +0000 (12:49 +0000)
committerGuido van Rossum <guido@python.org>
Fri, 12 Aug 1994 12:49:46 +0000 (12:49 +0000)
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
Objects/classobject.c

index bd6cc1dffb5c41107f6d9e238facdcd402c8664c..6b1b85b44ee3069352601cd49ae32957df9d482f 100644 (file)
@@ -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;
index 35ce0b1710621099e5e266555a12e55b81feb82e..b8b72e9fd94ecdda15a9341e4c2ba6729b15e45a 100644 (file)
@@ -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*/