[Python-checkins] CVS: python/dist/src/Objects typeobject.c,2.32,2.33
Guido van Rossum
gvanrossum@users.sourceforge.net
Wed, 15 Aug 2001 16:57:05 -0700
Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv27196
Modified Files:
typeobject.c
Log Message:
- Another big step in the right direction. All the overridable
operators for which a default implementation exist now work, both in
dynamic classes and in static classes, overridden or not. This
affects __repr__, __str__, __hash__, __contains__, __nonzero__,
__cmp__, and the rich comparisons (__lt__ etc.). For dynamic
classes, this meant copying a lot of code from classobject! (XXX
There are still some holes, because the comparison code in object.c
uses PyInstance_Check(), meaning new-style classes don't get the
same dispensation. This needs more thinking.)
- Add object.__hash__, object.__repr__, object.__str__. The __str__
dispatcher now calls the __repr__ dispatcher, as it should.
- For static classes, the tp_compare, tp_richcompare and tp_hash slots
are now inherited together, or not at all. (XXX I fear there are
still some situations where you can inherit __hash__ when you
shouldn't, but mostly it's OK now, and I think there's no way we can
get that 100% right.)
Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.32
retrieving revision 2.33
diff -C2 -d -r2.32 -r2.33
*** typeobject.c 2001/08/14 20:04:48 2.32
--- typeobject.c 2001/08/15 23:57:02 2.33
***************
*** 852,857 ****
}
- #if 0
- /* XXX These should be made smarter before they can be used */
static PyObject *
object_repr(PyObject *self)
--- 852,855 ----
***************
*** 863,866 ****
--- 861,875 ----
}
+ static PyObject *
+ object_str(PyObject *self)
+ {
+ unaryfunc f;
+
+ f = self->ob_type->tp_repr;
+ if (f == NULL)
+ f = object_repr;
+ return f(self);
+ }
+
static long
object_hash(PyObject *self)
***************
*** 868,872 ****
return _Py_HashPointer(self);
}
- #endif
static void
--- 877,880 ----
***************
*** 892,902 ****
0, /* tp_setattr */
0, /* tp_compare */
! 0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
! 0, /* tp_hash */
0, /* tp_call */
! 0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
PyObject_GenericSetAttr, /* tp_setattro */
--- 900,910 ----
0, /* tp_setattr */
0, /* tp_compare */
! object_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
! object_hash, /* tp_hash */
0, /* tp_call */
! object_str, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
PyObject_GenericSetAttr, /* tp_setattro */
***************
*** 1164,1175 ****
/* tp_compare see tp_richcompare */
COPYSLOT(tp_repr);
! COPYSLOT(tp_hash);
COPYSLOT(tp_call);
COPYSLOT(tp_str);
COPYSLOT(tp_as_buffer);
if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE) {
! if (type->tp_compare == NULL && type->tp_richcompare == NULL) {
type->tp_compare = base->tp_compare;
type->tp_richcompare = base->tp_richcompare;
}
}
--- 1172,1187 ----
/* tp_compare see tp_richcompare */
COPYSLOT(tp_repr);
! /* tp_hash see tp_richcompare */
COPYSLOT(tp_call);
COPYSLOT(tp_str);
COPYSLOT(tp_as_buffer);
if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE) {
! if (type->tp_compare == NULL &&
! type->tp_richcompare == NULL &&
! type->tp_hash == NULL)
! {
type->tp_compare = base->tp_compare;
type->tp_richcompare = base->tp_richcompare;
+ type->tp_hash = base->tp_hash;
}
}
***************
*** 2194,2205 ****
slot_sq_contains(PyObject *self, PyObject *value)
{
! PyObject *res = PyObject_CallMethod(self, "__contains__", "O", value);
! int r;
! if (res == NULL)
! return -1;
! r = PyInt_AsLong(res);
! Py_DECREF(res);
! return r;
}
--- 2206,2230 ----
slot_sq_contains(PyObject *self, PyObject *value)
{
! PyObject *func, *res, *args;
! func = PyObject_GetAttrString(self, "__contains__");
!
! if (func != NULL) {
! args = Py_BuildValue("(O)", value);
! if (args == NULL)
! res = NULL;
! else {
! res = PyEval_CallObject(func, args);
! Py_DECREF(args);
! }
! Py_DECREF(func);
! if (res == NULL)
! return -1;
! return PyObject_IsTrue(res);
! }
! else {
! PyErr_Clear();
! return _PySequence_IterContains(self, value);
! }
}
***************
*** 2255,2265 ****
slot_nb_nonzero(PyObject *self)
{
! /* XXX This should cope with a missing __nonzero__ */
! /* XXX Should it also look for __len__? */
! PyObject *res = PyObject_CallMethod(self, "__nonzero__", "");
! if (res == NULL)
! return -1;
! return (int)PyInt_AsLong(res);
}
--- 2280,2302 ----
slot_nb_nonzero(PyObject *self)
{
! PyObject *func, *res;
! func = PyObject_GetAttrString(self, "__nonzero__");
! if (func == NULL) {
! PyErr_Clear();
! func = PyObject_GetAttrString(self, "__len__");
! }
!
! if (func != NULL) {
! res = PyEval_CallObject(func, NULL);
! Py_DECREF(func);
! if (res == NULL)
! return -1;
! return PyObject_IsTrue(res);
! }
! else {
! PyErr_Clear();
! return 1;
! }
}
***************
*** 2294,2323 ****
static int
slot_tp_compare(PyObject *self, PyObject *other)
{
! /* XXX Should this cope with a missing __cmp__? */
! PyObject *res = PyObject_CallMethod(self, "__cmp__", "O", other);
! long r;
! if (res == NULL)
! return -1;
! r = PyInt_AsLong(res);
! Py_DECREF(res);
! return (int)r;
}
! /* XXX This should cope with a missing __repr__, and also look for __str__ */
! SLOT0(slot_tp_repr, "__repr__")
static long
slot_tp_hash(PyObject *self)
{
! /* XXX This should cope with a missing __hash__ */
! PyObject *res = PyObject_CallMethod(self, "__hash__", "");
long h;
! if (res == NULL)
! return -1;
! h = PyInt_AsLong(res);
if (h == -1 && !PyErr_Occurred())
h = -2;
--- 2331,2453 ----
static int
+ half_compare(PyObject *self, PyObject *other)
+ {
+ PyObject *func, *args, *res;
+ int c;
+
+ func = PyObject_GetAttrString(self, "__cmp__");
+ if (func == NULL) {
+ PyErr_Clear();
+ }
+ else {
+ args = Py_BuildValue("(O)", other);
+ if (args == NULL)
+ res = NULL;
+ else {
+ res = PyObject_CallObject(func, args);
+ Py_DECREF(args);
+ }
+ if (res != Py_NotImplemented) {
+ if (res == NULL)
+ return -2;
+ c = PyInt_AsLong(res);
+ Py_DECREF(res);
+ if (c == -1 && PyErr_Occurred())
+ return -2;
+ return (c < 0) ? -1 : (c > 0) ? 1 : 0;
+ }
+ Py_DECREF(res);
+ }
+ return 2;
+ }
+
+ static int
slot_tp_compare(PyObject *self, PyObject *other)
{
! int c;
! if (self->ob_type->tp_compare == slot_tp_compare) {
! c = half_compare(self, other);
! if (c <= 1)
! return c;
! }
! if (other->ob_type->tp_compare == slot_tp_compare) {
! c = half_compare(other, self);
! if (c < -1)
! return -2;
! if (c <= 1)
! return -c;
! }
! return (void *)self < (void *)other ? -1 :
! (void *)self > (void *)other ? 1 : 0;
}
! static PyObject *
! slot_tp_repr(PyObject *self)
! {
! PyObject *func, *res;
!
! func = PyObject_GetAttrString(self, "__repr__");
! if (func != NULL) {
! res = PyEval_CallObject(func, NULL);
! Py_DECREF(func);
! return res;
! }
! else {
! char buf[120];
! PyErr_Clear();
! sprintf(buf, "<%.80s object at %p>",
! self->ob_type->tp_name, self);
! return PyString_FromString(buf);
! }
! }
!
! static PyObject *
! slot_tp_str(PyObject *self)
! {
! PyObject *func, *res;
!
! func = PyObject_GetAttrString(self, "__str__");
! if (func != NULL) {
! res = PyEval_CallObject(func, NULL);
! Py_DECREF(func);
! return res;
! }
! else {
! PyErr_Clear();
! return slot_tp_repr(self);
! }
! }
static long
slot_tp_hash(PyObject *self)
{
! PyObject *func, *res;
long h;
! func = PyObject_GetAttrString(self, "__hash__");
!
! if (func != NULL) {
! res = PyEval_CallObject(func, NULL);
! Py_DECREF(func);
! if (res == NULL)
! return -1;
! h = PyInt_AsLong(res);
! }
! else {
! PyErr_Clear();
! func = PyObject_GetAttrString(self, "__eq__");
! if (func == NULL) {
! PyErr_Clear();
! func = PyObject_GetAttrString(self, "__cmp__");
! }
! if (func != NULL) {
! Py_DECREF(func);
! PyErr_SetString(PyExc_TypeError, "unhashable type");
! return -1;
! }
! PyErr_Clear();
! h = _Py_HashPointer((void *)self);
! }
if (h == -1 && !PyErr_Occurred())
h = -2;
***************
*** 2338,2344 ****
}
- /* XXX This should cope with a missing __str__, and also look for __repr__ */
- SLOT0(slot_tp_str, "__str__")
-
static PyObject *
slot_tp_getattro(PyObject *self, PyObject *name)
--- 2468,2471 ----
***************
*** 2386,2403 ****
static PyObject *
slot_tp_richcompare(PyObject *self, PyObject *other, int op)
{
- /* XXX How should this cope with missing __xx__? */
- PyObject *meth = PyObject_GetAttrString(self, name_op[op]);
PyObject *res;
! if (meth == NULL)
! return NULL;
! res = PyObject_CallFunction(meth, "O", other);
! Py_DECREF(meth);
! return res;
}
! SLOT0(slot_tp_iter, "__iter__")
static PyObject *
--- 2513,2582 ----
static PyObject *
+ half_richcompare(PyObject *self, PyObject *other, int op)
+ {
+ PyObject *func, *args, *res;
+
+ func = PyObject_GetAttrString(self, name_op[op]);
+ if (func == NULL) {
+ PyErr_Clear();
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ args = Py_BuildValue("(O)", other);
+ if (args == NULL)
+ res = NULL;
+ else {
+ res = PyObject_CallObject(func, args);
+ Py_DECREF(args);
+ }
+ Py_DECREF(func);
+ return res;
+ }
+
+ /* Map rich comparison operators to their swapped version, e.g. LT --> GT */
+ static int swapped_op[] = {Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE};
+
+ static PyObject *
slot_tp_richcompare(PyObject *self, PyObject *other, int op)
{
PyObject *res;
! if (self->ob_type->tp_richcompare == slot_tp_richcompare) {
! res = half_richcompare(self, other, op);
! if (res != Py_NotImplemented)
! return res;
! Py_DECREF(res);
! }
! if (other->ob_type->tp_richcompare == slot_tp_richcompare) {
! res = half_richcompare(other, self, swapped_op[op]);
! if (res != Py_NotImplemented) {
! return res;
! }
! Py_DECREF(res);
! }
! Py_INCREF(Py_NotImplemented);
! return Py_NotImplemented;
}
! static PyObject *
! slot_tp_iter(PyObject *self)
! {
! PyObject *func, *res;
!
! func = PyObject_GetAttrString(self, "__iter__");
! if (func != NULL) {
! res = PyObject_CallObject(func, NULL);
! Py_DECREF(func);
! return res;
! }
! PyErr_Clear();
! func = PyObject_GetAttrString(self, "__getitem__");
! if (func == NULL) {
! PyErr_SetString(PyExc_TypeError, "iter() of non-sequence");
! return NULL;
! }
! Py_DECREF(func);
! return PySeqIter_New(self);
! }
static PyObject *