]> granicus.if.org Git - python/commitdiff
Halfway checkin. This is still messy, but it's beginning to address
authorGuido van Rossum <guido@python.org>
Tue, 9 Oct 2001 19:39:46 +0000 (19:39 +0000)
committerGuido van Rossum <guido@python.org>
Tue, 9 Oct 2001 19:39:46 +0000 (19:39 +0000)
the problem that slots weren't inherited properly.  override_slots()
no longer exists; in its place comes fixup_slot_dispatchers() which
does more and different work and is table-based.  (Eventually I want
this table also to replace all the little tab_foo tables.)

Also add a wrapper for __delslice__; this required a change in
test_descrtut.py.

Lib/test/test_descrtut.py
Objects/typeobject.c

index 80e7f05e0e564fd66d26751d83714950e3beb574..2e019aa92d1d606c096495a461373f8080b59ef5 100644 (file)
@@ -190,6 +190,7 @@ Instead, you can get the same information from the list type:
      '__contains__',
      '__delattr__',
      '__delitem__',
+     '__delslice__',
      '__eq__',
      '__ge__',
      '__getattribute__',
index 65267d3338da8318c56be69fcc3bf2c962b513d8..63843c53dc7c545210fb0adc760fa82b2ce51313 100644 (file)
@@ -299,7 +299,6 @@ subtype_dealloc(PyObject *self)
        }
 }
 
-staticforward void override_slots(PyTypeObject *type, PyObject *dict);
 staticforward PyTypeObject *solid_base(PyTypeObject *type);
 
 typedef struct {
@@ -677,6 +676,8 @@ solid_base(PyTypeObject *type)
 
 staticforward void object_dealloc(PyObject *);
 staticforward int object_init(PyObject *, PyObject *, PyObject *);
+staticforward int update_slot(PyTypeObject *, PyObject *, PyObject *);
+staticforward void fixup_slot_dispatchers(PyTypeObject *);
 
 static PyObject *
 subtype_dict(PyObject *obj, void *context)
@@ -1011,9 +1012,8 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
                return NULL;
        }
 
-       /* Override slots that deserve it */
-       if (!PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE))
-               override_slots(type, type->tp_defined);
+       /* Put the proper slots in place */
+       fixup_slot_dispatchers(type);
 
        return (PyObject *)type;
 }
@@ -1104,9 +1104,12 @@ type_getattro(PyTypeObject *type, PyObject *name)
 static int
 type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
 {
-       if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE)
-               return PyObject_GenericSetAttr((PyObject *)type, name, value);
-       PyErr_SetString(PyExc_TypeError, "can't set type attributes");
+       if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
+               if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
+                       return -1;
+               return update_slot(type, name, value);
+       }
+       PyErr_SetString(PyExc_TypeError, "can't set static type attributes");
        return -1;
 }
 
@@ -1857,11 +1860,7 @@ PyType_Ready(PyTypeObject *type)
                inherit_special(type, type->tp_base);
 
        /* Initialize tp_dict properly */
-       if (PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE)) {
-               /* For a dynamic type, all slots are overridden */
-               override_slots(type, NULL);
-       }
-       else {
+       if (!PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE)) {
                /* For a static type, tp_dict is the consolidation
                   of the tp_defined of its bases in MRO. */
                Py_DECREF(type->tp_dict);
@@ -1881,6 +1880,18 @@ PyType_Ready(PyTypeObject *type)
                        inherit_slots(type, base);
                }
        }
+       else {
+               /* For a dynamic type, we simply inherit the base slots. */
+               bases = type->tp_mro;
+               assert(bases != NULL);
+               assert(PyTuple_Check(bases));
+               n = PyTuple_GET_SIZE(bases);
+               for (i = 1; i < n; i++) {
+                       base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
+                       assert(PyType_Check(base));
+                       inherit_slots(type, base);
+               }
+       }
 
        /* Some more special stuff */
        base = type->tp_base;
@@ -1987,7 +1998,7 @@ wrap_binaryfunc_l(PyObject *self, PyObject *args, void *wrapped)
        if (!PyArg_ParseTuple(args, "O", &other))
                return NULL;
        if (!(self->ob_type->tp_flags & Py_TPFLAGS_CHECKTYPES) &&
-           self->ob_type != other->ob_type) {
+           !PyType_IsSubtype(other->ob_type, self->ob_type)) {
                Py_INCREF(Py_NotImplemented);
                return Py_NotImplemented;
        }
