[Python-checkins] cpython (merge 3.4 -> 3.5): Issue #4395: Better testing and documentation of binary operators.

robert.collins python-checkins at python.org
Fri Aug 7 00:34:50 CEST 2015


https://hg.python.org/cpython/rev/b9a0165a3de8
changeset:   97312:b9a0165a3de8
branch:      3.5
parent:      97309:2752fe734bfb
parent:      97311:f5069e6e4229
user:        Robert Collins <rbtcollins at hp.com>
date:        Fri Aug 07 10:32:15 2015 +1200
summary:
  Issue #4395: Better testing and documentation of binary operators.

Patch by Martin Panter.

files:
  Doc/reference/datamodel.rst |  22 +++++++++++++---------
  Lib/test/test_binop.py      |  22 +++++++++++++++++++++-
  Misc/NEWS                   |   3 +++
  3 files changed, 37 insertions(+), 10 deletions(-)


diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -1276,10 +1276,14 @@
    context (e.g., in the condition of an ``if`` statement), Python will call
    :func:`bool` on the value to determine if the result is true or false.
 
-   There are no implied relationships among the comparison operators. The truth
-   of ``x==y`` does not imply that ``x!=y`` is false.  Accordingly, when
-   defining :meth:`__eq__`, one should also define :meth:`__ne__` so that the
-   operators will behave as expected.  See the paragraph on :meth:`__hash__` for
+   By default, :meth:`__ne__` delegates to :meth:`__eq__` and
+   inverts the result unless it is ``NotImplemented``.  There are no other
+   implied relationships among the comparison operators, for example,
+   the truth of ``(x<y or x==y)`` does not imply ``x<=y``.
+   To automatically generate ordering operations from a single root operation,
+   see :func:`functools.total_ordering`.
+
+   See the paragraph on :meth:`__hash__` for
    some important notes on creating :term:`hashable` objects which support
    custom comparison operations and are usable as dictionary keys.
 
@@ -1288,11 +1292,11 @@
    rather, :meth:`__lt__` and :meth:`__gt__` are each other's reflection,
    :meth:`__le__` and :meth:`__ge__` are each other's reflection, and
    :meth:`__eq__` and :meth:`__ne__` are their own reflection.
-
-   Arguments to rich comparison methods are never coerced.
-
-   To automatically generate ordering operations from a single root operation,
-   see :func:`functools.total_ordering`.
+   If the operands are of different types, and right operand's type is
+   a direct or indirect subclass of the left operand's type,
+   the reflected method of the right operand has priority, otherwise
+   the left operand's method has priority.  Virtual subclassing is
+   not considered.
 
 .. method:: object.__hash__(self)
 
diff --git a/Lib/test/test_binop.py b/Lib/test/test_binop.py
--- a/Lib/test/test_binop.py
+++ b/Lib/test/test_binop.py
@@ -3,6 +3,7 @@
 import unittest
 from test import support
 from operator import eq, ne, lt, gt, le, ge
+from abc import ABCMeta
 
 def gcd(a, b):
     """Greatest common divisor using Euclid's algorithm."""
@@ -332,7 +333,7 @@
         self.log_operation('A.__ge__')
         return NotImplemented
 
-class B(OperationLogger):
+class B(OperationLogger, metaclass=ABCMeta):
     def __eq__(self, other):
         self.log_operation('B.__eq__')
         return NotImplemented
@@ -354,6 +355,20 @@
         self.log_operation('C.__ge__')
         return NotImplemented
 
+class V(OperationLogger):
+    """Virtual subclass of B"""
+    def __eq__(self, other):
+        self.log_operation('V.__eq__')
+        return NotImplemented
+    def __le__(self, other):
+        self.log_operation('V.__le__')
+        return NotImplemented
+    def __ge__(self, other):
+        self.log_operation('V.__ge__')
+        return NotImplemented
+B.register(V)
+
+
 class OperationOrderTests(unittest.TestCase):
     def test_comparison_orders(self):
         self.assertEqual(op_sequence(eq, A, A), ['A.__eq__', 'A.__eq__'])
@@ -369,5 +384,10 @@
         self.assertEqual(op_sequence(le, B, C), ['C.__ge__', 'B.__le__'])
         self.assertEqual(op_sequence(le, C, B), ['C.__le__', 'B.__ge__'])
 
+        self.assertTrue(issubclass(V, B))
+        self.assertEqual(op_sequence(eq, B, V), ['B.__eq__', 'V.__eq__'])
+        self.assertEqual(op_sequence(le, B, V), ['B.__le__', 'V.__ge__'])
+
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -13,6 +13,9 @@
 Library
 -------
 
+- Issue #4395: Better testing and documentation of binary operators.
+  Patch by Martin Panter.
+
 - Issue #23973: Update typing.py from GitHub repo.
 
 - Issue #23004: mock_open() now reads binary data correctly when the type of

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list