Massive changes as per PEP 208.  Read it for details.
diff --git a/Objects/abstract.c b/Objects/abstract.c
index dfdfc43..9050a4c 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -1,7 +1,12 @@
 /* Abstract Object Interface (many thanks to Jim Fulton) */
 
+
 #include "Python.h"
 #include <ctype.h>
+#include "structmember.h" /* we need the offsetof() macro from there */
+
+#define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \
+				Py_TPFLAGS_NEWSTYLENUMBER)
 
 /* Shorthands to return certain errors */
 
@@ -281,222 +286,282 @@
 
 /* Binary operators */
 
-#define BINOP(v, w, opname, ropname, thisfunc) \
-	if (PyInstance_Check(v) || PyInstance_Check(w)) \
-		return PyInstance_DoBinOp(v, w, opname, ropname, thisfunc)
+/* New style number protocol support */
 
-PyObject *
-PyNumber_Or(PyObject *v, PyObject *w)
+#define NB_SLOT(x) offsetof(PyNumberMethods, x)
+#define NB_BINOP(nb_methods, slot) \
+		((binaryfunc*)(& ((char*)nb_methods)[slot] ))
+#define NB_TERNOP(nb_methods, slot) \
+		((ternaryfunc*)(& ((char*)nb_methods)[slot] ))
+
+/*
+  Calling scheme used for binary operations:
+
+  v	w	Action
+  -------------------------------------------------------------------
+  new	new	v.op(v,w), w.op(v,w)
+  new	old	v.op(v,w), coerce(v,w), v.op(v,w)
+  old	new	w.op(v,w), coerce(v,w), v.op(v,w)
+  old	old	coerce(v,w), v.op(v,w)
+
+  Legend:
+  -------
+  * new == new style number
+  * old == old style number
+  * Action indicates the order in which operations are tried until either
+    a valid result is produced or an error occurs.
+
+ */
+
+static PyObject *
+binary_op1(PyObject *v, PyObject *w, const int op_slot)
 {
-	BINOP(v, w, "__or__", "__ror__", PyNumber_Or);
-	if (v->ob_type->tp_as_number != NULL) {
-		PyObject *x = NULL;
-		PyObject * (*f)(PyObject *, PyObject *) = NULL;
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_or) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
+	PyObject *x;
+	binaryfunc *slot;
+	if (v->ob_type->tp_as_number != NULL && NEW_STYLE_NUMBER(v)) {
+		slot = NB_BINOP(v->ob_type->tp_as_number, op_slot);
+		if (*slot) {
+			x = (*slot)(v, w);
+			if (x != Py_NotImplemented) {
+				return x;
+			}
+			Py_DECREF(x); /* can't do it */
+		}
+		if (v->ob_type == w->ob_type) {
+			goto binop_error;
+		}
 	}
-	return type_error("bad operand type(s) for |");
+	if (w->ob_type->tp_as_number != NULL && NEW_STYLE_NUMBER(w)) {
+		slot = NB_BINOP(w->ob_type->tp_as_number, op_slot);
+		if (*slot) {
+			x = (*slot)(v, w);
+			if (x != Py_NotImplemented) {
+				return x;
+			}
+			Py_DECREF(x); /* can't do it */
+		}
+	}
+	if (!NEW_STYLE_NUMBER(v) || !NEW_STYLE_NUMBER(w)) {
+		int err = PyNumber_CoerceEx(&v, &w);
+		if (err < 0) {
+			return NULL;
+		}
+		if (err == 0) {
+			PyNumberMethods *mv = v->ob_type->tp_as_number;
+			if (mv) {
+				slot = NB_BINOP(mv, op_slot);
+				if (*slot) {
+					PyObject *x = (*slot)(v, w);
+					Py_DECREF(v);
+					Py_DECREF(w);
+					return x;
+				}
+			}
+			/* CoerceEx incremented the reference counts */
+			Py_DECREF(v);
+			Py_DECREF(w);
+		}
+	}
+binop_error:
+	Py_INCREF(Py_NotImplemented);
+	return Py_NotImplemented;
+}
+	    
+static PyObject *
+binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name)
+{
+	PyObject *result = binary_op1(v, w, op_slot);
+	if (result == Py_NotImplemented) {
+		Py_DECREF(Py_NotImplemented);
+		PyErr_Format(PyExc_TypeError, 
+				"unsupported operand type(s) for %s", op_name);
+		return NULL;
+	}
+	return result;
 }
 
