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