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/Include/descrobject.h b/Include/descrobject.h
index a868310..3d58181 100644
--- a/Include/descrobject.h
+++ b/Include/descrobject.h
@@ -21,7 +21,7 @@
 
 extern DL_IMPORT(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *);
 extern DL_IMPORT(PyObject *) PyDescr_NewMember(PyTypeObject *,
-					       struct memberlist *);
+					       struct PyMemberDef *);
 extern DL_IMPORT(PyObject *) PyDescr_NewGetSet(PyTypeObject *,
 					       struct getsetlist *);
 extern DL_IMPORT(PyObject *) PyDescr_NewWrapper(PyTypeObject *,
diff --git a/Include/object.h b/Include/object.h
index 160331e..1d0ae5f 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -274,7 +274,7 @@
 
 	/* Attribute descriptor and subclassing stuff */
 	struct PyMethodDef *tp_methods;
-	struct memberlist *tp_members;
+	struct PyMemberDef *tp_members;
 	struct getsetlist *tp_getset;
 	struct _typeobject *tp_base;
 	PyObject *tp_dict;
diff --git a/Include/structmember.h b/Include/structmember.h
index cd35fdb..2c9f41d 100644
--- a/Include/structmember.h
+++ b/Include/structmember.h
@@ -28,12 +28,22 @@
    pointer is NULL. */
 
 struct memberlist {
+	/* Obsolete version, for binary backwards compatibility */
 	char *name;
 	int type;
 	int offset;
 	int flags;
 };
 
+typedef struct PyMemberDef {
+	/* Current version, use this */
+	char *name;
+	int type;
+	int offset;
+	int flags;
+	char *doc;
+} PyMemberDef;
+
 /* Types */
 #define T_SHORT		0
 #define T_INT		1
@@ -66,9 +76,15 @@
 #define RESTRICTED	(READ_RESTRICTED | WRITE_RESTRICTED)
 
 
+/* Obsolete API, for binary backwards compatibility */
 DL_IMPORT(PyObject *) PyMember_Get(char *, struct memberlist *, char *);
 DL_IMPORT(int) PyMember_Set(char *, struct memberlist *, char *, PyObject *);
 
+/* Current API, use this */
+DL_IMPORT(PyObject *) PyMember_GetOne(char *, struct PyMemberDef *);
+DL_IMPORT(int) PyMember_SetOne(char *, struct PyMemberDef *, PyObject *);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/Modules/xxsubtype.c b/Modules/xxsubtype.c
index c20a1c7..cdf6d07 100644
--- a/Modules/xxsubtype.c
+++ b/Modules/xxsubtype.c
@@ -148,8 +148,9 @@
 	return 0;
 }
 