-PyObject *
-PyNumber_Xor(PyObject *v, PyObject *w)
+
+/*
+  Calling scheme used for ternary operations:
+
+  v	w	z	Action
+  -------------------------------------------------------------------
+  new	new	new	v.op(v,w,z), w.op(v,w,z), z.op(v,w,z)
+  new	old	new	v.op(v,w,z), z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
+  old	new	new	w.op(v,w,z), z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
+  old	old	new	z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
+  new	new	old	v.op(v,w,z), w.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
+  new	old	old	v.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
+  old	new	old	w.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
+  old	old	old	coerce(v,w,z), v.op(v,w,z)
+
+  Legend:
+  -------
+  * new == new style number
+  * old == old style number
+  * Action indicates the order in which operations are tried until either
+    a valid result is produced or an error occurs.
+  * coerce(v,w,z) actually does: coerce(v,w), coerce(v,z), coerce(w,z) and
+    only if z != Py_None; if z == Py_None, then it is treated as absent
+    variable and only coerce(v,w) is tried.
+
+ */
+
+static PyObject *
+ternary_op(PyObject *v,
+	   PyObject *w,
+	   PyObject *z,
+	   const int op_slot,
+	   const char *op_name)
 {
-	BINOP(v, w, "__xor__", "__rxor__", PyNumber_Xor);
-	if (v->ob_type->tp_as_number != NULL) {
-		PyObject *x = NULL;
-		PyObject * (*f)(PyObject *, PyObject *) = NULL;
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_xor) != NULL)
-			x = (*f)(v, w);
+	PyNumberMethods *mv, *mw, *mz;
+	register PyObject *x = NULL;
+	register ternaryfunc *slot;
+	
+	mv = v->ob_type->tp_as_number;
+	if (mv != NULL && NEW_STYLE_NUMBER(v)) {
+		/* try v.op(v,w,z) */
+		slot = NB_TERNOP(mv, op_slot);
+		if (*slot) {
+			x = (*slot)(v, w, z);
+			if (x != Py_NotImplemented)
+				return x;
+			/* Can't do it... fall through */
+			Py_DECREF(x);
+		}
+		if (v->ob_type == w->ob_type &&
+				(z == Py_None || z->ob_type == v->ob_type)) {
+			goto ternary_error;
+		}
+	}
+	mw = w->ob_type->tp_as_number;
+	if (mw != NULL && NEW_STYLE_NUMBER(w)) {
+		/* try w.op(v,w,z) */
+		slot = NB_TERNOP(mw,op_slot);
+		if (*slot) {
+			x = (*slot)(v, w, z);
+			if (x != Py_NotImplemented)
+				return x;
+			/* Can't do it... fall through */
+			Py_DECREF(x);
+		}
+		if (NEW_STYLE_NUMBER(v) &&
+				(z == Py_None || z->ob_type == v->ob_type)) {
+			goto ternary_error;
+		}
+	}
+	mz = z->ob_type->tp_as_number;
+	if (mz != NULL && NEW_STYLE_NUMBER(z)) {
+		/* try: z.op(v,w,z) */
+		slot = NB_TERNOP(mz, op_slot);
+		if (*slot) {
+			x = (*slot)(v, w, z);
+			if (x != Py_NotImplemented)
+				return x;
+			/* Can't do it... fall through */
+			Py_DECREF(x);
+		}
+	}
+
+	if (!NEW_STYLE_NUMBER(v) || !NEW_STYLE_NUMBER(w) ||
+			(z != Py_None && !NEW_STYLE_NUMBER(z))) {
+		/* we have an old style operand, coerce */
+		PyObject *v1, *z1, *w2, *z2;
+		int c;
+		
+		c = PyNumber_Coerce(&v, &w);
+		if (c != 0)
+			goto error3;
+
+		/* Special case: if the third argument is None, it is
+		   treated as absent argument and not coerced. */
+		if (z == Py_None) {
+			if (v->ob_type->tp_as_number) {
+				slot = NB_TERNOP(v->ob_type->tp_as_number,
+						 op_slot);
+				if (*slot)
+					x = (*slot)(v, w, z);
+				else
+					c = -1;
+			}
+			else
+				c = -1;
+			goto error2;
+		}
+		v1 = v;
+		z1 = z;
+		c = PyNumber_Coerce(&v1, &z1);
+		if (c != 0)
+			goto error2;
+		w2 = w;
+		z2 = z1;
+		c = PyNumber_Coerce(&w2, &z2);
+		if (c != 0)
+			goto error1;
+
+		if (v1->ob_type->tp_as_number != NULL) {
+			slot = NB_TERNOP(v1->ob_type->tp_as_number,
+					 op_slot);
+			if (*slot)
+				x = (*slot)(v1, w2, z2);
+			else
+				c = -1;
+		}
+		else
+			c = -1;
+
+		Py_DECREF(w2);
+		Py_DECREF(z2);
+	error1:
+		Py_DECREF(v1);
+		Py_DECREF(z1);
+	error2:
 		Py_DECREF(v);
 		Py_DECREF(w);
-		if (f != NULL)
+	error3:
+		if (c >= 0)
 			return x;
 	}
