mirror of https://github.com/python/cpython
bpo-20092. Use __index__ in constructors of int, float and complex. (GH-13108)
This commit is contained in:
parent
1a4d9ffa1a
commit
bdbad71b9d
|
@ -129,4 +129,10 @@ Complex Numbers as Python Objects
|
||||||
|
|
||||||
If *op* is not a Python complex number object but has a :meth:`__complex__`
|
If *op* is not a Python complex number object but has a :meth:`__complex__`
|
||||||
method, this method will first be called to convert *op* to a Python complex
|
method, this method will first be called to convert *op* to a Python complex
|
||||||
number object. Upon failure, this method returns ``-1.0`` as a real value.
|
number object. If ``__complex__()`` is not defined then it falls back to
|
||||||
|
:meth:`__float__`. If ``__float__()`` is not defined then it falls back
|
||||||
|
to :meth:`__index__`. Upon failure, this method returns ``-1.0`` as a real
|
||||||
|
value.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.8
|
||||||
|
Use :meth:`__index__` if available.
|
||||||
|
|
|
@ -47,9 +47,13 @@ Floating Point Objects
|
||||||
Return a C :c:type:`double` representation of the contents of *pyfloat*. If
|
Return a C :c:type:`double` representation of the contents of *pyfloat*. If
|
||||||
*pyfloat* is not a Python floating point object but has a :meth:`__float__`
|
*pyfloat* is not a Python floating point object but has a :meth:`__float__`
|
||||||
method, this method will first be called to convert *pyfloat* into a float.
|
method, this method will first be called to convert *pyfloat* into a float.
|
||||||
|
If ``__float__()`` is not defined then it falls back to :meth:`__index__`.
|
||||||
This method returns ``-1.0`` upon failure, so one should call
|
This method returns ``-1.0`` upon failure, so one should call
|
||||||
:c:func:`PyErr_Occurred` to check for errors.
|
:c:func:`PyErr_Occurred` to check for errors.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.8
|
||||||
|
Use :meth:`__index__` if available.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: double PyFloat_AS_DOUBLE(PyObject *pyfloat)
|
.. c:function:: double PyFloat_AS_DOUBLE(PyObject *pyfloat)
|
||||||
|
|
||||||
|
|
|
@ -318,6 +318,11 @@ are always available. They are listed here in alphabetical order.
|
||||||
:class:`int` and :class:`float`. If both arguments are omitted, returns
|
:class:`int` and :class:`float`. If both arguments are omitted, returns
|
||||||
``0j``.
|
``0j``.
|
||||||
|
|
||||||
|
For a general Python object ``x``, ``complex(x)`` delegates to
|
||||||
|
``x.__complex__()``. If ``__complex__()`` is not defined then it falls back
|
||||||
|
to :meth:`__float__`. If ``__float__()`` is not defined then it falls back
|
||||||
|
to :meth:`__index__`.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
When converting from a string, the string must not contain whitespace
|
When converting from a string, the string must not contain whitespace
|
||||||
|
@ -330,6 +335,10 @@ are always available. They are listed here in alphabetical order.
|
||||||
.. versionchanged:: 3.6
|
.. versionchanged:: 3.6
|
||||||
Grouping digits with underscores as in code literals is allowed.
|
Grouping digits with underscores as in code literals is allowed.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.8
|
||||||
|
Falls back to :meth:`__index__` if :meth:`__complex__` and
|
||||||
|
:meth:`__float__` are not defined.
|
||||||
|
|
||||||
|
|
||||||
.. function:: delattr(object, name)
|
.. function:: delattr(object, name)
|
||||||
|
|
||||||
|
@ -584,7 +593,8 @@ are always available. They are listed here in alphabetical order.
|
||||||
float, an :exc:`OverflowError` will be raised.
|
float, an :exc:`OverflowError` will be raised.
|
||||||
|
|
||||||
For a general Python object ``x``, ``float(x)`` delegates to
|
For a general Python object ``x``, ``float(x)`` delegates to
|
||||||
``x.__float__()``.
|
``x.__float__()``. If ``__float__()`` is not defined then it falls back
|
||||||
|
to :meth:`__index__`.
|
||||||
|
|
||||||
If no argument is given, ``0.0`` is returned.
|
If no argument is given, ``0.0`` is returned.
|
||||||
|
|
||||||
|
@ -609,6 +619,9 @@ are always available. They are listed here in alphabetical order.
|
||||||
.. versionchanged:: 3.7
|
.. versionchanged:: 3.7
|
||||||
*x* is now a positional-only parameter.
|
*x* is now a positional-only parameter.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.8
|
||||||
|
Falls back to :meth:`__index__` if :meth:`__float__` is not defined.
|
||||||
|
|
||||||
|
|
||||||
.. index::
|
.. index::
|
||||||
single: __format__
|
single: __format__
|
||||||
|
@ -780,7 +793,8 @@ are always available. They are listed here in alphabetical order.
|
||||||
|
|
||||||
Return an integer object constructed from a number or string *x*, or return
|
Return an integer object constructed from a number or string *x*, or return
|
||||||
``0`` if no arguments are given. If *x* defines :meth:`__int__`,
|
``0`` if no arguments are given. If *x* defines :meth:`__int__`,
|
||||||
``int(x)`` returns ``x.__int__()``. If *x* defines :meth:`__trunc__`,
|
``int(x)`` returns ``x.__int__()``. If *x* defines :meth:`__index__`,
|
||||||
|
it returns ``x.__index__()``. If *x* defines :meth:`__trunc__`,
|
||||||
it returns ``x.__trunc__()``.
|
it returns ``x.__trunc__()``.
|
||||||
For floating point numbers, this truncates towards zero.
|
For floating point numbers, this truncates towards zero.
|
||||||
|
|
||||||
|
@ -812,6 +826,9 @@ are always available. They are listed here in alphabetical order.
|
||||||
.. versionchanged:: 3.7
|
.. versionchanged:: 3.7
|
||||||
*x* is now a positional-only parameter.
|
*x* is now a positional-only parameter.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.8
|
||||||
|
Falls back to :meth:`__index__` if :meth:`__int__` is not defined.
|
||||||
|
|
||||||
|
|
||||||
.. function:: isinstance(object, classinfo)
|
.. function:: isinstance(object, classinfo)
|
||||||
|
|
||||||
|
|
|
@ -2394,11 +2394,9 @@ left undefined.
|
||||||
functions). Presence of this method indicates that the numeric object is
|
functions). Presence of this method indicates that the numeric object is
|
||||||
an integer type. Must return an integer.
|
an integer type. Must return an integer.
|
||||||
|
|
||||||
.. note::
|
If :meth:`__int__`, :meth:`__float__` and :meth:`__complex__` are not
|
||||||
|
defined then corresponding built-in functions :func:`int`, :func:`float`
|
||||||
In order to have a coherent integer type class, when :meth:`__index__` is
|
and :func:`complex` fall back to :meth:`__index__`.
|
||||||
defined :meth:`__int__` should also be defined, and both should return
|
|
||||||
the same value.
|
|
||||||
|
|
||||||
|
|
||||||
.. method:: object.__round__(self, [,ndigits])
|
.. method:: object.__round__(self, [,ndigits])
|
||||||
|
|
|
@ -250,6 +250,12 @@ Other Language Changes
|
||||||
compatible with the existing :meth:`float.as_integer_ratio` method.
|
compatible with the existing :meth:`float.as_integer_ratio` method.
|
||||||
(Contributed by Lisa Roach in :issue:`33073`.)
|
(Contributed by Lisa Roach in :issue:`33073`.)
|
||||||
|
|
||||||
|
* Constructors of :class:`int`, :class:`float` and :class:`complex` will now
|
||||||
|
use the :meth:`~object.__index__` special method, if available and the
|
||||||
|
corresponding method :meth:`~object.__int__`, :meth:`~object.__float__`
|
||||||
|
or :meth:`~object.__complex__` is not available.
|
||||||
|
(Contributed by Serhiy Storchaka in :issue:`20092`.)
|
||||||
|
|
||||||
* Added support of ``\N{name}`` escapes in :mod:`regular expressions <re>`.
|
* Added support of ``\N{name}`` escapes in :mod:`regular expressions <re>`.
|
||||||
(Contributed by Jonathan Eunice and Serhiy Storchaka in :issue:`30688`.)
|
(Contributed by Jonathan Eunice and Serhiy Storchaka in :issue:`30688`.)
|
||||||
|
|
||||||
|
@ -868,7 +874,10 @@ Build and C API Changes
|
||||||
``__index__()`` method (like :class:`~decimal.Decimal` and
|
``__index__()`` method (like :class:`~decimal.Decimal` and
|
||||||
:class:`~fractions.Fraction`). :c:func:`PyNumber_Check` will now return
|
:class:`~fractions.Fraction`). :c:func:`PyNumber_Check` will now return
|
||||||
``1`` for objects implementing ``__index__()``.
|
``1`` for objects implementing ``__index__()``.
|
||||||
(Contributed by Serhiy Storchaka in :issue:`36048`.)
|
:c:func:`PyNumber_Long`, :c:func:`PyNumber_Float` and
|
||||||
|
:c:func:`PyFloat_AsDouble` also now use the ``__index__()`` method if
|
||||||
|
available.
|
||||||
|
(Contributed by Serhiy Storchaka in :issue:`36048` and :issue:`20092`.)
|
||||||
|
|
||||||
* Heap-allocated type objects will now increase their reference count
|
* Heap-allocated type objects will now increase their reference count
|
||||||
in :c:func:`PyObject_Init` (and its parallel macro ``PyObject_INIT``)
|
in :c:func:`PyObject_Init` (and its parallel macro ``PyObject_INIT``)
|
||||||
|
|
|
@ -220,12 +220,11 @@ class CMathTests(unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
class NeitherComplexNorFloatOS:
|
class NeitherComplexNorFloatOS:
|
||||||
pass
|
pass
|
||||||
class MyInt(object):
|
class Index:
|
||||||
def __int__(self): return 2
|
def __int__(self): return 2
|
||||||
def __index__(self): return 2
|
def __index__(self): return 2
|
||||||
class MyIntOS:
|
class MyInt:
|
||||||
def __int__(self): return 2
|
def __int__(self): return 2
|
||||||
def __index__(self): return 2
|
|
||||||
|
|
||||||
# other possible combinations of __float__ and __complex__
|
# other possible combinations of __float__ and __complex__
|
||||||
# that should work
|
# that should work
|
||||||
|
@ -255,6 +254,7 @@ class CMathTests(unittest.TestCase):
|
||||||
self.assertEqual(f(FloatAndComplexOS()), f(cx_arg))
|
self.assertEqual(f(FloatAndComplexOS()), f(cx_arg))
|
||||||
self.assertEqual(f(JustFloat()), f(flt_arg))
|
self.assertEqual(f(JustFloat()), f(flt_arg))
|
||||||
self.assertEqual(f(JustFloatOS()), f(flt_arg))
|
self.assertEqual(f(JustFloatOS()), f(flt_arg))
|
||||||
|
self.assertEqual(f(Index()), f(int(Index())))
|
||||||
# TypeError should be raised for classes not providing
|
# TypeError should be raised for classes not providing
|
||||||
# either __complex__ or __float__, even if they provide
|
# either __complex__ or __float__, even if they provide
|
||||||
# __int__ or __index__. An old-style class
|
# __int__ or __index__. An old-style class
|
||||||
|
@ -263,7 +263,6 @@ class CMathTests(unittest.TestCase):
|
||||||
self.assertRaises(TypeError, f, NeitherComplexNorFloat())
|
self.assertRaises(TypeError, f, NeitherComplexNorFloat())
|
||||||
self.assertRaises(TypeError, f, MyInt())
|
self.assertRaises(TypeError, f, MyInt())
|
||||||
self.assertRaises(Exception, f, NeitherComplexNorFloatOS())
|
self.assertRaises(Exception, f, NeitherComplexNorFloatOS())
|
||||||
self.assertRaises(Exception, f, MyIntOS())
|
|
||||||
# non-complex return value from __complex__ -> TypeError
|
# non-complex return value from __complex__ -> TypeError
|
||||||
for bad_complex in non_complexes:
|
for bad_complex in non_complexes:
|
||||||
self.assertRaises(TypeError, f, MyComplex(bad_complex))
|
self.assertRaises(TypeError, f, MyComplex(bad_complex))
|
||||||
|
|
|
@ -368,6 +368,24 @@ class ComplexTest(unittest.TestCase):
|
||||||
self.assertAlmostEqual(complex(real=float2(17.), imag=float2(23.)), 17+23j)
|
self.assertAlmostEqual(complex(real=float2(17.), imag=float2(23.)), 17+23j)
|
||||||
self.assertRaises(TypeError, complex, float2(None))
|
self.assertRaises(TypeError, complex, float2(None))
|
||||||
|
|
||||||
|
class MyIndex:
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
def __index__(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
self.assertAlmostEqual(complex(MyIndex(42)), 42.0+0.0j)
|
||||||
|
self.assertAlmostEqual(complex(123, MyIndex(42)), 123.0+42.0j)
|
||||||
|
self.assertRaises(OverflowError, complex, MyIndex(2**2000))
|
||||||
|
self.assertRaises(OverflowError, complex, 123, MyIndex(2**2000))
|
||||||
|
|
||||||
|
class MyInt:
|
||||||
|
def __int__(self):
|
||||||
|
return 42
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, complex, MyInt())
|
||||||
|
self.assertRaises(TypeError, complex, 123, MyInt())
|
||||||
|
|
||||||
class complex0(complex):
|
class complex0(complex):
|
||||||
"""Test usage of __complex__() when inheriting from 'complex'"""
|
"""Test usage of __complex__() when inheriting from 'complex'"""
|
||||||
def __complex__(self):
|
def __complex__(self):
|
||||||
|
|
|
@ -223,6 +223,21 @@ class GeneralFloatCases(unittest.TestCase):
|
||||||
with self.assertWarns(DeprecationWarning):
|
with self.assertWarns(DeprecationWarning):
|
||||||
self.assertIs(type(FloatSubclass(F())), FloatSubclass)
|
self.assertIs(type(FloatSubclass(F())), FloatSubclass)
|
||||||
|
|
||||||
|
class MyIndex:
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
def __index__(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
self.assertEqual(float(MyIndex(42)), 42.0)
|
||||||
|
self.assertRaises(OverflowError, float, MyIndex(2**2000))
|
||||||
|
|
||||||
|
class MyInt:
|
||||||
|
def __int__(self):
|
||||||
|
return 42
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, float, MyInt())
|
||||||
|
|
||||||
def test_keyword_args(self):
|
def test_keyword_args(self):
|
||||||
with self.assertRaisesRegex(TypeError, 'keyword argument'):
|
with self.assertRaisesRegex(TypeError, 'keyword argument'):
|
||||||
float(x='3.14')
|
float(x='3.14')
|
||||||
|
|
|
@ -457,6 +457,8 @@ class Float_TestCase(unittest.TestCase):
|
||||||
with self.assertWarns(DeprecationWarning):
|
with self.assertWarns(DeprecationWarning):
|
||||||
self.assertEqual(getargs_f(BadFloat2()), 4.25)
|
self.assertEqual(getargs_f(BadFloat2()), 4.25)
|
||||||
self.assertEqual(getargs_f(BadFloat3(7.5)), 7.5)
|
self.assertEqual(getargs_f(BadFloat3(7.5)), 7.5)
|
||||||
|
self.assertEqual(getargs_f(Index()), 99.0)
|
||||||
|
self.assertRaises(TypeError, getargs_f, Int())
|
||||||
|
|
||||||
for x in (FLT_MIN, -FLT_MIN, FLT_MAX, -FLT_MAX, INF, -INF):
|
for x in (FLT_MIN, -FLT_MIN, FLT_MAX, -FLT_MAX, INF, -INF):
|
||||||
self.assertEqual(getargs_f(x), x)
|
self.assertEqual(getargs_f(x), x)
|
||||||
|
@ -489,6 +491,8 @@ class Float_TestCase(unittest.TestCase):
|
||||||
with self.assertWarns(DeprecationWarning):
|
with self.assertWarns(DeprecationWarning):
|
||||||
self.assertEqual(getargs_d(BadFloat2()), 4.25)
|
self.assertEqual(getargs_d(BadFloat2()), 4.25)
|
||||||
self.assertEqual(getargs_d(BadFloat3(7.5)), 7.5)
|
self.assertEqual(getargs_d(BadFloat3(7.5)), 7.5)
|
||||||
|
self.assertEqual(getargs_d(Index()), 99.0)
|
||||||
|
self.assertRaises(TypeError, getargs_d, Int())
|
||||||
|
|
||||||
for x in (DBL_MIN, -DBL_MIN, DBL_MAX, -DBL_MAX, INF, -INF):
|
for x in (DBL_MIN, -DBL_MIN, DBL_MAX, -DBL_MAX, INF, -INF):
|
||||||
self.assertEqual(getargs_d(x), x)
|
self.assertEqual(getargs_d(x), x)
|
||||||
|
@ -511,6 +515,8 @@ class Float_TestCase(unittest.TestCase):
|
||||||
with self.assertWarns(DeprecationWarning):
|
with self.assertWarns(DeprecationWarning):
|
||||||
self.assertEqual(getargs_D(BadComplex2()), 4.25+0.5j)
|
self.assertEqual(getargs_D(BadComplex2()), 4.25+0.5j)
|
||||||
self.assertEqual(getargs_D(BadComplex3(7.5+0.25j)), 7.5+0.25j)
|
self.assertEqual(getargs_D(BadComplex3(7.5+0.25j)), 7.5+0.25j)
|
||||||
|
self.assertEqual(getargs_D(Index()), 99.0+0j)
|
||||||
|
self.assertRaises(TypeError, getargs_D, Int())
|
||||||
|
|
||||||
for x in (DBL_MIN, -DBL_MIN, DBL_MAX, -DBL_MAX, INF, -INF):
|
for x in (DBL_MIN, -DBL_MIN, DBL_MAX, -DBL_MAX, INF, -INF):
|
||||||
c = complex(x, 1.0)
|
c = complex(x, 1.0)
|
||||||
|
|
|
@ -60,7 +60,7 @@ class BaseTestCase(unittest.TestCase):
|
||||||
# subclasses. See issue #17576.
|
# subclasses. See issue #17576.
|
||||||
class MyInt(int):
|
class MyInt(int):
|
||||||
def __index__(self):
|
def __index__(self):
|
||||||
return int(self) + 1
|
return int(str(self)) + 1
|
||||||
|
|
||||||
my_int = MyInt(7)
|
my_int = MyInt(7)
|
||||||
direct_index = my_int.__index__()
|
direct_index = my_int.__index__()
|
||||||
|
|
|
@ -378,15 +378,23 @@ class IntTestCases(unittest.TestCase):
|
||||||
int(ExceptionalTrunc())
|
int(ExceptionalTrunc())
|
||||||
|
|
||||||
for trunc_result_base in (object, Classic):
|
for trunc_result_base in (object, Classic):
|
||||||
class Integral(trunc_result_base):
|
class Index(trunc_result_base):
|
||||||
def __int__(self):
|
def __index__(self):
|
||||||
return 42
|
return 42
|
||||||
|
|
||||||
class TruncReturnsNonInt(base):
|
class TruncReturnsNonInt(base):
|
||||||
def __trunc__(self):
|
def __trunc__(self):
|
||||||
return Integral()
|
return Index()
|
||||||
with self.assertWarns(DeprecationWarning):
|
self.assertEqual(int(TruncReturnsNonInt()), 42)
|
||||||
self.assertEqual(int(TruncReturnsNonInt()), 42)
|
|
||||||
|
class Intable(trunc_result_base):
|
||||||
|
def __int__(self):
|
||||||
|
return 42
|
||||||
|
|
||||||
|
class TruncReturnsNonIndex(base):
|
||||||
|
def __trunc__(self):
|
||||||
|
return Intable()
|
||||||
|
self.assertEqual(int(TruncReturnsNonInt()), 42)
|
||||||
|
|
||||||
class NonIntegral(trunc_result_base):
|
class NonIntegral(trunc_result_base):
|
||||||
def __trunc__(self):
|
def __trunc__(self):
|
||||||
|
@ -418,6 +426,21 @@ class IntTestCases(unittest.TestCase):
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
int(TruncReturnsBadInt())
|
int(TruncReturnsBadInt())
|
||||||
|
|
||||||
|
def test_int_subclass_with_index(self):
|
||||||
|
class MyIndex(int):
|
||||||
|
def __index__(self):
|
||||||
|
return 42
|
||||||
|
|
||||||
|
class BadIndex(int):
|
||||||
|
def __index__(self):
|
||||||
|
return 42.0
|
||||||
|
|
||||||
|
my_int = MyIndex(7)
|
||||||
|
self.assertEqual(my_int, 7)
|
||||||
|
self.assertEqual(int(my_int), 7)
|
||||||
|
|
||||||
|
self.assertEqual(int(BadIndex()), 0)
|
||||||
|
|
||||||
def test_int_subclass_with_int(self):
|
def test_int_subclass_with_int(self):
|
||||||
class MyInt(int):
|
class MyInt(int):
|
||||||
def __int__(self):
|
def __int__(self):
|
||||||
|
@ -431,9 +454,19 @@ class IntTestCases(unittest.TestCase):
|
||||||
self.assertEqual(my_int, 7)
|
self.assertEqual(my_int, 7)
|
||||||
self.assertEqual(int(my_int), 42)
|
self.assertEqual(int(my_int), 42)
|
||||||
|
|
||||||
self.assertRaises(TypeError, int, BadInt())
|
my_int = BadInt(7)
|
||||||
|
self.assertEqual(my_int, 7)
|
||||||
|
self.assertRaises(TypeError, int, my_int)
|
||||||
|
|
||||||
def test_int_returns_int_subclass(self):
|
def test_int_returns_int_subclass(self):
|
||||||
|
class BadIndex:
|
||||||
|
def __index__(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
class BadIndex2(int):
|
||||||
|
def __index__(self):
|
||||||
|
return True
|
||||||
|
|
||||||
class BadInt:
|
class BadInt:
|
||||||
def __int__(self):
|
def __int__(self):
|
||||||
return True
|
return True
|
||||||
|
@ -442,6 +475,10 @@ class IntTestCases(unittest.TestCase):
|
||||||
def __int__(self):
|
def __int__(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
class TruncReturnsBadIndex:
|
||||||
|
def __trunc__(self):
|
||||||
|
return BadIndex()
|
||||||
|
|
||||||
class TruncReturnsBadInt:
|
class TruncReturnsBadInt:
|
||||||
def __trunc__(self):
|
def __trunc__(self):
|
||||||
return BadInt()
|
return BadInt()
|
||||||
|
@ -450,6 +487,17 @@ class IntTestCases(unittest.TestCase):
|
||||||
def __trunc__(self):
|
def __trunc__(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
bad_int = BadIndex()
|
||||||
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
n = int(bad_int)
|
||||||
|
self.assertEqual(n, 1)
|
||||||
|
self.assertIs(type(n), int)
|
||||||
|
|
||||||
|
bad_int = BadIndex2()
|
||||||
|
n = int(bad_int)
|
||||||
|
self.assertEqual(n, 0)
|
||||||
|
self.assertIs(type(n), int)
|
||||||
|
|
||||||
bad_int = BadInt()
|
bad_int = BadInt()
|
||||||
with self.assertWarns(DeprecationWarning):
|
with self.assertWarns(DeprecationWarning):
|
||||||
n = int(bad_int)
|
n = int(bad_int)
|
||||||
|
@ -462,6 +510,12 @@ class IntTestCases(unittest.TestCase):
|
||||||
self.assertEqual(n, 1)
|
self.assertEqual(n, 1)
|
||||||
self.assertIs(type(n), int)
|
self.assertIs(type(n), int)
|
||||||
|
|
||||||
|
bad_int = TruncReturnsBadIndex()
|
||||||
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
n = int(bad_int)
|
||||||
|
self.assertEqual(n, 1)
|
||||||
|
self.assertIs(type(n), int)
|
||||||
|
|
||||||
bad_int = TruncReturnsBadInt()
|
bad_int = TruncReturnsBadInt()
|
||||||
with self.assertWarns(DeprecationWarning):
|
with self.assertWarns(DeprecationWarning):
|
||||||
n = int(bad_int)
|
n = int(bad_int)
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Constructors of :class:`int`, :class:`float` and :class:`complex` will now
|
||||||
|
use the :meth:`~object.__index__` special method, if available and the
|
||||||
|
corresponding method :meth:`~object.__int__`, :meth:`~object.__float__`
|
||||||
|
or :meth:`~object.__complex__` is not available.
|
|
@ -1373,6 +1373,13 @@ PyNumber_Long(PyObject *o)
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
if (m && m->nb_index) {
|
||||||
|
result = _PyLong_FromNbIndexOrNbInt(o);
|
||||||
|
if (result != NULL && !PyLong_CheckExact(result)) {
|
||||||
|
Py_SETREF(result, _PyLong_Copy((PyLongObject *)result));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
trunc_func = _PyObject_LookupSpecial(o, &PyId___trunc__);
|
trunc_func = _PyObject_LookupSpecial(o, &PyId___trunc__);
|
||||||
if (trunc_func) {
|
if (trunc_func) {
|
||||||
result = _PyObject_CallNoArg(trunc_func);
|
result = _PyObject_CallNoArg(trunc_func);
|
||||||
|
@ -1480,6 +1487,18 @@ PyNumber_Float(PyObject *o)
|
||||||
Py_DECREF(res);
|
Py_DECREF(res);
|
||||||
return PyFloat_FromDouble(val);
|
return PyFloat_FromDouble(val);
|
||||||
}
|
}
|
||||||
|
if (m && m->nb_index) {
|
||||||
|
PyObject *res = PyNumber_Index(o);
|
||||||
|
if (!res) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
double val = PyLong_AsDouble(res);
|
||||||
|
Py_DECREF(res);
|
||||||
|
if (val == -1.0 && PyErr_Occurred()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return PyFloat_FromDouble(val);
|
||||||
|
}
|
||||||
if (PyFloat_Check(o)) { /* A float subclass with nb_float == NULL */
|
if (PyFloat_Check(o)) { /* A float subclass with nb_float == NULL */
|
||||||
return PyFloat_FromDouble(PyFloat_AS_DOUBLE(o));
|
return PyFloat_FromDouble(PyFloat_AS_DOUBLE(o));
|
||||||
}
|
}
|
||||||
|
|
|
@ -984,7 +984,7 @@ complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i)
|
||||||
}
|
}
|
||||||
|
|
||||||
nbr = r->ob_type->tp_as_number;
|
nbr = r->ob_type->tp_as_number;
|
||||||
if (nbr == NULL || nbr->nb_float == NULL) {
|
if (nbr == NULL || (nbr->nb_float == NULL && nbr->nb_index == NULL)) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"complex() first argument must be a string or a number, "
|
"complex() first argument must be a string or a number, "
|
||||||
"not '%.200s'",
|
"not '%.200s'",
|
||||||
|
@ -996,7 +996,7 @@ complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i)
|
||||||
}
|
}
|
||||||
if (i != NULL) {
|
if (i != NULL) {
|
||||||
nbi = i->ob_type->tp_as_number;
|
nbi = i->ob_type->tp_as_number;
|
||||||
if (nbi == NULL || nbi->nb_float == NULL) {
|
if (nbi == NULL || (nbi->nb_float == NULL && nbi->nb_index == NULL)) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"complex() second argument must be a number, "
|
"complex() second argument must be a number, "
|
||||||
"not '%.200s'",
|
"not '%.200s'",
|
||||||
|
@ -1052,7 +1052,7 @@ complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i)
|
||||||
/* The "imag" part really is entirely imaginary, and
|
/* The "imag" part really is entirely imaginary, and
|
||||||
contributes nothing in the real direction.
|
contributes nothing in the real direction.
|
||||||
Just treat it as a double. */
|
Just treat it as a double. */
|
||||||
tmp = (*nbi->nb_float)(i);
|
tmp = PyNumber_Float(i);
|
||||||
if (tmp == NULL)
|
if (tmp == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
ci.real = PyFloat_AsDouble(tmp);
|
ci.real = PyFloat_AsDouble(tmp);
|
||||||
|
|
|
@ -246,6 +246,15 @@ PyFloat_AsDouble(PyObject *op)
|
||||||
|
|
||||||
nb = Py_TYPE(op)->tp_as_number;
|
nb = Py_TYPE(op)->tp_as_number;
|
||||||
if (nb == NULL || nb->nb_float == NULL) {
|
if (nb == NULL || nb->nb_float == NULL) {
|
||||||
|
if (nb && nb->nb_index) {
|
||||||
|
PyObject *res = PyNumber_Index(op);
|
||||||
|
if (!res) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
double val = PyLong_AsDouble(res);
|
||||||
|
Py_DECREF(res);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
PyErr_Format(PyExc_TypeError, "must be real number, not %.50s",
|
PyErr_Format(PyExc_TypeError, "must be real number, not %.50s",
|
||||||
op->ob_type->tp_name);
|
op->ob_type->tp_name);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
Loading…
Reference in New Issue