Add optional docstrings to member descriptors.  For backwards
compatibility, this required all places where an array of "struct
memberlist" structures was declared that is referenced from a type's
tp_members slot to change the type of the structure to PyMemberDef;
"struct memberlist" is now only used by old code that still calls
PyMember_Get/Set.  The code in PyObject_GenericGetAttr/SetAttr now
calls the new APIs PyMember_GetOne/SetOne, which take a PyMemberDef
argument.

As examples, I added actual docstrings to the attributes of a few
types: file, complex, instance method, super, and xxsubtype.spamlist.

Also converted the symtable to new style getattr.
diff --git a/Python/structmember.c b/Python/structmember.c
index ed34783..077be70 100644
--- a/Python/structmember.c
+++ b/Python/structmember.c
@@ -32,226 +32,237 @@
 PyMember_Get(char *addr, struct memberlist *mlist, char *name)
 {
 	struct memberlist *l;
-	
+
 	if (strcmp(name, "__members__") == 0)
 		return listmembers(mlist);
 	for (l = mlist; l->name != NULL; l++) {
 		if (strcmp(l->name, name) == 0) {
-			PyObject *v;
-			if ((l->flags & READ_RESTRICTED) &&
-			    PyEval_GetRestricted()) {
-				PyErr_SetString(PyExc_RuntimeError,
-						"restricted attribute");
-				return NULL;
-			}
-			addr += l->offset;
-			switch (l->type) {
-			case T_BYTE:
-				v = PyInt_FromLong((long)
-						 (((*(char*)addr & 0xff)
-						   ^ 0x80) - 0x80));
-				break;
-			case T_UBYTE:
-				v = PyInt_FromLong((long) *(char*)addr & 0xff);
-				break;
-			case T_SHORT:
-				v = PyInt_FromLong((long) *(short*)addr);
-				break;
-			case T_USHORT:
-				v = PyInt_FromLong((long)
-						 *(unsigned short*)addr);
-				break;
-			case T_INT:
-				v = PyInt_FromLong((long) *(int*)addr);
-				break;
-			case T_UINT:
-				v = PyInt_FromLong((long)
-						   *(unsigned int*)addr);
-				break;
-			case T_LONG:
-				v = PyInt_FromLong(*(long*)addr);
-				break;
-			case T_ULONG:
-				v = PyLong_FromDouble((double)
-						   *(unsigned long*)addr);
-				break;
-			case T_FLOAT:
-				v = PyFloat_FromDouble((double)*(float*)addr);
-				break;
-			case T_DOUBLE:
-				v = PyFloat_FromDouble(*(double*)addr);
-				break;
-			case T_STRING:
-				if (*(char**)addr == NULL) {
-					Py_INCREF(Py_None);
-					v = Py_None;
-				}
-				else
-					v = PyString_FromString(*(char**)addr);
-				break;
-			case T_STRING_INPLACE:
-				v = PyString_FromString((char*)addr);
-				break;
-#ifdef macintosh
-			case T_PSTRING:
-				if (*(char**)addr == NULL) {
-					Py_INCREF(Py_None);
-					v = Py_None;
-				}
-				else
-					v = PyString_FromStringAndSize(
-						(*(char**)addr)+1,
-						**(unsigned char**)addr);
-				break;
-			case T_PSTRING_INPLACE:
-				v = PyString_FromStringAndSize(
-					((char*)addr)+1,
-					*(unsigned char*)addr);
-				break;
-#endif /* macintosh */
-			case T_CHAR:
-				v = PyString_FromStringAndSize((char*)addr, 1);
-				break;
-			case T_OBJECT:
-				v = *(PyObject **)addr;
-				if (v == NULL)
-					v = Py_None;
-				Py_INCREF(v);
-				break;
-			default:
-				PyErr_SetString(PyExc_SystemError,
-						"bad memberlist type");
-				v = NULL;
-			}
-			return v;
+			PyMemberDef copy;
+			copy.name = l->name;
+			copy.type = l->type;
+			copy.offset = l->offset;
+			copy.flags = l->flags;
+			copy.doc = NULL;
+			return PyMember_GetOne(addr, &copy);
 		}
 	}
-	
 	PyErr_SetString(PyExc_AttributeError, name);
 	return NULL;
 }
 