-	return type_error("bad operand type(s) for ^");
+	
+ternary_error:
+	PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for %s",
+			op_name);
+	return NULL;
 }
 
-PyObject *
-PyNumber_And(PyObject *v, PyObject *w)
-{
-	BINOP(v, w, "__and__", "__rand__", PyNumber_And);
-	if (v->ob_type->tp_as_number != NULL) {
-		PyObject *x = NULL;
-		PyObject * (*f)(PyObject *, PyObject *) = NULL;
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_and) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-	return type_error("bad operand type(s) for &");
-}
+#define BINARY_FUNC(func, op, op_name) \
+    PyObject * \
+    func(PyObject *v, PyObject *w) { \
+	    return binary_op(v, w, NB_SLOT(op), op_name); \
+    }
 
-PyObject *
-PyNumber_Lshift(PyObject *v, PyObject *w)
-{
-	BINOP(v, w, "__lshift__", "__rlshift__", PyNumber_Lshift);
-	if (v->ob_type->tp_as_number != NULL) {
-		PyObject *x = NULL;
-		PyObject * (*f)(PyObject *, PyObject *) = NULL;
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_lshift) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-	return type_error("bad operand type(s) for <<");
-}
-
-PyObject *
-PyNumber_Rshift(PyObject *v, PyObject *w)
-{
-	BINOP(v, w, "__rshift__", "__rrshift__", PyNumber_Rshift);
-	if (v->ob_type->tp_as_number != NULL) {
-		PyObject *x = NULL;
-		PyObject * (*f)(PyObject *, PyObject *) = NULL;
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_rshift) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-	return type_error("bad operand type(s) for >>");
-}
+BINARY_FUNC(PyNumber_Or, nb_or, "|")
+BINARY_FUNC(PyNumber_Xor, nb_xor, "^")
+BINARY_FUNC(PyNumber_And, nb_and, "&")
+BINARY_FUNC(PyNumber_Lshift, nb_lshift, "<<")
+BINARY_FUNC(PyNumber_Rshift, nb_rshift, ">>")
+BINARY_FUNC(PyNumber_Subtract, nb_subtract, "-")
+BINARY_FUNC(PyNumber_Multiply, nb_multiply, "*")
+BINARY_FUNC(PyNumber_Divide, nb_divide, "/")
+BINARY_FUNC(PyNumber_Divmod, nb_divmod, "divmod()")
 
 PyObject *
 PyNumber_Add(PyObject *v, PyObject *w)
 {
-	PySequenceMethods *m;
-
-	BINOP(v, w, "__add__", "__radd__", PyNumber_Add);
-	m = v->ob_type->tp_as_sequence;
-	if (m && m->sq_concat)
-		return (*m->sq_concat)(v, w);
-	else if (v->ob_type->tp_as_number != NULL) {
-		PyObject *x = NULL;
-		PyObject * (*f)(PyObject *, PyObject *) = NULL;
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_add) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-	return type_error("bad operand type(s) for +");
-}
-
-PyObject *
-PyNumber_Subtract(PyObject *v, PyObject *w)
-{
-	BINOP(v, w, "__sub__", "__rsub__", PyNumber_Subtract);
-	if (v->ob_type->tp_as_number != NULL) {
-		PyObject *x = NULL;
-		PyObject * (*f)(PyObject *, PyObject *) = NULL;
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_subtract) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-	return type_error("bad operand type(s) for -");
-}
-
-PyObject *
-PyNumber_Multiply(PyObject *v, PyObject *w)
-{
-	PyTypeObject *tp = v->ob_type;
-	PySequenceMethods *m;
-
-	BINOP(v, w, "__mul__", "__rmul__", PyNumber_Multiply);
-	if (tp->tp_as_number != NULL &&
-	    w->ob_type->tp_as_sequence != NULL) {
-		/* number*sequence -- swap v and w */
-		PyObject *tmp = v;
-		v = w;
-		w = tmp;
-		tp = v->ob_type;
-	}
-	if (tp->tp_as_number != NULL) {
-		PyObject *x = NULL;
-		PyObject * (*f)(PyObject *, PyObject *) = NULL;
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_multiply) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-	m = tp->tp_as_sequence;
-	if (m && m->sq_repeat) {
-		long mul_value;
-
-		if (PyInt_Check(w)) {
-			mul_value = PyInt_AsLong(w);
+	PyObject *result = binary_op1(v, w, NB_SLOT(nb_add));
+	if (result == Py_NotImplemented) {
+		PySequenceMethods *m = v->ob_type->tp_as_sequence;
+		Py_DECREF(Py_NotImplemented);
+		if (m && m->sq_concat) {
+			result = (*m->sq_concat)(v, w);
 		}
-		else if (PyLong_Check(w)) {
-			mul_value = PyLong_AsLong(w);
-			if (mul_value == -1 && PyErr_Occurred())
-                                return NULL; 
-		}
-		else {
-			return type_error(
-				"can't multiply sequence with non-int");
-		}
-		return (*m->sq_repeat)(v, (int)mul_value);
+                else {
+                    PyErr_SetString(PyExc_TypeError,
+                                    "unsupported operand types for +");
+                    result = NULL;
+                }
 	}
-	return type_error("bad operand type(s) for *");
-}
-
-PyObject *
-PyNumber_Divide(PyObject *v, PyObject *w)
-{
-	BINOP(v, w, "__div__", "__rdiv__", PyNumber_Divide);
-	if (v->ob_type->tp_as_number != NULL) {
-		PyObject *x = NULL;
-		PyObject * (*f)(PyObject *, PyObject *) = NULL;
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_divide) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-	return type_error("bad operand type(s) for /");
+	return result;
 }
 
 PyObject *
@@ -506,605 +571,130 @@
 		return PyString_Format(v, w);
 	else if (PyUnicode_Check(v))
 		return PyUnicode_Format(v, w);
-	BINOP(v, w, "__mod__", "__rmod__", PyNumber_Remainder);
-	if (v->ob_type->tp_as_number != NULL) {
-		PyObject *x = NULL;
-		PyObject * (*f)(PyObject *, PyObject *) = NULL;
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_remainder) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-	return type_error("bad operand type(s) for %");
-}
-
-PyObject *
-PyNumber_Divmod(PyObject *v, PyObject *w)
-{
-	BINOP(v, w, "__divmod__", "__rdivmod__", PyNumber_Divmod);
-	if (v->ob_type->tp_as_number != NULL) {
-		PyObject *x = NULL;
-		PyObject * (*f)(PyObject *, PyObject *) = NULL;
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_divmod) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-	return type_error("bad operand type(s) for divmod()");
-}
-
-/* Power (binary or ternary) */
-
-static PyObject *
-do_pow(PyObject *v, PyObject *w)
-{
-	PyObject *res;
-	PyObject * (*f)(PyObject *, PyObject *, PyObject *);
-	BINOP(v, w, "__pow__", "__rpow__", do_pow);
-	if (v->ob_type->tp_as_number == NULL ||
-	    w->ob_type->tp_as_number == NULL) {
-		PyErr_SetString(PyExc_TypeError,
-				"pow(x, y) requires numeric arguments");
-		return NULL;
-	}
-	if (PyNumber_Coerce(&v, &w) != 0)
-		return NULL;
-	if (v->ob_type->tp_as_number != NULL &&
-	    (f = v->ob_type->tp_as_number->nb_power) != NULL)
-		res = (*f)(v, w, Py_None);
-	else
-		res = type_error("pow(x, y) not defined for these operands");
-	Py_DECREF(v);
-	Py_DECREF(w);
-	return res;
+	return binary_op(v, w, NB_SLOT(nb_remainder), "%");
 }
 
 PyObject *
 PyNumber_Power(PyObject *v, PyObject *w, PyObject *z)
 {
-	PyObject *res;
-	PyObject *v1, *z1, *w2, *z2;
-	PyObject * (*f)(PyObject *, PyObject *, PyObject *);
-
-	if (z == Py_None)
-		return do_pow(v, w);
-	/* XXX The ternary version doesn't do class instance coercions */
-	if (PyInstance_Check(v))
-		return v->ob_type->tp_as_number->nb_power(v, w, z);
-	if (v->ob_type->tp_as_number == NULL ||
-	    z->ob_type->tp_as_number == NULL ||
-	    w->ob_type->tp_as_number == NULL) {
-		return type_error("pow(x, y, z) requires numeric arguments");
-	}
-	if (PyNumber_Coerce(&v, &w) != 0)
-		return NULL;
-	res = NULL;
-	v1 = v;
-	z1 = z;
-	if (PyNumber_Coerce(&v1, &z1) != 0)
-		goto error2;
-	w2 = w;
-	z2 = z1;
- 	if (PyNumber_Coerce(&w2, &z2) != 0)
-		goto error1;
-	if (v->ob_type->tp_as_number != NULL &&
-	    (f = v1->ob_type->tp_as_number->nb_power) != NULL)
-		res = (*f)(v1, w2, z2);
-	else
-		res = type_error(
-			"pow(x, y, z) not defined for these operands");
-	Py_DECREF(w2);
-	Py_DECREF(z2);
-  error1:
-	Py_DECREF(v1);
-	Py_DECREF(z1);
-  error2:
-	Py_DECREF(v);
-	Py_DECREF(w);
-	return res;
+	return ternary_op(v, w, z, NB_SLOT(nb_power), "** or pow()");
 }
 
 /* Binary in-place operators */
 
 /* The in-place operators are defined to fall back to the 'normal',
-   non in-place operations, if the in-place methods are not in place, and to
-   take class instances into account. This is how it is supposed to work:
+   non in-place operations, if the in-place methods are not in place.
 
-   - If the left-hand-side object (the first argument) is an
-     instance object, try to let PyInstance_HalfBinOp() handle it.  Pass the
-     non in-place variant of the function as callback, because it will only
-     be used if the left-hand object is changed by coercion.
-
-   - Otherwise, if the left hand object is not an instance object, it has
-     the appropriate struct members, and they are filled, call the
-     appropriate function and return the result. No coercion is done on the
-     arguments; the left-hand object is the one the operation is performed
-     on, and it's up to the function to deal with the right-hand object.
+   - If the left hand object has the appropriate struct members, and
+     they are filled, call the appropriate function and return the
+     result.  No coercion is done on the arguments; the left-hand object
+     is the one the operation is performed on, and it's up to the
+     function to deal with the right-hand object.
      
    - Otherwise, in-place modification is not supported. Handle it exactly as
-     a non in-place operation of the same kind:
-
-     - If either object is an instance, let PyInstance_DoBinOp() handle it.
-     
-     - Otherwise, both arguments are C types. If the left-hand object has
-       the appropriate struct members filled, coerce, call the
-       appropriate function, and return the result.
-  
-     - Otherwise, we are out of options: raise a type error specific to
-       augmented assignment.
+     a non in-place operation of the same kind.
 
    */
 
 #define HASINPLACE(t) PyType_HasFeature((t)->ob_type, Py_TPFLAGS_HAVE_INPLACEOPS)
 
-PyObject *
-PyNumber_InPlaceOr(PyObject *v, PyObject *w)
+static PyObject *
+binary_iop(PyObject *v, PyObject *w, const int iop_slot, const int op_slot,
+		const char *op_name)
 {
-	PyObject * (*f)(PyObject *, PyObject *) = NULL;
-	PyObject *x = NULL;
-
-	if (PyInstance_Check(v)) {
-		if (PyInstance_HalfBinOp(v, w, "__ior__", &x,
-					 PyNumber_Or, 0) <= 0)
-			return x;
+	PyNumberMethods *mv = v->ob_type->tp_as_number;
+	if (mv != NULL && HASINPLACE(v)) {
+		binaryfunc *slot = NB_BINOP(mv, iop_slot);
+		if (*slot) {
+			PyObject *x = (*slot)(v, w);
+			if (x != Py_NotImplemented) {
+				return x;
+			}
+			Py_DECREF(x);
+		}
 	}
-	else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
-		 (f = v->ob_type->tp_as_number->nb_inplace_or) != NULL)
-		return (*f)(v, w);
-
-	BINOP(v, w, "__or__", "__ror__", PyNumber_Or);
-
-	if (v->ob_type->tp_as_number != NULL) {
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_or) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-
-	return type_error("bad operand type(s) for |=");
+	return binary_op(v, w, op_slot, op_name);
 }
 
-PyObject *
-PyNumber_InPlaceXor(PyObject *v, PyObject *w)
-{
-	PyObject * (*f)(PyObject *, PyObject *) = NULL;
-	PyObject *x = NULL;
-
-	if (PyInstance_Check(v)) {
-		if (PyInstance_HalfBinOp(v, w, "__ixor__", &x,
-					 PyNumber_Xor, 0) <= 0)
-			return x;
-	}
-	else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
-		 (f = v->ob_type->tp_as_number->nb_inplace_xor) != NULL)
-		return (*f)(v, w);
-
-	BINOP(v, w, "__xor__", "__rxor__", PyNumber_Xor);
-
-	if (v->ob_type->tp_as_number != NULL) {
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_xor) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
+#define INPLACE_BINOP(func, iop, op, op_name) \
+	PyObject * \
+	func(PyObject *v, PyObject *w) { \
+		return binary_iop(v, w, NB_SLOT(iop), NB_SLOT(op), op_name); \
 	}
 
-	return type_error("bad operand type(s) for ^=");
-}
-
-PyObject *
-PyNumber_InPlaceAnd(PyObject *v, PyObject *w)
-{
-	PyObject * (*f)(PyObject *, PyObject *) = NULL;
-	PyObject *x = NULL;
-
-	if (PyInstance_Check(v)) {
-		if (PyInstance_HalfBinOp(v, w, "__iand__", &x,
-					 PyNumber_And, 0) <= 0)
-			return x;
-	}
-	else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
-		 (f = v->ob_type->tp_as_number->nb_inplace_and) != NULL)
-		return (*f)(v, w);
-
-	BINOP(v, w, "__and__", "__rand__", PyNumber_And);
-
-	if (v->ob_type->tp_as_number != NULL) {
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_and) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-
-	return type_error("bad operand type(s) for &=");
-}
-
-PyObject *
-PyNumber_InPlaceLshift(PyObject *v, PyObject *w)
-{
-	PyObject * (*f)(PyObject *, PyObject *) = NULL;
-	PyObject *x = NULL;
-
-	if (PyInstance_Check(v)) {
-		if (PyInstance_HalfBinOp(v, w, "__ilshift__", &x,
-					PyNumber_Lshift, 0) <= 0)
-			return x;
-	}
-	else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
-		 (f = v->ob_type->tp_as_number->nb_inplace_lshift) != NULL)
-		return (*f)(v, w);
-
-	BINOP(v, w, "__lshift__", "__rlshift__", PyNumber_Lshift);
-
-	if (v->ob_type->tp_as_number != NULL) {
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_lshift) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-
-	return type_error("bad operand type(s) for <<=");
-}
-
-PyObject *
-PyNumber_InPlaceRshift(PyObject *v, PyObject *w)
-{
-	PyObject * (*f)(PyObject *, PyObject *) = NULL;
-	PyObject *x = NULL;
-
-	if (PyInstance_Check(v)) {
-		if (PyInstance_HalfBinOp(v, w, "__irshift__", &x,
-					PyNumber_Rshift, 0) <= 0)
-			return x;
-	}
-	else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
-		 (f = v->ob_type->tp_as_number->nb_inplace_rshift) != NULL)
-		return (*f)(v, w);
-
-	BINOP(v, w, "__rshift__", "__rrshift__", PyNumber_Rshift);
-
-	if (v->ob_type->tp_as_number != NULL) {
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_rshift) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-
-	return type_error("bad operand type(s) for >>=");
-}
+INPLACE_BINOP(PyNumber_InPlaceOr, nb_inplace_or, nb_or, "|=")
+INPLACE_BINOP(PyNumber_InPlaceXor, nb_inplace_xor, nb_xor, "^=")
+INPLACE_BINOP(PyNumber_InPlaceAnd, nb_inplace_and, nb_and, "&=")
+INPLACE_BINOP(PyNumber_InPlaceLshift, nb_inplace_lshift, nb_lshift, "<<=")
+INPLACE_BINOP(PyNumber_InPlaceRshift, nb_inplace_rshift, nb_rshift, ">>=")
+INPLACE_BINOP(PyNumber_InPlaceSubtract, nb_inplace_subtract, nb_subtract, "-=")
+INPLACE_BINOP(PyNumber_InPlaceDivide, nb_inplace_divide, nb_divide, "/=")
 
 PyObject *
 PyNumber_InPlaceAdd(PyObject *v, PyObject *w)
 {
-	PyObject * (*f)(PyObject *, PyObject *) = NULL;
-	PyObject *x = NULL;
-
-	if (PyInstance_Check(v)) {
-		if (PyInstance_HalfBinOp(v, w, "__iadd__", &x,
-					 PyNumber_Add, 0) <= 0)
-			return x;
-	}
-	else if (HASINPLACE(v)) {
-		if (v->ob_type->tp_as_sequence != NULL)
-			f = v->ob_type->tp_as_sequence->sq_inplace_concat;
-		if (f == NULL && v->ob_type->tp_as_number != NULL)
-			f = v->ob_type->tp_as_number->nb_inplace_add;
-		if (f != NULL)
-			return (*f)(v, w);
-	}
-
-	BINOP(v, w, "__add__", "__radd__", PyNumber_Add);
+	binaryfunc f = NULL;
 
 	if (v->ob_type->tp_as_sequence != NULL) {
-		f = v->ob_type->tp_as_sequence->sq_concat;
+		if (HASINPLACE(v))
+			f = v->ob_type->tp_as_sequence->sq_inplace_concat;
+		if (f == NULL)
+			f = v->ob_type->tp_as_sequence->sq_concat;
 		if (f != NULL)
 			return (*f)(v, w);
 	}
-	if (v->ob_type->tp_as_number != NULL) {
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL) {
-			f = v->ob_type->tp_as_number->nb_add;
-			if (f != NULL)
-				x = (*f)(v, w);
-		}
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-
-	return type_error("bad operand type(s) for +=");
-}
-
-PyObject *
-PyNumber_InPlaceSubtract(PyObject *v, PyObject *w)
-{
-	PyObject * (*f)(PyObject *, PyObject *) = NULL;
-	PyObject *x = NULL;
-
-	if (PyInstance_Check(v)) {
-		if (PyInstance_HalfBinOp(v, w, "__isub__", &x,
-					PyNumber_Subtract, 0) <= 0)
-			return x;
-	}
-	else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
-		 (f = v->ob_type->tp_as_number->nb_inplace_subtract) != NULL)
-		return (*f)(v, w);
-
-	BINOP(v, w, "__sub__", "__rsub__", PyNumber_Subtract);
-
-	if (v->ob_type->tp_as_number != NULL) {
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_subtract) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-
-	return type_error("bad operand type(s) for -=");
+	return binary_iop(v, w, NB_SLOT(nb_inplace_add), NB_SLOT(nb_add), "+=");
 }
 
 PyObject *
 PyNumber_InPlaceMultiply(PyObject *v, PyObject *w)
 {
-	PyObject * (*f)(PyObject *, PyObject *) = NULL;
 	PyObject * (*g)(PyObject *, int) = NULL;
-	PyObject *x = NULL;
-
-	if (PyInstance_Check(v)) {
-		if (PyInstance_HalfBinOp(v, w, "__imul__", &x,
-					PyNumber_Multiply, 0) <= 0)
-			return x;
-	}
-	else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
-		 (f = v->ob_type->tp_as_number->nb_inplace_multiply) != NULL)
-		return (*f)(v, w);
-	else if (v->ob_type->tp_as_sequence != NULL && HASINPLACE(v) &&
-		 (g = v->ob_type->tp_as_sequence->sq_inplace_repeat) != NULL) {
-		long mul_value;
-
+	if (HASINPLACE(v) && v->ob_type->tp_as_sequence &&
+		(g = v->ob_type->tp_as_sequence->sq_inplace_repeat)) {
+		long n;
 		if (PyInt_Check(w)) {
-			mul_value = PyInt_AsLong(w);
+			n  = PyInt_AsLong(w);
 		}
 		else if (PyLong_Check(w)) {
-			mul_value = PyLong_AsLong(w);
-			if (mul_value == -1 && PyErr_Occurred())
-                                return NULL; 
+			n = PyLong_AsLong(w);
+			if (n == -1 && PyErr_Occurred())
+				return NULL;
 		}
 		else {
-			return type_error(
-				"can't multiply sequence with non-int");
+			return type_error("can't multiply sequence to non-int");
 		}
-		return (*g)(v, (int)mul_value);
+		return (*g)(v, (int)n);
 	}
-
-	BINOP(v, w, "__mul__", "__rmul__", PyNumber_Multiply);
-
-	if (v->ob_type->tp_as_number != NULL) {
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_multiply) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-	else if (v->ob_type->tp_as_sequence != NULL &&
-		 (g = v->ob_type->tp_as_sequence->sq_repeat) != NULL) {
-		long mul_value;
-
-		if (PyInt_Check(w)) {
-			mul_value = PyInt_AsLong(w);
-		}
-		else if (PyLong_Check(w)) {
-			mul_value = PyLong_AsLong(w);
-			if (mul_value == -1 && PyErr_Occurred())
-                                return NULL; 
-		}
-		else {
-			return type_error(
-				"can't multiply sequence with non-int");
-		}
-		return (*g)(v, (int)mul_value);
-	}
-	return type_error("bad operand type(s) for *=");
+	return binary_iop(v, w, NB_SLOT(nb_inplace_multiply),
+				NB_SLOT(nb_multiply), "*=");
 }
 
