type_new(): look for __dynamic__ at the module level (after looking in
the class dict).  Anything but a nonnegative int in either place is
*ignored* (before, a non-Boolean was an error).  The default is still
static -- in a comparative test, Jeremy's Tools/compiler package ran
twice as slow (compiling itself) using dynamic as the default.  (The
static version, which requires a few tweaks to avoid modifying class
variables, runs at about the same speed as the classic version.)

slot_tp_descr_get(): this also needed fallback behavior.

slot_tp_getattro(): remove a debug fprintf() call.
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 474ff3e..29cb203 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -566,23 +566,44 @@
 		return NULL;
 	}
 
-	/* Should this be a dynamic class (i.e. modifiable __dict__)? */
+	/* Should this be a dynamic class (i.e. modifiable __dict__)?
+	   Look in two places for a variable named __dynamic__:
+	   1) in the class dict
+	   2) in the module dict (globals)
+	   The first variable that is an int >= 0 is used.
+	   Otherwise, a default is calculated from the base classes:
+	   if any base class is dynamic, this class is dynamic; otherwise
+	   it is static. */
+	dynamic = -1; /* Not yet determined */
+	/* Look in the class */
 	tmp = PyDict_GetItemString(dict, "__dynamic__");
 	if (tmp != NULL) {
-		/* The class author has a preference */
-		dynamic = PyObject_IsTrue(tmp);
-		Py_DECREF(tmp);
+		dynamic = PyInt_AsLong(tmp);
 		if (dynamic < 0)
-			return NULL;
+			PyErr_Clear();
 	}
-	else {
-		/* Make a new class dynamic if any of its bases is dynamic.
-		   This is not always the same as inheriting the __dynamic__
-		   class attribute! */
+	if (dynamic < 0) {
+		/* Look in the module globals */
+		tmp = PyEval_GetGlobals();
+		if (tmp != NULL) {
+			tmp = PyDict_GetItemString(tmp, "__dynamic__");
+			if (tmp != NULL) {
+				dynamic = PyInt_AsLong(tmp);
+				if (dynamic < 0)
+					PyErr_Clear();
+			}
+		}
+	}
+	if (dynamic < 0) {
+		/* Make a new class dynamic if any of its bases is
+		   dynamic.  This is not always the same as inheriting
+		   the __dynamic__ class attribute! */
 		dynamic = 0;
 		for (i = 0; i < nbases; i++) {
-			tmptype = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
-			if (tmptype->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
+			tmptype = (PyTypeObject *)
+				PyTuple_GET_ITEM(bases, i);
+			if (tmptype->tp_flags &
+			    Py_TPFLAGS_DYNAMICTYPE) {
 				dynamic = 1;
 				break;
 			}
@@ -2565,8 +2586,6 @@
 		/* Avoid further slowdowns */
 		if (tp->tp_getattro == slot_tp_getattro)
 			tp->tp_getattro = PyObject_GenericGetAttr;
-		else
-			fprintf(stderr, "huh?\n");
 		return PyObject_GenericGetAttr(self, name);
 	}
 	return PyObject_CallFunction(getattr, "OO", self, name);
@@ -2672,7 +2691,28 @@
 	return PyObject_CallMethod(self, "next", "");
 }
 
-SLOT2(slot_tp_descr_get, "__get__", PyObject *, PyObject *, "OO")
+static PyObject *
+slot_tp_descr_get(PyObject *self, PyObject *obj, PyObject *type)
+{
+	PyTypeObject *tp = self->ob_type;
+	PyObject *get;
+	static PyObject *get_str = NULL;
+
+	if (get_str == NULL) {
+		get_str = PyString_InternFromString("__get__");
+		if (get_str == NULL)
+			return NULL;
+	}
+	get = _PyType_Lookup(tp, get_str);
+	if (get == NULL) {
+		/* Avoid further slowdowns */
+		if (tp->tp_descr_get == slot_tp_descr_get)
+			tp->tp_descr_get = NULL;
+		Py_INCREF(self);
+		return self;
+	}
+	return PyObject_CallFunction(get, "OOO", self, obj, type);
+}
 
 static int
 slot_tp_descr_set(PyObject *self, PyObject *target, PyObject *value)