+PyObject *
+PyMember_GetOne(char *addr, PyMemberDef *l)
+{
+	PyObject *v;
+	if ((l->flags & READ_RESTRICTED) &&
+	    PyEval_GetRestricted()) {
+		PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
+		return NULL;
+	}
+	addr += l->offset;
+	switch (l->type) {
+	case T_BYTE:
+		v = PyInt_FromLong(
+			(long) (((*(char*)addr & 0xff) ^ 0x80) - 0x80));
+		break;
+	case T_UBYTE:
+		v = PyInt_FromLong((long) *(char*)addr & 0xff);
+		break;
+	case T_SHORT:
+		v = PyInt_FromLong((long) *(short*)addr);
+		break;
+	case T_USHORT:
+		v = PyInt_FromLong((long) *(unsigned short*)addr);
+		break;
+	case T_INT:
+		v = PyInt_FromLong((long) *(int*)addr);
+		break;
+	case T_UINT:
+		v = PyInt_FromLong((long) *(unsigned int*)addr);
+		break;
+	case T_LONG:
+		v = PyInt_FromLong(*(long*)addr);
+		break;
+	case T_ULONG:
+		v = PyLong_FromDouble((double) *(unsigned long*)addr);
+		break;
+	case T_FLOAT:
+		v = PyFloat_FromDouble((double)*(float*)addr);
+		break;
+	case T_DOUBLE:
+		v = PyFloat_FromDouble(*(double*)addr);
+		break;
+	case T_STRING:
+		if (*(char**)addr == NULL) {
+			Py_INCREF(Py_None);
+			v = Py_None;
+		}
+		else
+			v = PyString_FromString(*(char**)addr);
+		break;
+	case T_STRING_INPLACE:
+		v = PyString_FromString((char*)addr);
+		break;
+#ifdef macintosh
+	case T_PSTRING:
+		if (*(char**)addr == NULL) {
+			Py_INCREF(Py_None);
+			v = Py_None;
+		}
+		else
+			v = PyString_FromStringAndSize(
+				(*(char**)addr)+1,
+				**(unsigned char**)addr);
+		break;
+	case T_PSTRING_INPLACE:
+		v = PyString_FromStringAndSize(
+			((char*)addr)+1,
+			*(unsigned char*)addr);
+		break;
+#endif /* macintosh */
+	case T_CHAR:
+		v = PyString_FromStringAndSize((char*)addr, 1);
+		break;
+	case T_OBJECT:
+		v = *(PyObject **)addr;
+		if (v == NULL)
+			v = Py_None;
+		Py_INCREF(v);
+		break;
+	default:
+		PyErr_SetString(PyExc_SystemError, "bad memberdescr type");
+		v = NULL;
+	}
+	return v;
+}
+
 int
 PyMember_Set(char *addr, struct memberlist *mlist, char *name, PyObject *v)
 {
 	struct memberlist *l;
-	PyObject *oldv;
-	
+
 	for (l = mlist; l->name != NULL; l++) {
 		if (strcmp(l->name, name) == 0) {
-			if ((l->flags & READONLY) || l->type == T_STRING
-#ifdef macintosh
-			    || l->type == T_PSTRING
-#endif
-				)
-			{
-				PyErr_SetString(PyExc_TypeError,
-						"readonly attribute");
-				return -1;
-			}
-			if ((l->flags & WRITE_RESTRICTED) &&
-			    PyEval_GetRestricted()) {
-				PyErr_SetString(PyExc_RuntimeError,
-						"restricted attribute");
-				return -1;
-			}
-			if (v == NULL && l->type != T_OBJECT) {
-				PyErr_SetString(PyExc_TypeError,
-				  "can't delete numeric/char attribute");
-				return -1;
-			}
-			addr += l->offset;
-			switch (l->type) {
-			case T_BYTE:
-			case T_UBYTE:
-				if (!PyInt_Check(v)) {
-					PyErr_BadArgument();
-					return -1;
-				}
-				*(char*)addr = (char) PyInt_AsLong(v);
-				break;
-			case T_SHORT:
-			case T_USHORT:
-				if (!PyInt_Check(v)) {
-					PyErr_BadArgument();
-					return -1;
-				}
-				*(short*)addr = (short) PyInt_AsLong(v);
-				break;
-			case T_UINT:
-			case T_INT:
-				if (!PyInt_Check(v)) {
-					PyErr_BadArgument();
-					return -1;
-				}
-				*(int*)addr = (int) PyInt_AsLong(v);
-				break;
-			case T_LONG:
-				if (!PyInt_Check(v)) {
-					PyErr_BadArgument();
-					return -1;
-				}
-				*(long*)addr = PyInt_AsLong(v);
-				break;
-			case T_ULONG:
-				if (PyInt_Check(v))
-					*(long*)addr = PyInt_AsLong(v);
-				else if (PyLong_Check(v))
-					*(long*)addr = PyLong_AsLong(v);
-				else {
-					PyErr_BadArgument();
-					return -1;
-				}
-				break;
-			case T_FLOAT:
-				if (PyInt_Check(v))
-					*(float*)addr =
-						(float) PyInt_AsLong(v);
-				else if (PyFloat_Check(v))
-					*(float*)addr =
-						(float) PyFloat_AsDouble(v);
-				else {
-					PyErr_BadArgument();
-					return -1;
-				}
-				break;
-			case T_DOUBLE:
-				if (PyInt_Check(v))
-					*(double*)addr =
-						(double) PyInt_AsLong(v);
-				else if (PyFloat_Check(v))
-					*(double*)addr = PyFloat_AsDouble(v);
-				else {
-					PyErr_BadArgument();
-					return -1;
-				}
-				break;
-			case T_OBJECT:
-				Py_XINCREF(v);
-				oldv = *(PyObject **)addr;
-				*(PyObject **)addr = v;
-				Py_XDECREF(oldv);
-				break;
-			case T_CHAR:
-				if (PyString_Check(v) &&
-				    PyString_Size(v) == 1) {
-					*(char*)addr =
-						PyString_AsString(v)[0];
-				}
-				else {
-					PyErr_BadArgument();
-					return -1;
-				}
-				break;
-			default:
-				PyErr_SetString(PyExc_SystemError,
-						"bad memberlist type");
-				return -1;
-			}
-			return 0;
+			PyMemberDef copy;
+			copy.name = l->name;
+			copy.type = l->type;
+			copy.offset = l->offset;
+			copy.flags = l->flags;
+			copy.doc = NULL;
+			return PyMember_SetOne(addr, &copy, v);
 		}
 	}
-	
+
 	PyErr_SetString(PyExc_AttributeError, name);
 	return -1;
 }