-static struct memberlist spamdict_members[] = {
-	{"state", T_INT, offsetof(spamdictobject, state), READONLY},
+static PyMemberDef spamdict_members[] = {
+	{"state", T_INT, offsetof(spamdictobject, state), READONLY,
+	 "an int variable for demonstration purposes"},
 	{0}
 };
 
diff --git a/Objects/classobject.c b/Objects/classobject.c
index 3845dfc..f8ee6fd 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -2006,10 +2006,13 @@
 
 #define OFF(x) offsetof(PyMethodObject, x)
 
-static struct memberlist instancemethod_memberlist[] = {
-	{"im_class",	T_OBJECT,	OFF(im_class),	READONLY|RESTRICTED},
-	{"im_func",	T_OBJECT,	OFF(im_func),	READONLY|RESTRICTED},
-	{"im_self",	T_OBJECT,	OFF(im_self),	READONLY|RESTRICTED},
+static PyMemberDef instancemethod_memberlist[] = {
+	{"im_class",	T_OBJECT,	OFF(im_class),	READONLY|RESTRICTED,
+	 "the class associated with a method"},
+	{"im_func",	T_OBJECT,	OFF(im_func),	READONLY|RESTRICTED,
+	 "the function (or other callable) implementing a method"},
+	{"im_self",	T_OBJECT,	OFF(im_self),	READONLY|RESTRICTED,
+	 "the instance to which a method is bound; None for unbound methods"},
 	{NULL}	/* Sentinel */
 };
 
diff --git a/Objects/complexobject.c b/Objects/complexobject.c
index a2ccadb..191dcba 100644
--- a/Objects/complexobject.c
+++ b/Objects/complexobject.c
@@ -625,9 +625,11 @@
 	{NULL,		NULL}		/* sentinel */
 };
 
-static struct memberlist complex_members[] = {
-	{"real", T_DOUBLE, offsetof(PyComplexObject, cval.real), 0},
-	{"imag", T_DOUBLE, offsetof(PyComplexObject, cval.imag), 0},
+static PyMemberDef complex_members[] = {
+	{"real", T_DOUBLE, offsetof(PyComplexObject, cval.real), 0,
+	 "the real part of a complex number"},
+	{"imag", T_DOUBLE, offsetof(PyComplexObject, cval.imag), 0,
+	 "the imaginary part of a complex number"},
 	{0},
 };
 
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index e5b08c3..dfbb3b6 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -21,7 +21,7 @@
 
 typedef struct {
 	COMMON;
-	struct memberlist *d_member;
+	PyMemberDef *d_member;
 } PyMemberDescrObject;
 
 typedef struct {
@@ -126,8 +126,7 @@
 
 	if (descr_check((PyDescrObject *)descr, obj, type, &res))
 		return res;
-	return PyMember_Get((char *)obj, descr->d_member,
-			    descr->d_member->name);
+	return PyMember_GetOne((char *)obj, descr->d_member);
 }
 
 static PyObject *
@@ -181,8 +180,7 @@
 
 	if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
 		return res;
-	return PyMember_Set((char *)obj, descr->d_member,
-			    descr->d_member->name, value);
+	return PyMember_SetOne((char *)obj, descr->d_member, value);
 }
 
 static int
@@ -289,7 +287,7 @@
 }
 
 static PyObject *