-PyObject *
-PyNumber_InPlaceDivide(PyObject *v, PyObject *w)
-{
-	PyObject * (*f)(PyObject *, PyObject *) = NULL;
-	PyObject *x = NULL;
 
-	if (PyInstance_Check(v)) {
-		if (PyInstance_HalfBinOp(v, w, "__idiv__", &x,
-					PyNumber_Divide, 0) <= 0)
-			return x;
-	}
-	else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
-		 (f = v->ob_type->tp_as_number->nb_inplace_divide) != NULL)
-		return (*f)(v, w);
-
-	BINOP(v, w, "__div__", "__rdiv__", PyNumber_Divide);
-
-	if (v->ob_type->tp_as_number != NULL) {
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if (v->ob_type->tp_as_number != NULL &&
-		    (f = v->ob_type->tp_as_number->nb_divide) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-
-	return type_error("bad operand type(s) for /=");
-}
 
 PyObject *
 PyNumber_InPlaceRemainder(PyObject *v, PyObject *w)
 {
-	PyObject * (*f)(PyObject *, PyObject *) = NULL;
-	PyObject *x = NULL;
-
-	if (PyInstance_Check(v)) {
-		if (PyInstance_HalfBinOp(v, w, "__imod__", &x,
-					PyNumber_Remainder, 0) <= 0)
-			return x;
-	}
-	else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
-		 (f = v->ob_type->tp_as_number->nb_inplace_remainder) != NULL)
-		return (*f)(v, w);
-
 	if (PyString_Check(v))
 		return PyString_Format(v, w);
 	else if (PyUnicode_Check(v))
 		return PyUnicode_Format(v, w);
-
-	BINOP(v, w, "__mod__", "__rmod__", PyNumber_Remainder);
-
-	if (v->ob_type->tp_as_number != NULL) {
-		if (PyNumber_Coerce(&v, &w) != 0)
-			return NULL;
-		if ((f = v->ob_type->tp_as_number->nb_remainder) != NULL)
-			x = (*f)(v, w);
-		Py_DECREF(v);
-		Py_DECREF(w);
-		if (f != NULL)
-			return x;
-	}
-
-	return type_error("bad operand type(s) for %=");
-}
-
-
-/* In-place Power (binary or ternary, for API consistency) */
-
-static PyObject *
-do_inplace_pow(PyObject *v, PyObject *w)
-{
-	PyObject * (*f)(PyObject *, PyObject *, PyObject *) = NULL;
-	PyObject *x = NULL;
-
-	if (PyInstance_Check(v)) {
-		if (PyInstance_HalfBinOp(v, w, "__ipow__", &x, do_pow, 0) <= 0)
-			return x;
-	}
-	else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
-		 (f = v->ob_type->tp_as_number->nb_inplace_power) != NULL)
-		return (*f)(v, w, Py_None);
-
-	BINOP(v, w, "__pow__", "__rpow__", do_pow);
-
-	if (v->ob_type->tp_as_number == NULL ||
-	    w->ob_type->tp_as_number == NULL) {
-		return type_error("bad operand type(s) for **=");
-	}
-	if (PyNumber_Coerce(&v, &w) != 0)
-		return NULL;
-	if ((f = v->ob_type->tp_as_number->nb_power) != NULL)
-		x = (*f)(v, w, Py_None);
 	else
