Make instances a new style number type. See PEP 208 for details. Instance

types no longer get special treatment from abstract.c so more number number
methods have to be implemented.
This commit is contained in:
Neil Schemenauer 2001-01-04 01:43:46 +00:00
parent 5a1f015bee
commit 29bfc07183

View file

@ -4,6 +4,7 @@
#include "Python.h" #include "Python.h"
#include "structmember.h" #include "structmember.h"
/* Forward */ /* Forward */
static PyObject *class_lookup(PyClassObject *, PyObject *, static PyObject *class_lookup(PyClassObject *, PyObject *,
PyClassObject **); PyClassObject **);
@ -755,36 +756,6 @@ instance_repr(PyInstanceObject *inst)
return res; return res;
} }
static PyObject *
instance_compare1(PyObject *inst, PyObject *other)
{
return PyInstance_DoBinOp(inst, other, "__cmp__", "__rcmp__",
instance_compare1);
}
static int
instance_compare(PyObject *inst, PyObject *other)
{
PyObject *result;
long outcome;
result = instance_compare1(inst, other);
if (result == NULL)
return -1;
if (!PyInt_Check(result)) {
Py_DECREF(result);
PyErr_SetString(PyExc_TypeError,
"comparison did not return an int");
return -1;
}
outcome = PyInt_AsLong(result);
Py_DECREF(result);
if (outcome < 0)
return -1;
else if (outcome > 0)
return 1;
return 0;
}
static long static long
instance_hash(PyInstanceObject *inst) instance_hash(PyInstanceObject *inst)
{ {
@ -1185,117 +1156,119 @@ generic_unary_op(PyInstanceObject *self, PyObject *methodname)
return res; return res;
} }
static PyObject *
/* Implement a binary operator involving at least one class instance. */ generic_binary_op(PyObject *v, PyObject *w, char *opname)
PyObject *
PyInstance_DoBinOp(PyObject *v, PyObject *w, char *opname, char *ropname,
PyObject * (*thisfunc)(PyObject *, PyObject *))
{ {
char buf[256]; PyObject *result;
PyObject *result = NULL; PyObject *args;
PyObject *func = PyObject_GetAttrString(v, opname);
if (PyInstance_HalfBinOp(v, w, opname, &result, thisfunc, 0) <= 0) if (func == NULL) {
return result; if (!PyErr_ExceptionMatches(PyExc_AttributeError))
if (PyInstance_HalfBinOp(w, v, ropname, &result, thisfunc, 1) <= 0) return NULL;
return result; PyErr_Clear();
/* Sigh -- special case for comparisons */ Py_INCREF(Py_NotImplemented);
if (strcmp(opname, "__cmp__") == 0) { return Py_NotImplemented;
Py_uintptr_t iv = (Py_uintptr_t)v;
Py_uintptr_t iw = (Py_uintptr_t)w;
long c = (iv < iw) ? -1 : (iv > iw) ? 1 : 0;
return PyInt_FromLong(c);
} }
sprintf(buf, "%s nor %s defined for these operands", opname, ropname); args = Py_BuildValue("(O)", w);
PyErr_SetString(PyExc_TypeError, buf); if (args == NULL) {
Py_DECREF(func);
return NULL; return NULL;
} }
result = PyEval_CallObject(func, args);
Py_DECREF(args);
Py_DECREF(func);
return result;
}
/* Try one half of a binary operator involving a class instance.
Return value:
-1 if an exception is to be reported right away
0 if we have a valid result
1 if we could try another operation
*/
static PyObject *coerce_obj; static PyObject *coerce_obj;
int /* Try one half of a binary operator involving a class instance. */
PyInstance_HalfBinOp(PyObject *v, PyObject *w, char *opname, PyObject **r_result, static PyObject *
PyObject * (*thisfunc)(PyObject *, PyObject *), int swapped) half_binop(PyObject *v, PyObject *w, char *opname, binaryfunc thisfunc,
int swapped)
{ {
PyObject *func;
PyObject *args; PyObject *args;
PyObject *coercefunc; PyObject *coercefunc;
PyObject *coerced = NULL; PyObject *coerced = NULL;
PyObject *v1; PyObject *v1;
PyObject *result;
if (!PyInstance_Check(v)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
if (!PyInstance_Check(v))
return 1;
if (coerce_obj == NULL) { if (coerce_obj == NULL) {
coerce_obj = PyString_InternFromString("__coerce__"); coerce_obj = PyString_InternFromString("__coerce__");
if (coerce_obj == NULL) if (coerce_obj == NULL)
return -1; return NULL;
} }
coercefunc = PyObject_GetAttr(v, coerce_obj); coercefunc = PyObject_GetAttr(v, coerce_obj);
if (coercefunc == NULL) { if (coercefunc == NULL) {
PyErr_Clear(); PyErr_Clear();
return generic_binary_op(v, w, opname);
} }
else {
args = Py_BuildValue("(O)", w); args = Py_BuildValue("(O)", w);
if (args == NULL) { if (args == NULL) {
return -1; return NULL;
} }
coerced = PyEval_CallObject(coercefunc, args); coerced = PyEval_CallObject(coercefunc, args);
Py_DECREF(args); Py_DECREF(args);
Py_DECREF(coercefunc); Py_DECREF(coercefunc);
if (coerced == NULL) { if (coerced == NULL) {
return -1; return NULL;
} }
if (coerced == Py_None) { if (coerced == Py_None || coerced == Py_NotImplemented) {
Py_DECREF(coerced); Py_DECREF(coerced);
return 1; return generic_binary_op(v, w, opname);
} }
if (!PyTuple_Check(coerced) || PyTuple_Size(coerced) != 2) { if (!PyTuple_Check(coerced) || PyTuple_Size(coerced) != 2) {
Py_DECREF(coerced); Py_DECREF(coerced);
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"coercion should return None or 2-tuple"); "coercion should return None or 2-tuple");
return -1; return NULL;
} }
v1 = PyTuple_GetItem(coerced, 0); v1 = PyTuple_GetItem(coerced, 0);
w = PyTuple_GetItem(coerced, 1); w = PyTuple_GetItem(coerced, 1);
if (v1 != v) { if (v1 == v) {
v = v1; /* prevent recursion if __coerce__ returns self as the first
if (!PyInstance_Check(v) && !PyInstance_Check(w)) { * argument */
result = generic_binary_op(v, w, opname);
} else {
if (swapped) if (swapped)
*r_result = (*thisfunc)(w, v); result = (thisfunc)(w, v1);
else else
*r_result = (*thisfunc)(v, w); result = (thisfunc)(v1, w);
}
Py_DECREF(coerced); Py_DECREF(coerced);
return *r_result == NULL ? -1 : 0; return result;
} }
/* Implement a binary operator involving at least one class instance. */
static PyObject *
do_binop(PyObject *v, PyObject *w, char *opname, char *ropname,
binaryfunc thisfunc)
{
PyObject *result = half_binop(v, w, opname, thisfunc, 0);
if (result == Py_NotImplemented) {
Py_DECREF(Py_NotImplemented);
result = half_binop(w, v, ropname, thisfunc, 1);
} }
return result;
} }
func = PyObject_GetAttrString(v, opname);
if (func == NULL) { static PyObject *
Py_XDECREF(coerced); do_binop_inplace(PyObject *v, PyObject *w, char *iopname, char *opname,
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) char *ropname, binaryfunc thisfunc)
return -1; {
PyErr_Clear(); PyObject *result = half_binop(v, w, iopname, thisfunc, 0);
return 1; if (result == Py_NotImplemented) {
Py_DECREF(Py_NotImplemented);
result = do_binop(v, w, opname, ropname, thisfunc);
} }
args = Py_BuildValue("(O)", w); return result;
if (args == NULL) {
Py_DECREF(func);
Py_XDECREF(coerced);
return -1;
}
*r_result = PyEval_CallObject(func, args);
Py_DECREF(args);
Py_DECREF(func);
Py_XDECREF(coerced);
return *r_result == NULL ? -1 : 0;
} }
static int static int
@ -1314,11 +1287,11 @@ instance_coerce(PyObject **pv, PyObject **pw)
} }
coercefunc = PyObject_GetAttr(v, coerce_obj); coercefunc = PyObject_GetAttr(v, coerce_obj);
if (coercefunc == NULL) { if (coercefunc == NULL) {
/* No __coerce__ method: always OK */ /* No __coerce__ method */
PyErr_Clear(); PyErr_Clear();
Py_INCREF(v); Py_INCREF(v);
Py_INCREF(w); Py_INCREF(w);
return 0; return 1;
} }
/* Has __coerce__ method: call it */ /* Has __coerce__ method: call it */
args = Py_BuildValue("(O)", w); args = Py_BuildValue("(O)", w);
@ -1332,7 +1305,7 @@ instance_coerce(PyObject **pv, PyObject **pw)
/* __coerce__ call raised an exception */ /* __coerce__ call raised an exception */
return -1; return -1;
} }
if (coerced == Py_None) { if (coerced == Py_None || coerced == Py_NotImplemented) {
/* __coerce__ says "I can't do it" */ /* __coerce__ says "I can't do it" */
Py_DECREF(coerced); Py_DECREF(coerced);
return 1; return 1;
@ -1353,7 +1326,6 @@ instance_coerce(PyObject **pv, PyObject **pw)
return 0; return 0;
} }
#define UNARY(funcname, methodname) \ #define UNARY(funcname, methodname) \
static PyObject *funcname(PyInstanceObject *self) { \ static PyObject *funcname(PyInstanceObject *self) { \
static PyObject *o; \ static PyObject *o; \
@ -1361,10 +1333,102 @@ static PyObject *funcname(PyInstanceObject *self) { \
return generic_unary_op(self, o); \ return generic_unary_op(self, o); \
} }
#define BINARY(f, m, n) \
static PyObject *f(PyObject *v, PyObject *w) { \
return do_binop(v, w, "__" m "__", "__r" m "__", n); \
}
#define BINARY_INPLACE(f, m, n) \
static PyObject *f(PyObject *v, PyObject *w) { \
return do_binop_inplace(v, w, "__i" m "__", "__" m "__", \
"__r" m "__", n); \
}
UNARY(instance_neg, "__neg__") UNARY(instance_neg, "__neg__")
UNARY(instance_pos, "__pos__") UNARY(instance_pos, "__pos__")
UNARY(instance_abs, "__abs__") UNARY(instance_abs, "__abs__")
BINARY(instance_or, "or", PyNumber_Or)
BINARY(instance_and, "and", PyNumber_And)
BINARY(instance_xor, "xor", PyNumber_Xor)
BINARY(instance_lshift, "lshift", PyNumber_Lshift)
BINARY(instance_rshift, "rshift", PyNumber_Rshift)
BINARY(instance_add, "add", PyNumber_Add)
BINARY(instance_sub, "sub", PyNumber_Subtract)
BINARY(instance_mul, "mul", PyNumber_Multiply)
BINARY(instance_div, "div", PyNumber_Divide)
BINARY(instance_mod, "mod", PyNumber_Remainder)
BINARY(instance_divmod, "divmod", PyNumber_Divmod)
BINARY_INPLACE(instance_ior, "or", PyNumber_InPlaceOr)
BINARY_INPLACE(instance_ixor, "xor", PyNumber_InPlaceXor)
BINARY_INPLACE(instance_iand, "and", PyNumber_InPlaceAnd)
BINARY_INPLACE(instance_ilshift, "lshift", PyNumber_InPlaceLshift)
BINARY_INPLACE(instance_irshift, "rshift", PyNumber_InPlaceRshift)
BINARY_INPLACE(instance_iadd, "add", PyNumber_InPlaceAdd)
BINARY_INPLACE(instance_isub, "sub", PyNumber_InPlaceSubtract)
BINARY_INPLACE(instance_imul, "mul", PyNumber_InPlaceMultiply)
BINARY_INPLACE(instance_idiv, "div", PyNumber_InPlaceDivide)
BINARY_INPLACE(instance_imod, "mod", PyNumber_InPlaceRemainder)
static PyObject *
do_cmp(PyObject *v, PyObject *w)
{
int cmp = PyObject_Compare(v, w);
if (PyErr_Occurred()) {
return NULL;
}
return PyInt_FromLong(cmp);
}
static PyObject *
instance_cmp(PyObject *v, PyObject *w)
{
PyObject *result = half_binop(v, w, "__cmp__", do_cmp, 0);
if (result == Py_NotImplemented) {
Py_DECREF(Py_NotImplemented);
/* __rcmp__ is not called on instances, instead they
* automaticly reverse the arguments and return the negative of
* __cmp__ if it exists */
result = half_binop(w, v, "__cmp__", do_cmp, 0);
if (result != Py_NotImplemented && result != NULL) {
PyObject *r = PyNumber_Negative(result);
Py_DECREF(result);
result = r;
}
}
return result;
}
static int
instance_compare(PyObject *inst, PyObject *other)
{
PyObject *result;
long outcome;
result = instance_cmp(inst, other);
if (result == NULL) {
return -1;
}
if (result == Py_NotImplemented) {
Py_DECREF(result);
return -1;
}
if (!PyInt_Check(result)) {
Py_DECREF(result);
PyErr_SetString(PyExc_TypeError,
"comparison did not return an int");
return -1;
}
outcome = PyInt_AsLong(result);
Py_DECREF(result);
if (outcome < 0)
return -1;
else if (outcome > 0)
return 1;
return 0;
}
static int static int
instance_nonzero(PyInstanceObject *self) instance_nonzero(PyInstanceObject *self)
{ {
@ -1412,19 +1476,26 @@ UNARY(instance_float, "__float__")
UNARY(instance_oct, "__oct__") UNARY(instance_oct, "__oct__")
UNARY(instance_hex, "__hex__") UNARY(instance_hex, "__hex__")
static PyObject *
bin_power(PyObject *v, PyObject *w)
{
return PyNumber_Power(v, w, Py_None);
}
/* This version is for ternary calls only (z != None) */ /* This version is for ternary calls only (z != None) */
static PyObject * static PyObject *
instance_pow(PyObject *v, PyObject *w, PyObject *z) instance_pow(PyObject *v, PyObject *w, PyObject *z)
{ {
/* XXX Doesn't do coercions... */ if (z == Py_None) {
return do_binop(v, w, "__pow__", "__rpow__", bin_power);
}
else {
PyObject *func; PyObject *func;
PyObject *args; PyObject *args;
PyObject *result; PyObject *result;
static PyObject *powstr;
if (powstr == NULL) /* XXX Doesn't do coercions... */
powstr = PyString_InternFromString("__pow__"); func = PyObject_GetAttrString(v, "__pow__");
func = PyObject_GetAttr(v, powstr);
if (func == NULL) if (func == NULL)
return NULL; return NULL;
args = Py_BuildValue("(OO)", w, z); args = Py_BuildValue("(OO)", w, z);
@ -1437,19 +1508,29 @@ instance_pow(PyObject *v, PyObject *w, PyObject *z)
Py_DECREF(args); Py_DECREF(args);
return result; return result;
} }
}
static PyObject * static PyObject *
instance_inplace_pow(PyObject *v, PyObject *w, PyObject *z) bin_inplace_power(PyObject *v, PyObject *w)
{ {
return PyNumber_InPlacePower(v, w, Py_None);
}
static PyObject *
instance_ipow(PyObject *v, PyObject *w, PyObject *z)
{
if (z == Py_None) {
return do_binop_inplace(v, w, "__ipow__", "__pow__",
"__rpow__", bin_inplace_power);
}
else {
/* XXX Doesn't do coercions... */ /* XXX Doesn't do coercions... */
PyObject *func; PyObject *func;
PyObject *args; PyObject *args;
PyObject *result; PyObject *result;
static PyObject *ipowstr;
if (ipowstr == NULL) func = PyObject_GetAttrString(v, "__ipow__");
ipowstr = PyString_InternFromString("__ipow__");
func = PyObject_GetAttr(v, ipowstr);
if (func == NULL) { if (func == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL; return NULL;
@ -1466,43 +1547,46 @@ instance_inplace_pow(PyObject *v, PyObject *w, PyObject *z)
Py_DECREF(args); Py_DECREF(args);
return result; return result;
} }
}
static PyNumberMethods instance_as_number = { static PyNumberMethods instance_as_number = {
0, /*nb_add*/ (binaryfunc)instance_add, /*nb_add*/
0, /*nb_subtract*/ (binaryfunc)instance_sub, /*nb_subtract*/
0, /*nb_multiply*/ (binaryfunc)instance_mul, /*nb_multiply*/
0, /*nb_divide*/ (binaryfunc)instance_div, /*nb_divide*/
0, /*nb_remainder*/ (binaryfunc)instance_mod, /*nb_remainder*/
0, /*nb_divmod*/ (binaryfunc)instance_divmod, /*nb_divmod*/
(ternaryfunc)instance_pow, /*nb_power*/ (ternaryfunc)instance_pow, /*nb_power*/
(unaryfunc)instance_neg, /*nb_negative*/ (unaryfunc)instance_neg, /*nb_negative*/
(unaryfunc)instance_pos, /*nb_positive*/ (unaryfunc)instance_pos, /*nb_positive*/
(unaryfunc)instance_abs, /*nb_absolute*/ (unaryfunc)instance_abs, /*nb_absolute*/
(inquiry)instance_nonzero, /*nb_nonzero*/ (inquiry)instance_nonzero, /*nb_nonzero*/
(unaryfunc)instance_invert, /*nb_invert*/ (unaryfunc)instance_invert, /*nb_invert*/
0, /*nb_lshift*/ (binaryfunc)instance_lshift, /*nb_lshift*/
0, /*nb_rshift*/ (binaryfunc)instance_rshift, /*nb_rshift*/
0, /*nb_and*/ (binaryfunc)instance_and, /*nb_and*/
0, /*nb_xor*/ (binaryfunc)instance_xor, /*nb_xor*/
0, /*nb_or*/ (binaryfunc)instance_or, /*nb_or*/
(coercion)instance_coerce, /*nb_coerce*/ (coercion)instance_coerce, /*nb_coerce*/
(unaryfunc)instance_int, /*nb_int*/ (unaryfunc)instance_int, /*nb_int*/
(unaryfunc)instance_long, /*nb_long*/ (unaryfunc)instance_long, /*nb_long*/
(unaryfunc)instance_float, /*nb_float*/ (unaryfunc)instance_float, /*nb_float*/
(unaryfunc)instance_oct, /*nb_oct*/ (unaryfunc)instance_oct, /*nb_oct*/
(unaryfunc)instance_hex, /*nb_hex*/ (unaryfunc)instance_hex, /*nb_hex*/
0, /*nb_inplace_add*/ (binaryfunc)instance_iadd, /*nb_inplace_add*/
0, /*nb_inplace_subtract*/ (binaryfunc)instance_isub, /*nb_inplace_subtract*/
0, /*nb_inplace_multiply*/ (binaryfunc)instance_imul, /*nb_inplace_multiply*/
0, /*nb_inplace_divide*/ (binaryfunc)instance_idiv, /*nb_inplace_divide*/
0, /*nb_inplace_remainder*/ (binaryfunc)instance_imod, /*nb_inplace_remainder*/
(ternaryfunc)instance_inplace_pow, /*nb_inplace_power*/ (ternaryfunc)instance_ipow, /*nb_inplace_power*/
0, /*nb_inplace_lshift*/ (binaryfunc)instance_ilshift, /*nb_inplace_lshift*/
0, /*nb_inplace_rshift*/ (binaryfunc)instance_irshift, /*nb_inplace_rshift*/
0, /*nb_inplace_and*/ (binaryfunc)instance_iand, /*nb_inplace_and*/
0, /*nb_inplace_xor*/ (binaryfunc)instance_ixor, /*nb_inplace_xor*/
0, /*nb_inplace_or*/ (binaryfunc)instance_ior, /*nb_inplace_or*/
(binaryfunc)instance_cmp, /*nb_cmp*/
}; };
PyTypeObject PyInstance_Type = { PyTypeObject PyInstance_Type = {
@ -1526,7 +1610,7 @@ PyTypeObject PyInstance_Type = {
(getattrofunc)instance_getattr, /*tp_getattro*/ (getattrofunc)instance_getattr, /*tp_getattro*/
(setattrofunc)instance_setattr, /*tp_setattro*/ (setattrofunc)instance_setattr, /*tp_setattro*/
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC | Py_TPFLAGS_NEWSTYLENUMBER, /*tp_flags*/
0, /* tp_doc */ 0, /* tp_doc */
(traverseproc)instance_traverse, /* tp_traverse */ (traverseproc)instance_traverse, /* tp_traverse */
}; };