-member_get_doc(PyMethodDescrObject *descr, void *closure)
+method_get_doc(PyMethodDescrObject *descr, void *closure)
 {
 	if (descr->d_method->ml_doc == NULL) {
 		Py_INCREF(Py_None);
@@ -298,12 +296,27 @@
 	return PyString_FromString(descr->d_method->ml_doc);
 }
 
-static struct memberlist descr_members[] = {
+static PyMemberDef descr_members[] = {
 	{"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},
 	{"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},
 	{0}
 };
 
+static struct getsetlist method_getset[] = {
+	{"__doc__", (getter)method_get_doc},
+	{0}
+};
+
+static PyObject *
+member_get_doc(PyMemberDescrObject *descr, void *closure)
+{
+	if (descr->d_member->doc == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+	return PyString_FromString(descr->d_member->doc);
+}
+
 static struct getsetlist member_getset[] = {
 	{"__doc__", (getter)member_get_doc},
 	{0}
@@ -355,7 +368,7 @@
 	0,					/* tp_iternext */
 	0,					/* tp_methods */
 	descr_members,				/* tp_members */
-	member_getset,				/* tp_getset */
+	method_getset,				/* tp_getset */
 	0,					/* tp_base */
 	0,					/* tp_dict */
 	(descrgetfunc)method_get,		/* tp_descr_get */
@@ -393,7 +406,7 @@
 	0,					/* tp_iternext */
 	0,					/* tp_methods */
 	descr_members,				/* tp_members */
-	0,					/* tp_getset */
+	member_getset,				/* tp_getset */
 	0,					/* tp_base */
 	0,					/* tp_dict */
 	(descrgetfunc)member_get,		/* tp_descr_get */
@@ -507,7 +520,7 @@
 }
 
 PyObject *
-PyDescr_NewMember(PyTypeObject *type, struct memberlist *member)
+PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member)
 {
 	PyMemberDescrObject *descr;
 
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 6ceb83c..5c879ff 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -1383,10 +1383,13 @@
 
 #define OFF(x) offsetof(PyFileObject, x)
 
-static struct memberlist file_memberlist[] = {
-	{"softspace",	T_INT,		OFF(f_softspace)},
-	{"mode",	T_OBJECT,	OFF(f_mode),	RO},
-	{"name",	T_OBJECT,	OFF(f_name),	RO},
+static PyMemberDef file_memberlist[] = {
+	{"softspace",	T_INT,		OFF(f_softspace), 0,
+	 "flag indicating that a space needs to be printed; used by print"},
+	{"mode",	T_OBJECT,	OFF(f_mode),	RO,
+	 "file mode ('r', 'w', 'a', possibly with 'b' or '+' added)"},
+	{"name",	T_OBJECT,	OFF(f_name),	RO,
+	 "file name"},
 	/* getattr(f, "closed") is implemented without this table */
 	{NULL}	/* Sentinel */
 };
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index fd9a4e2..cb7e80a 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -10,7 +10,7 @@
 
 #define OFF(x) offsetof(PyFrameObject, x)
 
-static struct memberlist frame_memberlist[] = {
+static PyMemberDef frame_memberlist[] = {
 	{"f_back",	T_OBJECT,	OFF(f_back),	RO},
 	{"f_code",	T_OBJECT,	OFF(f_code),	RO},
 	{"f_builtins",	T_OBJECT,	OFF(f_builtins),RO},
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index 91a3127..e1cf080 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -129,7 +129,7 @@
 
 #define RR ()
 
-static struct memberlist func_memberlist[] = {
+static PyMemberDef func_memberlist[] = {
         {"func_closure",  T_OBJECT,     OFF(func_closure),
 	 RESTRICTED|READONLY},
         {"func_doc",      T_OBJECT,     OFF(func_doc), WRITE_RESTRICTED},
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
index 6d91ecc..586785c 100644
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -9,7 +9,7 @@
 	PyObject *md_dict;
 } PyModuleObject;
 
-struct memberlist module_members[] = {
+PyMemberDef module_members[] = {
 	{"__dict__", T_OBJECT, offsetof(PyModuleObject, md_dict), READONLY},
 	{0}
 };
diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c
index 8f52f9e..81517a8 100644
--- a/Objects/sliceobject.c
+++ b/Objects/sliceobject.c
@@ -129,7 +129,7 @@
 	return s;
 }
 
-static struct memberlist slice_members[] = {
+static PyMemberDef slice_members[] = {
 	{"start", T_OBJECT, offsetof(PySliceObject, start), READONLY},
 	{"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY},
 	{"step", T_OBJECT, offsetof(PySliceObject, step), READONLY},
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 26ddabe..b53555d 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -4,7 +4,7 @@
 #include "Python.h"
 #include "structmember.h"
 
-static struct memberlist type_members[] = {
+static PyMemberDef type_members[] = {
 	{"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY},
 	{"__itemsize__", T_INT, offsetof(PyTypeObject, tp_itemsize), READONLY},
 	{"__flags__", T_LONG, offsetof(PyTypeObject, tp_flags), READONLY},
@@ -263,7 +263,7 @@
 	PyMappingMethods as_mapping;
 	PyBufferProcs as_buffer;
 	PyObject *name, *slots;
-	struct memberlist members[1];
+	PyMemberDef members[1];
 } etype;
 
 /* type test with subclassing support */
@@ -672,7 +672,7 @@
 	PyObject *slots, *tmp;
 	PyTypeObject *type, *base, *tmptype, *winner;
 	etype *et;
-	struct memberlist *mp;
+	PyMemberDef *mp;
 	int i, nbases, nslots, slotoffset, dynamic, add_dict, add_weak;
 
 	/* Special case: type(x) should return x->ob_type */
@@ -1087,7 +1087,7 @@
 	0,					/* ob_size */
 	"type",					/* tp_name */
 	sizeof(etype),				/* tp_basicsize */
-	sizeof(struct memberlist),		/* tp_itemsize */
+	sizeof(PyMemberDef),			/* tp_itemsize */
 	(destructor)type_dealloc,		/* tp_dealloc */
 	0,					/* tp_print */
 	0,			 		/* tp_getattr */
@@ -1192,7 +1192,7 @@
 	PyObject_Del(self);
 }
 
-static struct memberlist object_members[] = {
+static PyMemberDef object_members[] = {
 	{"__class__", T_OBJECT, offsetof(PyObject, ob_type), READONLY},
 	{0}
 };
@@ -1263,7 +1263,7 @@
 }
 
 static int
-add_members(PyTypeObject *type, struct memberlist *memb)
+add_members(PyTypeObject *type, PyMemberDef *memb)
 {
 	PyObject *dict = type->tp_defined;
 
@@ -3221,9 +3221,11 @@
 	PyObject *obj;
 } superobject;
 
-static struct memberlist super_members[] = {
-	{"__type__", T_OBJECT, offsetof(superobject, type), READONLY},
-	{"__obj__",  T_OBJECT, offsetof(superobject, obj), READONLY},
+static PyMemberDef super_members[] = {
+	{"__thisclass__", T_OBJECT, offsetof(superobject, type), READONLY,
+	 "the class invoking super()"},
+	{"__self__",  T_OBJECT, offsetof(superobject, obj), READONLY,
+	 "the instance invoking super(); may be None"},
 	{0}
 };
 
diff --git a/Python/ceval.c b/Python/ceval.c
index bbbdcf3..3ca1e3e 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -192,7 +192,7 @@
 	{NULL,          NULL}   /* Sentinel */
 };
 
-static struct memberlist gen_memberlist[] = {
+static PyMemberDef gen_memberlist[] = {
 	{"gi_frame",	T_OBJECT, offsetof(genobject, gi_frame),	RO},
 	{"gi_running",	T_INT,    offsetof(genobject, gi_running),	RO},
 	{NULL}	/* Sentinel */
diff --git a/Python/compile.c b/Python/compile.c
index 0f10dbe..dae2a3e 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -73,7 +73,7 @@
 
 #define OFF(x) offsetof(PyCodeObject, x)
 
-static struct memberlist code_memberlist[] = {
+static PyMemberDef code_memberlist[] = {
 	{"co_argcount",	T_INT,		OFF(co_argcount),	READONLY},
 	{"co_nlocals",	T_INT,		OFF(co_nlocals),	READONLY},
 	{"co_stacksize",T_INT,		OFF(co_stacksize),	READONLY},
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;
+}
diff --git a/Python/symtable.c b/Python/symtable.c
index e115167..4f63ae7 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -106,7 +106,7 @@
 
 #define OFF(x) offsetof(PySymtableEntryObject, x)
 
-static struct memberlist ste_memberlist[] = {
+static PyMemberDef ste_memberlist[] = {
 	{"id",       T_OBJECT, OFF(ste_id), READONLY},
 	{"name",     T_OBJECT, OFF(ste_name), READONLY},
 	{"symbols",  T_OBJECT, OFF(ste_symbols), READONLY},
@@ -119,12 +119,6 @@
 	{NULL}
 };
 
-static PyObject *
-ste_getattr(PySymtableEntryObject *ste, char *name)
-{
-	return PyMember_Get((char *)ste, ste_memberlist, name);
-}
-
 PyTypeObject PySymtableEntry_Type = {
 	PyObject_HEAD_INIT(&PyType_Type)
 	0,
@@ -133,7 +127,7 @@
 	0,
 	(destructor)ste_dealloc,                /* tp_dealloc */
 	0,                                      /* tp_print */
-	(getattrfunc)ste_getattr,               /* tp_getattr */
+	0,			               /* tp_getattr */
 	0,					/* tp_setattr */
 	0,			                /* tp_compare */
 	(reprfunc)ste_repr,			/* tp_repr */
@@ -143,9 +137,26 @@
 	0,					/* tp_hash */
 	0,					/* tp_call */
 	0,					/* tp_str */
-	0,					/* tp_getattro */
+	PyObject_GenericGetAttr,		/* tp_getattro */
 	0,					/* tp_setattro */
 	0,					/* tp_as_buffer */
 	Py_TPFLAGS_DEFAULT,	                /* tp_flags */
  	0,					/* tp_doc */
+	0,					/* tp_traverse */
+	0,					/* tp_clear */
+	0,					/* tp_richcompare */
+	0,					/* tp_weaklistoffset */
+	0,					/* tp_iter */
+	0,					/* tp_iternext */
+	0,					/* tp_methods */
+	ste_memberlist,				/* tp_members */
+	0,					/* tp_getset */
+	0,					/* tp_base */
+	0,					/* tp_dict */
+	0,					/* tp_descr_get */
+	0,					/* tp_descr_set */
+	0,					/* tp_dictoffset */
+	0,					/* tp_init */
+	0,					/* tp_alloc */
+	0,					/* tp_new */
 };