+
+int
+PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
+{
+	PyObject *oldv;
+
+	if ((l->flags & READONLY) || l->type == T_STRING
+#ifdef macintosh
+	    || l->type == T_PSTRING
+#endif
+		)
+	{
+		PyErr_SetString(PyExc_TypeError, "readonly attribute");
+		return -1;
+	}
+	if ((l->flags & WRITE_RESTRICTED) && PyEval_GetRestricted()) {
+		PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
+		return -1;
+	}
+	if (v == NULL && l->type != T_OBJECT) {
+		PyErr_SetString(PyExc_TypeError,
+				"can't delete numeric/char attribute");
+		return -1;
+	}
+	addr += l->offset;
+	switch (l->type) {
+	case T_BYTE:
+	case T_UBYTE:
+		if (!PyInt_Check(v)) {
+			PyErr_BadArgument();
+			return -1;
+		}
+		*(char*)addr = (char) PyInt_AsLong(v);
+		break;
+	case T_SHORT:
+	case T_USHORT:
+		if (!PyInt_Check(v)) {
+			PyErr_BadArgument();
+			return -1;
+		}
+		*(short*)addr = (short) PyInt_AsLong(v);
+		break;
+	case T_UINT:
+	case T_INT:
+		if (!PyInt_Check(v)) {
+			PyErr_BadArgument();
+			return -1;
+		}
+		*(int*)addr = (int) PyInt_AsLong(v);
+		break;
+	case T_LONG:
+		if (!PyInt_Check(v)) {
+			PyErr_BadArgument();
+			return -1;
+		}
+		*(long*)addr = PyInt_AsLong(v);
+		break;
+	case T_ULONG:
+		if (PyInt_Check(v))
+			*(long*)addr = PyInt_AsLong(v);
+		else if (PyLong_Check(v))
+			*(long*)addr = PyLong_AsLong(v);
+		else {
+			PyErr_BadArgument();
+			return -1;
+		}
+		break;
+	case T_FLOAT:
+		if (PyInt_Check(v))
+			*(float*)addr =
+				(float) PyInt_AsLong(v);
+		else if (PyFloat_Check(v))
+			*(float*)addr =
+				(float) PyFloat_AsDouble(v);
+		else {
+			PyErr_BadArgument();
+			return -1;
+		}
+		break;
+	case T_DOUBLE:
+		if (PyInt_Check(v))
+			*(double*)addr = (double) PyInt_AsLong(v);
+		else if (PyFloat_Check(v))
+			*(double*)addr = PyFloat_AsDouble(v);
+		else {
+			PyErr_BadArgument();
+			return -1;
+		}
+		break;
+	case T_OBJECT:
+		Py_XINCREF(v);
+		oldv = *(PyObject **)addr;
+		*(PyObject **)addr = v;
+		Py_XDECREF(oldv);
+		break;
+	case T_CHAR:
+		if (PyString_Check(v) && PyString_Size(v) == 1) {
+			*(char*)addr = PyString_AsString(v)[0];
+		}
+		else {
+			PyErr_BadArgument();
+			return -1;
+		}
+		break;
+	default:
+		PyErr_SetString(PyExc_SystemError, "bad memberdescr type");
+		return -1;
+	}
+	return 0;
+}