* 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
diff --git a/Include/classobject.h b/Include/classobject.h
index bd6cc1d..6b1b85b 100644
--- a/Include/classobject.h
+++ b/Include/classobject.h
@@ -30,6 +30,12 @@
 
 /* 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 @@
 	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 35ce0b1..b8b72e9 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -104,21 +104,23 @@
 {
 	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 @@
 	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 @@
 		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 @@
 	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 @@
 	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_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 @@
 	(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*/