[Python-checkins] CVS: python/nondist/peps pep-0207.txt,1.8,1.9
Guido van Rossum
gvanrossum@users.sourceforge.net
Fri, 19 Jan 2001 14:29:21 -0800
Update of /cvsroot/python/python/nondist/peps
In directory usw-pr-cvs1:/tmp/cvs-serv15427
Modified Files:
pep-0207.txt
Log Message:
Finalized this PEP. Closed all unresolved issues.
Index: pep-0207.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/peps/pep-0207.txt,v
retrieving revision 1.8
retrieving revision 1.9
diff -C2 -r1.8 -r1.9
*** pep-0207.txt 2000/12/06 21:22:52 1.8
--- pep-0207.txt 2001/01/19 22:29:19 1.9
***************
*** 4,8 ****
Author: guido@python.org (Guido van Rossum), DavidA@ActiveState.com (David Ascher)
Python-Version: 2.1
! Status: Incomplete
--- 4,8 ----
Author: guido@python.org (Guido van Rossum), DavidA@ActiveState.com (David Ascher)
Python-Version: 2.1
! Status: Final
***************
*** 30,35 ****
an arbitrary ordering, just so that equality can be tested.
! More motivation can be found in the proposals listed under
! previous work below.
--- 30,37 ----
an arbitrary ordering, just so that equality can be tested.
! Also, for some object types an equality test can be implemented
! much more efficiently than an ordering test; for example, lists
! and dictionaries that differ in length are unequal, but the
! ordering requires inspecting some (potentially all) items.
***************
*** 77,95 ****
1 Full backwards compatibility can be achieved as follows. When
! an object defines tp_compare() but not tp_richcmp(), and a rich
! comparison is requested, the outcome of tp_compare() is used in
! the ovious way. E.g. if "<" is requested, an exception if
tp_compare() raises an exception, the outcome is 1 if
tp_compare() is negative, and 0 if it is zero or positive. Etc.
! Full forward compatibility can be achieved as follows. (This is
! a bit arbitrary.) When a classic comparison is requested on an
! object that only implements tp_richcmp(), up to three
! comparisons are used: first == is tried, and if it returns true,
! 0 is returned; next, < is tried and if it returns true, -1 is
! returned; next, > is tried and if it returns true, +1 is
! returned. Finally, TypeError("incomparable objects") exception
! is raised. If any operator tried returns a non-Boolean value
! (see below), the exception is passed through.
2 Any type that returns a collection of Booleans instead of a
--- 79,105 ----
1 Full backwards compatibility can be achieved as follows. When
! an object defines tp_compare() but not tp_richcompare(), and a
! rich comparison is requested, the outcome of tp_compare() is
! used in the ovious way. E.g. if "<" is requested, an exception if
tp_compare() raises an exception, the outcome is 1 if
tp_compare() is negative, and 0 if it is zero or positive. Etc.
! Full forward compatibility can be achieved as follows. When a
! classic comparison is requested on an object that implements
! tp_richcompare(), up to three comparisons are used: first == is
! tried, and if it returns true, 0 is returned; next, < is tried
! and if it returns true, -1 is returned; next, > is tried and if
! it returns true, +1 is returned. If any operator tried returns
! a non-Boolean value (see below), the exception raised by
! conversion to Boolean is passed through. If none of the
! operators tried returns true, the classic comparison fallbacks
! are tried next.
!
! (I thought long and hard about the order in which the three
! comparisons should be tried. At one point I had a convincing
! argument for doing it in this order, based on the behavior of
! comparisons for cyclical data structures. But since that code
! has changed again, I'm not so sure that it makes a difference
! any more.)
2 Any type that returns a collection of Booleans instead of a
***************
*** 117,123 ****
(A<B)&(C<D).
! 6 The min(), max() and list.sort() operations will only use the
! < operator. The 'in' and 'not in' operators and dictionary
! lookup will only use the == operator.
--- 127,134 ----
(A<B)&(C<D).
! 6 The min() and list.sort() operations will only use the
! < operator; max() will only use the > operator. The 'in' and
! 'not in' operators and dictionary lookup will only use the ==
! operator.
***************
*** 128,132 ****
C API
! - New function:
PyObject *PyObject_RichCompare(PyObject *, PyObject *, enum cmp_op)
--- 139,143 ----
C API
! - New functions:
PyObject *PyObject_RichCompare(PyObject *, PyObject *, enum cmp_op)
***************
*** 134,139 ****
This performs the requested rich comparison, returning a Python
object or raising an exception. The 3rd argument must be one of
! LT, LE, EQ, NE, GT or GE.
- New typedef:
--- 145,159 ----
This performs the requested rich comparison, returning a Python
object or raising an exception. The 3rd argument must be one of
! Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT or Py_GE.
+ int PyObject_RichCompareBool(PyObject *, PyObject *, enum cmp_op)
+
+ This performs the requested rich comparison, returning a
+ Boolean: -1 for exception, 0 for false, 1 for true. The 3rd
+ argument must be one of Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT or
+ Py_GE. Note that when PyObject_RichCompare() returns a
+ non-Boolean object, PyObject_RichCompareBool() will raise an
+ exception.
+
- New typedef:
***************
*** 144,147 ****
--- 164,174 ----
richcmpfunc tp_richcompare;
+ This should be a function with the same signature as
+ PyObject_RichCompare(), and performing the same comparison.
+ At least one of the arguments is of the type whose
+ tp_richcompare slot is being used, but the other may have a
+ different type. If the function cannot compare the particular
+ combination of objects, it should return PyExc_NotImplemented.
+
- PyObject_Compare() is changed to try rich comparisons if they
are defined (but only if classic comparisons aren't defined).
***************
*** 152,219 ****
the outcome of a particular comparison (e.g. in list.sort(), and
of course for the comparison operators in ceval.c), the code is
! changed to call PyObject_RichCompare() instead; if the C code
! needs to know the outcome of the comparison, PyObject_IsTrue()
! is called on the result (which may raise an exception).
! - All built-in types that currently define a comparison will be
modified to define a rich comparison instead. (This is
! optional!)
Classes
-
- - Classes can define new special methods __lt__, __le__, __gt__,
- __ge__, __eq__, __ne__ to override the corresponding operators.
- (You gotta love the Fortran heritage.) If a class overrides
- __cmp__ as well, it is only used by PyObject_Compare().
-
-
- Unresolved Issues
-
- - David Ascher's proposal also introduces cmp(a, b, op) where op
- is one of "<", "<=", ">", ">=", "==", "!=", which should return
- the same as a <op> b. Is this necessary?
-
- - The rules for mixed comparisons are confusing. I propose to
- wait until the new coercion mechanism is in place, and use the
- new coercion rules for mixed comparisons. This may occasionally
- cause x<y to be replaced by y>x, if x doesn't implement
- comparison to y, but y does implement comparison to x.
-
- - With the above design, if a type or class defines both classic
- and rich comparisons, classic comparisons override rich
- comparisons when PyObject_Compare() is called, but rich
- comparisons override when PyObject_RichCompare() is called. Is
- this right? Or should rich comparisons always win except when
- cmp() is called?
-
- - Should we even bother upgrading the existing types?
-
- - If so, how should comparisons on container types be defined?
- Suppose we have a list whose items define rich comparisons. How
- should the itemwise comparisons be done? For example:
-
- def __lt__(a, b): # a<b for lists
- for i in range(min(len(a), len(b))):
- ai, bi = a[i], b[i]
- if ai < bi: return 1
- if ai == bi: continue
- if ai > bi: return 0
- raise TypeError, "incomparable item types"
- return len(a) < len(b)
-
- This uses the same sequence of comparisons as cmp(), so it may
- as well use cmp() instead:
-
- def __lt__(a, b): # a<b for lists
- for i in range(min(len(a), len(b))):
- c = cmp(a[i], b[i])
- if c < 0: return 1
- if c == 0: continue
- if c > 0: return 0
- assert 0 # unreachable
- return len(a) < len(b)
! And now there's not really a reason to change lists to rich
! comparisons.
--- 179,199 ----
the outcome of a particular comparison (e.g. in list.sort(), and
of course for the comparison operators in ceval.c), the code is
! changed to call PyObject_RichCompare() or
! PyObject_RichCompareBool() instead; if the C code needs to know
! the outcome of the comparison, PyObject_IsTrue() is called on
! the result (which may raise an exception).
! - Most built-in types that currently define a comparison will be
modified to define a rich comparison instead. (This is
! optional; I've converted lists, tuples, complex numbers, and
! arrays so far, and am not sure whether I will convert others.)
Classes
! - Classes can define new special methods __lt__, __le__, __eq__,
! __ne__,__gt__, __ge__ to override the corresponding operators.
! (I.e., <, <=, ==, !=, >, >=. You gotta love the Fortran
! heritage.) If a class defines __cmp__ as well, it is only used
! when __lt__ etc. have been tried and return NotImplemented.