@@ -2003,7 +2014,7 @@ wrap_binaryfunc_r(PyObject *self, PyObject *args, void *wrapped)
        if (!PyArg_ParseTuple(args, "O", &other))
                return NULL;
        if (!(self->ob_type->tp_flags & Py_TPFLAGS_CHECKTYPES) &&
-           self->ob_type != other->ob_type) {
+           !PyType_IsSubtype(other->ob_type, self->ob_type)) {
                Py_INCREF(Py_NotImplemented);
                return Py_NotImplemented;
        }
@@ -2332,9 +2343,26 @@ wrap_intintobjargproc(PyObject *self, PyObject *args, void *wrapped)
        return Py_None;
 }
 
+static PyObject *
+wrap_delslice(PyObject *self, PyObject *args, void *wrapped)
+{
+       intintobjargproc func = (intintobjargproc)wrapped;
+       int i, j, res;
+
+       if (!PyArg_ParseTuple(args, "ii", &i, &j))
+               return NULL;
+       res = (*func)(self, i, j, NULL);
+       if (res == -1 && PyErr_Occurred())
+               return NULL;
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
 static struct wrapperbase tab_setslice[] = {
        {"__setslice__", (wrapperfunc)wrap_intintobjargproc,
         "x.__setslice__(i, j, y) <==> x[i:j]=y"},
+       {"__delslice__", (wrapperfunc)wrap_delslice,
+        "x.__delslice__(i, j) <==> del x[i:j]"},
        {0}
 };
 
@@ -2609,7 +2637,7 @@ static struct wrapperbase tab_descr_get[] = {
 };
 
 static PyObject *
-wrap_descrsetfunc(PyObject *self, PyObject *args, void *wrapped)
+wrap_descr_set(PyObject *self, PyObject *args, void *wrapped)
 {
        descrsetfunc func = (descrsetfunc)wrapped;
        PyObject *obj, *value;
@@ -2625,7 +2653,7 @@ wrap_descrsetfunc(PyObject *self, PyObject *args, void *wrapped)
 }
 
 static struct wrapperbase tab_descr_set[] = {
-       {"__set__", (wrapperfunc)wrap_descrsetfunc,
+       {"__set__", (wrapperfunc)wrap_descr_set,
         "descr.__set__(obj, value)"},
        {0}
 };
@@ -3638,133 +3666,266 @@ slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
        return x;
 }
 
-/* This is called at the very end of type_new() (even after
-   PyType_Ready()) to complete the initialization of dynamic types.
-   The dict argument is the dictionary argument passed to type_new(),
-   which is the local namespace of the class statement, in other
-   words, it contains the methods.  For each special method (like
-   __repr__) defined in the dictionary, the corresponding function
-   slot in the type object (like tp_repr) is set to a special function
-   whose name is 'slot_' followed by the slot name and whose signature
-   is whatever is required for that slot.  These slot functions look
-   up the corresponding method in the type's dictionary and call it.
-   The slot functions have to take care of the various peculiarities
-   of the mapping between slots and special methods, such as mapping
-   one slot to multiple methods (tp_richcompare <--> __le__, __lt__
-   etc.)  or mapping multiple slots to a single method (sq_item,
-   mp_subscript <--> __getitem__). */
 
-static void
-override_slots(PyTypeObject *type, PyObject *dict)
-{
-       PySequenceMethods *sq = type->tp_as_sequence;
-       PyMappingMethods *mp = type->tp_as_mapping;
-       PyNumberMethods *nb = type->tp_as_number;
-
-#define SQSLOT(OPNAME, SLOTNAME, FUNCNAME) \
-       if (dict == NULL || PyDict_GetItemString(dict, OPNAME)) { \
-               sq->SLOTNAME = FUNCNAME; \
-       }
-
-#define MPSLOT(OPNAME, SLOTNAME, FUNCNAME) \
-       if (dict == NULL || PyDict_GetItemString(dict, OPNAME)) { \
-               mp->SLOTNAME = FUNCNAME; \
-       }
-
-#define NBSLOT(OPNAME, SLOTNAME, FUNCNAME) \
-       if (dict == NULL || PyDict_GetItemString(dict, OPNAME)) { \
-               nb->SLOTNAME = FUNCNAME; \
-       }
-
-#define TPSLOT(OPNAME, SLOTNAME, FUNCNAME) \
-       if (dict == NULL || PyDict_GetItemString(dict, OPNAME)) { \
-               type->SLOTNAME = FUNCNAME; \
-       }
-
-       SQSLOT("__len__", sq_length, slot_sq_length);
-       SQSLOT("__add__", sq_concat, slot_sq_concat);
-       SQSLOT("__mul__", sq_repeat, slot_sq_repeat);
-       SQSLOT("__getitem__", sq_item, slot_sq_item);
-       SQSLOT("__getslice__", sq_slice, slot_sq_slice);
-       SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item);
-       SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item);
-       SQSLOT("__setslice__", sq_ass_slice, slot_sq_ass_slice);
-       SQSLOT("__delslice__", sq_ass_slice, slot_sq_ass_slice);
-       SQSLOT("__contains__", sq_contains, slot_sq_contains);
-       SQSLOT("__iadd__", sq_inplace_concat, slot_sq_inplace_concat);
-       SQSLOT("__imul__", sq_inplace_repeat, slot_sq_inplace_repeat);
-
-       MPSLOT("__len__", mp_length, slot_mp_length);
-       MPSLOT("__getitem__", mp_subscript, slot_mp_subscript);
-       MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript);
-       MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript);
-
-       NBSLOT("__add__", nb_add, slot_nb_add);
-       NBSLOT("__sub__", nb_subtract, slot_nb_subtract);
-       NBSLOT("__mul__", nb_multiply, slot_nb_multiply);
-       NBSLOT("__div__", nb_divide, slot_nb_divide);
-       NBSLOT("__mod__", nb_remainder, slot_nb_remainder);
-       NBSLOT("__divmod__", nb_divmod, slot_nb_divmod);
-       NBSLOT("__pow__", nb_power, slot_nb_power);
-       NBSLOT("__neg__", nb_negative, slot_nb_negative);
-       NBSLOT("__pos__", nb_positive, slot_nb_positive);
-       NBSLOT("__abs__", nb_absolute, slot_nb_absolute);
-       NBSLOT("__nonzero__", nb_nonzero, slot_nb_nonzero);
-       NBSLOT("__invert__", nb_invert, slot_nb_invert);
-       NBSLOT("__lshift__", nb_lshift, slot_nb_lshift);
-       NBSLOT("__rshift__", nb_rshift, slot_nb_rshift);
-       NBSLOT("__and__", nb_and, slot_nb_and);
-       NBSLOT("__xor__", nb_xor, slot_nb_xor);
-       NBSLOT("__or__", nb_or, slot_nb_or);
-       NBSLOT("__coerce__", nb_coerce, slot_nb_coerce);
-       NBSLOT("__int__", nb_int, slot_nb_int);
-       NBSLOT("__long__", nb_long, slot_nb_long);
-       NBSLOT("__float__", nb_float, slot_nb_float);
-       NBSLOT("__oct__", nb_oct, slot_nb_oct);
-       NBSLOT("__hex__", nb_hex, slot_nb_hex);
-       NBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add);
-       NBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract);
-       NBSLOT("__imul__", nb_inplace_multiply, slot_nb_inplace_multiply);
-       NBSLOT("__idiv__", nb_inplace_divide, slot_nb_inplace_divide);
-       NBSLOT("__imod__", nb_inplace_remainder, slot_nb_inplace_remainder);
-       NBSLOT("__ipow__", nb_inplace_power, slot_nb_inplace_power);
-       NBSLOT("__ilshift__", nb_inplace_lshift, slot_nb_inplace_lshift);
-       NBSLOT("__irshift__", nb_inplace_rshift, slot_nb_inplace_rshift);
-       NBSLOT("__iand__", nb_inplace_and, slot_nb_inplace_and);
-       NBSLOT("__ixor__", nb_inplace_xor, slot_nb_inplace_xor);
-       NBSLOT("__ior__", nb_inplace_or, slot_nb_inplace_or);
-       NBSLOT("__floordiv__", nb_floor_divide, slot_nb_floor_divide);
-       NBSLOT("__truediv__", nb_true_divide, slot_nb_true_divide);
+/* Table mapping __foo__ names to tp_foo offsets and slot_tp_foo wrapper
+   functions.  The offsets here are relative to the 'etype' structure, which
+   incorporates the additional structures used for numbers, sequences and
+   mappings.  Note that multiple names may map to the same slot (e.g. __eq__,
+   __ne__ etc. all map to tp_richcompare) and one name may map to multiple
+   slots (e.g. __str__ affects tp_str as well as tp_repr). */
+
+typedef struct {
+       char *name;
+       int offset;
+       void *function;
+       wrapperfunc wrapper;
+} slotdef;
+
+#undef TPSLOT
+#undef ETSLOT
+#undef SQSLOT
+#undef MPSLOT
+#undef NBSLOT
+#undef BINSLOT
+#undef RBINSLOT
+
+#define TPSLOT(NAME, SLOT, FUNCTION, WRAPPER) \
+       {NAME, offsetof(PyTypeObject, SLOT), FUNCTION, WRAPPER}
+#define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER) \
+       {NAME, offsetof(etype, SLOT), FUNCTION, WRAPPER}
+#define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER) \
+       ETSLOT(NAME, as_sequence.SLOT, FUNCTION, WRAPPER)
+#define MPSLOT(NAME, SLOT, FUNCTION, WRAPPER) \
+       ETSLOT(NAME, as_mapping.SLOT, FUNCTION, WRAPPER)
+#define NBSLOT(NAME, SLOT, FUNCTION, WRAPPER) \
+       ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER)
+#define BINSLOT(NAME, SLOT, FUNCTION) \
+       ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l)
+#define RBINSLOT(NAME, SLOT, FUNCTION) \
+       ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r)
+
+static slotdef slotdefs[] = {
+       SQSLOT("__len__", sq_length, slot_sq_length, wrap_inquiry),
+       SQSLOT("__add__", sq_concat, slot_sq_concat, wrap_binaryfunc),
+       SQSLOT("__mul__", sq_repeat, slot_sq_repeat, wrap_intargfunc),
+       SQSLOT("__rmul__", sq_repeat, slot_sq_repeat, wrap_intargfunc),
+       SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item),
+       SQSLOT("__getslice__", sq_slice, slot_sq_slice, wrap_intintargfunc),
+       SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem),
+       SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem),
+       SQSLOT("__setslice__", sq_ass_slice, slot_sq_ass_slice,
+              wrap_intintobjargproc),
+       SQSLOT("__delslice__", sq_ass_slice, slot_sq_ass_slice, wrap_delslice),
+       SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc),
+       SQSLOT("__iadd__", sq_inplace_concat, slot_sq_inplace_concat,
+              wrap_binaryfunc),
+       SQSLOT("__imul__", sq_inplace_repeat, slot_sq_inplace_repeat,
+              wrap_intargfunc),
+
+       MPSLOT("__len__", mp_length, slot_mp_length, wrap_inquiry),
+       MPSLOT("__getitem__", mp_subscript, slot_mp_subscript, wrap_sq_item),
+       MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript,
+              wrap_objobjargproc),
+       MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript,
+              wrap_delitem),
+
+       BINSLOT("__add__", nb_add, slot_nb_add),
+       RBINSLOT("__radd__", nb_add, slot_nb_add),
+       BINSLOT("__sub__", nb_subtract, slot_nb_subtract),
+       RBINSLOT("__rsub__", nb_subtract, slot_nb_subtract),
+       BINSLOT("__mul__", nb_multiply, slot_nb_multiply),
+       RBINSLOT("__rmul__", nb_multiply, slot_nb_multiply),
+       BINSLOT("__div__", nb_divide, slot_nb_divide),
+       RBINSLOT("__rdiv__", nb_divide, slot_nb_divide),
+       BINSLOT("__mod__", nb_remainder, slot_nb_remainder),
+       RBINSLOT("__rmod__", nb_remainder, slot_nb_remainder),
+       BINSLOT("__divmod__", nb_divmod, slot_nb_divmod),
+       RBINSLOT("__rdivmod__", nb_divmod, slot_nb_divmod),
+       NBSLOT("__pow__", nb_power, slot_nb_power, wrap_ternaryfunc),
+       NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_ternaryfunc_r),
+       NBSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc),
+       NBSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc),
+       NBSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc),
+       NBSLOT("__nonzero__", nb_nonzero, slot_nb_nonzero, wrap_unaryfunc),
+       NBSLOT("__invert__", nb_invert, slot_nb_invert, wrap_unaryfunc),
+       BINSLOT("__lshift__", nb_lshift, slot_nb_lshift),
+       RBINSLOT("__rlshift__", nb_lshift, slot_nb_lshift),
+       BINSLOT("__rshift__", nb_rshift, slot_nb_rshift),
+       RBINSLOT("__rrshift__", nb_rshift, slot_nb_rshift),
+       BINSLOT("__and__", nb_and, slot_nb_and),
+       RBINSLOT("__rand__", nb_and, slot_nb_and),
+       BINSLOT("__xor__", nb_xor, slot_nb_xor),
+       RBINSLOT("__rxor__", nb_xor, slot_nb_xor),
+       BINSLOT("__or__", nb_or, slot_nb_or),
+       RBINSLOT("__ror__", nb_or, slot_nb_or),
+       NBSLOT("__coerce__", nb_coerce, slot_nb_coerce, wrap_coercefunc),
+       NBSLOT("__int__", nb_int, slot_nb_int, wrap_unaryfunc),
+       NBSLOT("__long__", nb_long, slot_nb_long, wrap_unaryfunc),
+       NBSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc),
+       NBSLOT("__oct__", nb_oct, slot_nb_oct, wrap_unaryfunc),
+       NBSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc),
+       NBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add,
+              wrap_binaryfunc),
+       NBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract,
+              wrap_binaryfunc),
+       NBSLOT("__imul__", nb_inplace_multiply, slot_nb_inplace_multiply,
+              wrap_binaryfunc),
+       NBSLOT("__idiv__", nb_inplace_divide, slot_nb_inplace_divide,
+              wrap_binaryfunc),
+       NBSLOT("__imod__", nb_inplace_remainder, slot_nb_inplace_remainder,
+              wrap_binaryfunc),
+       NBSLOT("__ipow__", nb_inplace_power, slot_nb_inplace_power,
+              wrap_ternaryfunc),
+       NBSLOT("__ilshift__", nb_inplace_lshift, slot_nb_inplace_lshift,
+              wrap_binaryfunc),
+       NBSLOT("__irshift__", nb_inplace_rshift, slot_nb_inplace_rshift,
+              wrap_binaryfunc),
+       NBSLOT("__iand__", nb_inplace_and, slot_nb_inplace_and,
+              wrap_binaryfunc),
+       NBSLOT("__ixor__", nb_inplace_xor, slot_nb_inplace_xor,
+              wrap_binaryfunc),
+       NBSLOT("__ior__", nb_inplace_or, slot_nb_inplace_or,
+              wrap_binaryfunc),
+       BINSLOT("__floordiv__", nb_floor_divide, slot_nb_floor_divide),
+       RBINSLOT("__rfloordiv__", nb_floor_divide, slot_nb_floor_divide),
+       BINSLOT("__truediv__", nb_true_divide, slot_nb_true_divide),
+       RBINSLOT("__rtruediv__", nb_true_divide, slot_nb_true_divide),
        NBSLOT("__ifloordiv__", nb_inplace_floor_divide,
-              slot_nb_inplace_floor_divide);
+              slot_nb_inplace_floor_divide, wrap_binaryfunc),
        NBSLOT("__itruediv__", nb_inplace_true_divide,
-              slot_nb_inplace_true_divide);
-
-       if (dict == NULL ||
-           PyDict_GetItemString(dict, "__str__") ||
-           PyDict_GetItemString(dict, "__repr__"))
-               type->tp_print = NULL;
-
-       TPSLOT("__cmp__", tp_compare, _PyObject_SlotCompare);
-       TPSLOT("__repr__", tp_repr, slot_tp_repr);
-       TPSLOT("__hash__", tp_hash, slot_tp_hash);
-       TPSLOT("__call__", tp_call, slot_tp_call);
-       TPSLOT("__str__", tp_str, slot_tp_str);
-       TPSLOT("__getattribute__", tp_getattro, slot_tp_getattro);
-       TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook);
-       TPSLOT("__setattr__", tp_setattro, slot_tp_setattro);
-       TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare);
-       TPSLOT("__le__", tp_richcompare, slot_tp_richcompare);
-       TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare);
-       TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare);
-       TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare);
-       TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare);
-       TPSLOT("__iter__", tp_iter, slot_tp_iter);
-       TPSLOT("next", tp_iternext, slot_tp_iternext);
-       TPSLOT("__get__", tp_descr_get, slot_tp_descr_get);
-       TPSLOT("__set__", tp_descr_set, slot_tp_descr_set);
-       TPSLOT("__init__", tp_init, slot_tp_init);
-       TPSLOT("__new__", tp_new, slot_tp_new);
+              slot_nb_inplace_true_divide, wrap_binaryfunc),
+
+       TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc),
+       TPSLOT("__str__", tp_print, NULL, NULL),
+       TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc),
+       TPSLOT("__repr__", tp_print, NULL, NULL),
+       TPSLOT("__cmp__", tp_compare, _PyObject_SlotCompare, wrap_cmpfunc),
+       TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc),
+       TPSLOT("__call__", tp_call, slot_tp_call, wrap_call),
+       TPSLOT("__getattribute__", tp_getattro, slot_tp_getattro,
+              wrap_binaryfunc),
+       TPSLOT("__getattribute__", tp_getattr, NULL, NULL),
+       TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL),
+       TPSLOT("__getattr__", tp_getattr, NULL, NULL),
+       TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr),
+       TPSLOT("__setattr__", tp_setattr, NULL, NULL),
+       TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr),
+       TPSLOT("__delattr__", tp_setattr, NULL, NULL),
+       TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt),
+       TPSLOT("__le__", tp_richcompare, slot_tp_richcompare, richcmp_le),
+       TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare, richcmp_eq),
+       TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare, richcmp_ne),
+       TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare, richcmp_gt),
+       TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge),
+       TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc),
+       TPSLOT("next", tp_iternext, slot_tp_iternext, wrap_next),
+       TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get),
+       TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set),
+       TPSLOT("__init__", tp_init, slot_tp_init, wrap_init),
+       TPSLOT("__new__", tp_new, slot_tp_new, NULL),
+       {NULL}
+};
+
+static int
+update_slot(PyTypeObject *type, PyObject *name, PyObject *value)
+{
+       char *s;
+       int n;
+       slotdef *p;
+       void **ptr;
+
+       assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
+       if (value == NULL)
+               return 0; /* Can't unset a slot */
+       s = PyString_AsString(name);
+       n = PyString_Size(name);
+       if (s == NULL || n < 0) {
+               /* Shouldn't happen, but can't be bothered */
+               PyErr_Clear();
+               return 0;
+       }
+       if (!(s[0] == '_' && s[1] == '_' && s[n-1] == '_' && s[n-2] == '_'))
+               return 0;
+       for (p = slotdefs; p->name; p++) {
+               if (!strcmp(p->name, s)) {
+                       ptr = (void **) ((char *)type + p->offset);
+                       *ptr = p->function;
+               }
+       }
+       return 0;
+}
+
+static void **
+slotptr(PyTypeObject *type, int offset)
+{
+       char *ptr;
+
+       assert(offset >= 0);
+       assert(offset < offsetof(etype, as_buffer));
+       if (offset >= offsetof(etype, as_mapping)) {
+               ptr = (void *)type->tp_as_mapping;
+               offset -= offsetof(etype, as_mapping);
+       }
+       else if (offset >= offsetof(etype, as_sequence)) {
+               ptr = (void *)type->tp_as_sequence;
+               offset -= offsetof(etype, as_sequence);
+       }
+       else if (offset >= offsetof(etype, as_number)) {
+               ptr = (void *)type->tp_as_number;
+               offset -= offsetof(etype, as_number);
+       }
+       else {
+               ptr = (void *)type;
+       }
+       if (ptr != NULL)
+               ptr += offset;
+       return (void **)ptr;
+}
+
+static void
+fixup_slot_dispatchers(PyTypeObject *type)
+{
+       slotdef *p;
+       PyObject *mro, *descr;
+       PyTypeObject *base;
+       PyWrapperDescrObject *d;
+       int i, n;
+       void **ptr;
+
+       for (p = slotdefs; p->name; p++) {
+               ptr = slotptr(type, p->offset);
+               if (ptr)
+                       *ptr = NULL;
+       }
+       mro = type->tp_mro;
+       assert(PyTuple_Check(mro));
+       n = PyTuple_GET_SIZE(mro);
+       for (p = slotdefs; p->name; p++) {
+               for (i = 0; i < n; i++) {
+                       base = (PyTypeObject *)PyTuple_GET_ITEM(mro, i);
+                       assert(PyType_Check(base));
+                       descr = PyDict_GetItemString(
+                               base->tp_defined, p->name);
+                       if (descr == NULL)
+                               continue;
+                       ptr = slotptr(type, p->offset);
+                       if (ptr == NULL)
+                               continue;
+                       if (descr->ob_type == &PyWrapperDescr_Type) {
+                               d = (PyWrapperDescrObject *)descr;
+                               if (d->d_base->wrapper == p->wrapper) {
+                                       if (*ptr == NULL) {
+                                               *ptr = d->d_wrapped;
+                                               continue;
+                                       }
+                                       if (p->wrapper == wrap_binaryfunc_r)
+                                               continue;
+                               }
+                       }
+                       *ptr = p->function;
+                       break;
+               }
+       }
 }