-		x = type_error("bad operand type(s) for **=");
-	Py_DECREF(v);
-	Py_DECREF(w);
-	return x;
+		return binary_iop(v, w, NB_SLOT(nb_inplace_remainder),
+					NB_SLOT(nb_remainder), "%=");
 }
 
+
 PyObject *
 PyNumber_InPlacePower(PyObject *v, PyObject *w, PyObject *z)
 {
-	PyObject *res;
-	PyObject *v1, *z1, *w2, *z2, *oldv;
-	PyObject * (*f)(PyObject *, PyObject *, PyObject *);
-
-	if (z == Py_None)
-		return do_inplace_pow(v, w);
-	/* XXX The ternary version doesn't do class instance coercions */
-	if (PyInstance_Check(v))
-		return v->ob_type->tp_as_number->nb_inplace_power(v, w, z);
-	if (v->ob_type->tp_as_number == NULL ||
-	    z->ob_type->tp_as_number == NULL ||
-	    w->ob_type->tp_as_number == NULL) {
-		return type_error(
-			"(inplace) pow(x, y, z) requires numeric arguments");
+	if (HASINPLACE(v) && v->ob_type->tp_as_number &&
+	    v->ob_type->tp_as_number->nb_inplace_power != NULL) {
+		return ternary_op(v, w, z, NB_SLOT(nb_inplace_power), "**=");
 	}
-	oldv = v;
-	Py_INCREF(oldv);
-	res = NULL;
-	if (PyNumber_Coerce(&v, &w) != 0)
-		goto error3;
-	v1 = v;
-	z1 = z;
-	if (PyNumber_Coerce(&v1, &z1) != 0)
-		goto error2;
-	w2 = w;
-	z2 = z1;
- 	if (PyNumber_Coerce(&w2, &z2) != 0)
-		goto error1;
-	if (oldv == v1 && HASINPLACE(v1) &&
-	    v->ob_type->tp_as_number != NULL &&
-	    (f = v1->ob_type->tp_as_number->nb_inplace_power) != NULL)
-		res = (*f)(v1, w2, z2);
-	else if (v1->ob_type->tp_as_number != NULL &&
-		 (f = v1->ob_type->tp_as_number->nb_power) != NULL)
-		res = (*f)(v1, w2, z2);
-	else
-		res = type_error(
-		     "(inplace) pow(x, y, z) not defined for these operands");
-	Py_DECREF(w2);
-	Py_DECREF(z2);
-  error1:
-	Py_DECREF(v1);
-	Py_DECREF(z1);
-  error2:
-	Py_DECREF(v);
-	Py_DECREF(w);
-  error3:
-	Py_DECREF(oldv);
-	return res;
+	else {
+		return ternary_op(v, w, z, NB_SLOT(nb_power), "**=");
+	}
 }