From f3e83a47b1fbb3d564b30e90db97d9cb7733b8d6 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 21 Jun 2021 14:53:21 +0300 Subject: [PATCH 1/5] bpo-40801: Add float.from_number() and complex.from_number() They are alternate constructors which only accept numbers (including objects with special methods __float__, __complex__ and __index__), but not strings. --- Lib/test/test_complex.py | 122 ++++++++++++++++++++----------- Lib/test/test_float.py | 89 +++++++++++++++------- Objects/clinic/complexobject.c.h | 11 ++- Objects/clinic/floatobject.c.h | 11 ++- Objects/complexobject.c | 59 +++++++++++---- Objects/floatobject.c | 31 ++++++++ 6 files changed, 237 insertions(+), 86 deletions(-) diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py index af39ee878dc913..d2e44355fbac60 100644 --- a/Lib/test/test_complex.py +++ b/Lib/test/test_complex.py @@ -9,6 +9,42 @@ INF = float("inf") NAN = float("nan") + +class ComplexSubclass(complex): + pass + +class OtherComplexSubclass(complex): + pass + +class MyIndex: + def __init__(self, value): + self.value = value + + def __index__(self): + return self.value + +class MyInt: + def __init__(self, value): + self.value = value + + def __int__(self): + return self.value + +class FloatLike: + def __init__(self, value): + self.value = value + + def __float__(self): + return self.value + +class ComplexLike: + def __init__(self, value): + self.value = value + + def __complex__(self): + return self.value + + # These tests ensure that complex math does the right thing ZERO_DIVISION = ( @@ -257,19 +293,11 @@ def test_conjugate(self): self.assertClose(complex(5.3, 9.8).conjugate(), 5.3-9.8j) def test_constructor(self): - class OS: - def __init__(self, value): self.value = value - def __complex__(self): return self.value - class NS(object): - def __init__(self, value): self.value = value - def __complex__(self): return self.value - self.assertEqual(complex(OS(1+10j)), 1+10j) - self.assertEqual(complex(NS(1+10j)), 1+10j) - self.assertRaises(TypeError, complex, OS(None)) - self.assertRaises(TypeError, complex, NS(None)) + self.assertEqual(complex(ComplexLike(1+10j)), 1+10j) + self.assertRaises(TypeError, complex, ComplexLike(None)) self.assertRaises(TypeError, complex, {}) - self.assertRaises(TypeError, complex, NS(1.5)) - self.assertRaises(TypeError, complex, NS(1)) + self.assertRaises(TypeError, complex, ComplexLike(1.5)) + self.assertRaises(TypeError, complex, ComplexLike(1)) self.assertAlmostEqual(complex("1+10j"), 1+10j) self.assertAlmostEqual(complex(10), 10+0j) @@ -316,8 +344,7 @@ def __complex__(self): return self.value self.assertAlmostEqual(complex('-1e-500j'), 0.0 - 0.0j) self.assertAlmostEqual(complex('-1e-500+1e-500j'), -0.0 + 0.0j) - class complex2(complex): pass - self.assertAlmostEqual(complex(complex2(1+1j)), 1+1j) + self.assertAlmostEqual(complex(ComplexSubclass(1+1j)), 1+1j) self.assertAlmostEqual(complex(real=17, imag=23), 17+23j) self.assertAlmostEqual(complex(real=17+23j), 17+23j) self.assertAlmostEqual(complex(real=17+23j, imag=23), 17+46j) @@ -399,33 +426,17 @@ def __complex__(self): self.assertRaises(EvilExc, complex, evilcomplex()) - class float2: - def __init__(self, value): - self.value = value - def __float__(self): - return self.value - - self.assertAlmostEqual(complex(float2(42.)), 42) - self.assertAlmostEqual(complex(real=float2(17.), imag=float2(23.)), 17+23j) - self.assertRaises(TypeError, complex, float2(None)) - - class MyIndex: - def __init__(self, value): - self.value = value - def __index__(self): - return self.value + self.assertAlmostEqual(complex(FloatLike(42.)), 42) + self.assertAlmostEqual(complex(real=FloatLike(17.), imag=FloatLike(23.)), 17+23j) + self.assertRaises(TypeError, complex, FloatLike(None)) 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()) + self.assertRaises(TypeError, complex, MyInt(42)) + self.assertRaises(TypeError, complex, 123, MyInt(42)) class complex0(complex): """Test usage of __complex__() when inheriting from 'complex'""" @@ -452,24 +463,22 @@ def __complex__(self): @support.requires_IEEE_754 def test_constructor_special_numbers(self): - class complex2(complex): - pass for x in 0.0, -0.0, INF, -INF, NAN: for y in 0.0, -0.0, INF, -INF, NAN: with self.subTest(x=x, y=y): z = complex(x, y) self.assertFloatsAreIdentical(z.real, x) self.assertFloatsAreIdentical(z.imag, y) - z = complex2(x, y) - self.assertIs(type(z), complex2) + z = ComplexSubclass(x, y) + self.assertIs(type(z), ComplexSubclass) self.assertFloatsAreIdentical(z.real, x) self.assertFloatsAreIdentical(z.imag, y) - z = complex(complex2(x, y)) + z = complex(ComplexSubclass(x, y)) self.assertIs(type(z), complex) self.assertFloatsAreIdentical(z.real, x) self.assertFloatsAreIdentical(z.imag, y) - z = complex2(complex(x, y)) - self.assertIs(type(z), complex2) + z = ComplexSubclass(complex(x, y)) + self.assertIs(type(z), ComplexSubclass) self.assertFloatsAreIdentical(z.real, x) self.assertFloatsAreIdentical(z.imag, y) @@ -485,6 +494,35 @@ def test_underscores(self): if not any(ch in lit for ch in 'xXoObB'): self.assertRaises(ValueError, complex, lit) + def test_from_number(self, cls=complex): + def eq(actual, expected): + self.assertEqual(actual, expected) + self.assertIs(type(actual), cls) + + eq(cls.from_number(3.14), 3.14+0j) + eq(cls.from_number(3.14j), 3.14j) + eq(cls.from_number(314), 314.0+0j) + eq(cls.from_number(OtherComplexSubclass(3.14, 2.72)), 3.14+2.72j) + eq(cls.from_number(ComplexLike(3.14+2.72j)), 3.14+2.72j) + eq(cls.from_number(FloatLike(3.14)), 3.14+0j) + eq(cls.from_number(MyIndex(314)), 314.0+0j) + + cNAN = complex(NAN, NAN) + x = cls.from_number(cNAN) + self.assertTrue(x != x) + self.assertIs(type(x), cls) + if cls is complex: + self.assertIs(cls.from_number(cNAN), cNAN) + + self.assertRaises(TypeError, cls.from_number, '3.14') + self.assertRaises(TypeError, cls.from_number, b'3.14') + self.assertRaises(TypeError, cls.from_number, MyInt(314)) + self.assertRaises(TypeError, cls.from_number, {}) + self.assertRaises(TypeError, cls.from_number) + + def test_from_number_subclass(self): + self.test_from_number(ComplexSubclass) + def test_hash(self): for x in range(-30, 30): self.assertEqual(hash(x), hash(complex(x, 0))) diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py index f0ed40f7c94a7e..d39f664013b6c6 100644 --- a/Lib/test/test_float.py +++ b/Lib/test/test_float.py @@ -31,6 +31,28 @@ class FloatSubclass(float): class OtherFloatSubclass(float): pass +class MyIndex: + def __init__(self, value): + self.value = value + + def __index__(self): + return self.value + +class MyInt: + def __init__(self, value): + self.value = value + + def __int__(self): + return self.value + +class FloatLike: + def __init__(self, value): + self.value = value + + def __float__(self): + return self.value + + class GeneralFloatCases(unittest.TestCase): def test_float(self): @@ -176,10 +198,6 @@ def test_float_with_comma(self): def test_floatconversion(self): # Make sure that calls to __float__() work properly - class Foo1(object): - def __float__(self): - return 42. - class Foo2(float): def __float__(self): return 42. @@ -201,50 +219,65 @@ class FooStr(str): def __float__(self): return float(str(self)) + 1 - self.assertEqual(float(Foo1()), 42.) + self.assertEqual(float(FloatLike(42.)), 42.) self.assertEqual(float(Foo2()), 42.) with self.assertWarns(DeprecationWarning): self.assertEqual(float(Foo3(21)), 42.) self.assertRaises(TypeError, float, Foo4(42)) self.assertEqual(float(FooStr('8')), 9.) - class Foo5: - def __float__(self): - return "" - self.assertRaises(TypeError, time.sleep, Foo5()) + self.assertRaises(TypeError, time.sleep, FloatLike("")) # Issue #24731 - class F: - def __float__(self): - return OtherFloatSubclass(42.) + f = FloatLike(OtherFloatSubclass(42.)) with self.assertWarns(DeprecationWarning): - self.assertEqual(float(F()), 42.) + self.assertEqual(float(f), 42.) with self.assertWarns(DeprecationWarning): - self.assertIs(type(float(F())), float) + self.assertIs(type(float(f)), float) with self.assertWarns(DeprecationWarning): - self.assertEqual(FloatSubclass(F()), 42.) + self.assertEqual(FloatSubclass(f), 42.) with self.assertWarns(DeprecationWarning): - self.assertIs(type(FloatSubclass(F())), FloatSubclass) - - class MyIndex: - def __init__(self, value): - self.value = value - def __index__(self): - return self.value + self.assertIs(type(FloatSubclass(f)), FloatSubclass) 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()) + self.assertRaises(TypeError, float, MyInt(42)) def test_keyword_args(self): with self.assertRaisesRegex(TypeError, 'keyword argument'): float(x='3.14') + def assertEqualAndType(self, actual, expected_value, expected_type): + self.assertEqual(actual, expected_value) + self.assertIs(type(actual), expected_type) + + def test_from_number(self, cls=float): + def eq(actual, expected): + self.assertEqual(actual, expected) + self.assertIs(type(actual), cls) + + eq(cls.from_number(3.14), 3.14) + eq(cls.from_number(314), 314.0) + eq(cls.from_number(OtherFloatSubclass(3.14)), 3.14) + eq(cls.from_number(FloatLike(3.14)), 3.14) + eq(cls.from_number(MyIndex(314)), 314.0) + + x = cls.from_number(NAN) + self.assertTrue(x != x) + self.assertIs(type(x), cls) + if cls is float: + self.assertIs(cls.from_number(NAN), NAN) + + self.assertRaises(TypeError, cls.from_number, '3.14') + self.assertRaises(TypeError, cls.from_number, b'3.14') + self.assertRaises(TypeError, cls.from_number, 3.14j) + self.assertRaises(TypeError, cls.from_number, MyInt(314)) + self.assertRaises(TypeError, cls.from_number, {}) + self.assertRaises(TypeError, cls.from_number) + + def test_from_number_subclass(self): + self.test_from_number(FloatSubclass) + def test_is_integer(self): self.assertFalse((1.1).is_integer()) self.assertTrue((1.).is_integer()) diff --git a/Objects/clinic/complexobject.c.h b/Objects/clinic/complexobject.c.h index 557fbf9752faf7..20eb8b550161fd 100644 --- a/Objects/clinic/complexobject.c.h +++ b/Objects/clinic/complexobject.c.h @@ -113,4 +113,13 @@ complex_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=056cac3226d94967 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(complex_from_number__doc__, +"from_number($type, number, /)\n" +"--\n" +"\n" +"Convert number to a complex floating-point number."); + +#define COMPLEX_FROM_NUMBER_METHODDEF \ + {"from_number", (PyCFunction)complex_from_number, METH_O|METH_CLASS, complex_from_number__doc__}, +/*[clinic end generated code: output=77dd57dca5630283 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/floatobject.c.h b/Objects/clinic/floatobject.c.h index 5643f0e3ac6501..e02c4187b65b5c 100644 --- a/Objects/clinic/floatobject.c.h +++ b/Objects/clinic/floatobject.c.h @@ -226,6 +226,15 @@ float_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) return return_value; } +PyDoc_STRVAR(float_from_number__doc__, +"from_number($type, number, /)\n" +"--\n" +"\n" +"Convert real number to a floating-point number."); + +#define FLOAT_FROM_NUMBER_METHODDEF \ + {"from_number", (PyCFunction)float_from_number, METH_O|METH_CLASS, float_from_number__doc__}, + PyDoc_STRVAR(float___getnewargs____doc__, "__getnewargs__($self, /)\n" "--\n" @@ -387,4 +396,4 @@ float___format__(PyObject *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=bb079c3e130e4ce6 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=74d0357d38360be6 input=a9049054013a1b77]*/ diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 91e06a8c2c2ab7..b51eda7505de3f 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -700,20 +700,6 @@ complex___format___impl(PyComplexObject *self, PyObject *format_spec) return _PyUnicodeWriter_Finish(&writer); } -static PyMethodDef complex_methods[] = { - COMPLEX_CONJUGATE_METHODDEF - COMPLEX___GETNEWARGS___METHODDEF - COMPLEX___FORMAT___METHODDEF - {NULL, NULL} /* sentinel */ -}; - -static PyMemberDef complex_members[] = { - {"real", T_DOUBLE, offsetof(PyComplexObject, cval.real), READONLY, - "the real part of a complex number"}, - {"imag", T_DOUBLE, offsetof(PyComplexObject, cval.imag), READONLY, - "the imaginary part of a complex number"}, - {0}, -}; static PyObject * complex_from_string_inner(const char *s, Py_ssize_t len, void *type) @@ -1021,6 +1007,51 @@ complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i) return complex_subtype_from_doubles(type, cr.real, ci.real); } +/*[clinic input] +@classmethod +complex.from_number + + number: object + / + +Convert number to a complex floating-point number. +[clinic start generated code]*/ + +static PyObject * +complex_from_number(PyTypeObject *type, PyObject *number) +/*[clinic end generated code: output=658a7a5fb0de074d input=3f8bdd3a2bc3facd]*/ +{ + if (PyComplex_CheckExact(number) && type == &PyComplex_Type) { + Py_INCREF(number); + return number; + } + Py_complex cv = PyComplex_AsCComplex(number); + if (cv.real == -1.0 && PyErr_Occurred()) { + return NULL; + } + PyObject *result = PyComplex_FromCComplex(cv); + if (type != &PyComplex_Type && result != NULL) { + Py_SETREF(result, PyObject_CallOneArg((PyObject *)type, result)); + } + return result; +} + +static PyMethodDef complex_methods[] = { + COMPLEX_FROM_NUMBER_METHODDEF + COMPLEX_CONJUGATE_METHODDEF + COMPLEX___GETNEWARGS___METHODDEF + COMPLEX___FORMAT___METHODDEF + {NULL, NULL} /* sentinel */ +}; + +static PyMemberDef complex_members[] = { + {"real", T_DOUBLE, offsetof(PyComplexObject, cval.real), READONLY, + "the real part of a complex number"}, + {"imag", T_DOUBLE, offsetof(PyComplexObject, cval.imag), READONLY, + "the imaginary part of a complex number"}, + {0}, +}; + static PyNumberMethods complex_as_number = { (binaryfunc)complex_add, /* nb_add */ (binaryfunc)complex_sub, /* nb_subtract */ diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 7e78132c01ca27..c513dbee12a050 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -1676,6 +1676,36 @@ float_vectorcall(PyObject *type, PyObject * const*args, } +/*[clinic input] +@classmethod +float.from_number + + number: object + / + +Convert real number to a floating-point number. +[clinic start generated code]*/ + +static PyObject * +float_from_number(PyTypeObject *type, PyObject *number) +/*[clinic end generated code: output=bbcf05529fe907a3 input=1f8424d9bc11866a]*/ +{ + if (PyFloat_CheckExact(number) && type == &PyFloat_Type) { + Py_INCREF(number); + return number; + } + double x = PyFloat_AsDouble(number); + if (x == -1.0 && PyErr_Occurred()) { + return NULL; + } + PyObject *result = PyFloat_FromDouble(x); + if (type != &PyFloat_Type && result != NULL) { + Py_SETREF(result, PyObject_CallOneArg((PyObject *)type, result)); + } + return result; +} + + /*[clinic input] float.__getnewargs__ [clinic start generated code]*/ @@ -1860,6 +1890,7 @@ float___format___impl(PyObject *self, PyObject *format_spec) } static PyMethodDef float_methods[] = { + FLOAT_FROM_NUMBER_METHODDEF FLOAT_CONJUGATE_METHODDEF FLOAT___TRUNC___METHODDEF FLOAT___FLOOR___METHODDEF From 7946ef1045b98581b5668c989d160f47c65a7d9f Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 21 Jun 2021 16:28:43 +0300 Subject: [PATCH 2/5] Fix test_doctest. --- Lib/test/test_doctest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index 828a0ff56763a4..b34ea640ae4572 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -668,7 +668,7 @@ def non_Python_modules(): r""" >>> import builtins >>> tests = doctest.DocTestFinder().find(builtins) - >>> 816 < len(tests) < 836 # approximate number of objects with docstrings + >>> 820 < len(tests) < 850 # approximate number of objects with docstrings True >>> real_tests = [t for t in tests if len(t.examples) > 0] >>> len(real_tests) # objects that actually have doctests From 4eb72c414dac82021d08c4a63df12ff22d45d84d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 14 Oct 2023 23:09:16 +0300 Subject: [PATCH 3/5] Add documentation. --- Doc/library/functions.rst | 4 +++ Doc/library/stdtypes.rst | 36 +++++++++++++++++++ Doc/whatsnew/3.13.rst | 5 +++ ...3-10-14-23-05-40.gh-issue-84978.Z0t6dg.rst | 1 + 4 files changed, 46 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-14-23-05-40.gh-issue-84978.Z0t6dg.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 35206097064284..fa4ffe1306e453 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -387,6 +387,8 @@ are always available. They are listed here in alphabetical order. to :meth:`~object.__float__`. If :meth:`!__float__` is not defined then it falls back to :meth:`~object.__index__`. + See also :meth:`complex.from_number` which only accept single numeric argument. + .. note:: When converting from a string, the string must not contain whitespace @@ -684,6 +686,8 @@ are always available. They are listed here in alphabetical order. ``x.__float__()``. If :meth:`~object.__float__` is not defined then it falls back to :meth:`~object.__index__`. + See also :meth:`float.from_number` which only accept numeric argument. + If no argument is given, ``0.0`` is returned. Examples:: diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index f45fd561d2bad3..3daffe63f32354 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -624,6 +624,23 @@ Additional Methods on Float The float type implements the :class:`numbers.Real` :term:`abstract base class`. float also has the following additional methods. +.. classmethod:: float.from_number(x) + + Class method to return a floating point number constructed from a number *x*. + + If the argument is an integer or a floating point number, a + floating point number with the same value (within Python's floating point + precision) is returned. If the argument is outside the range of a Python + float, an :exc:`OverflowError` will be raised. + + For a general Python object ``x``, ``float.from_number(x)`` delegates to + ``x.__float__()``. + If :meth:`~object.__float__` is not defined then it falls back + to :meth:`~object.__index__`. + + .. versionadded:: 3.13 + + .. method:: float.as_integer_ratio() Return a pair of integers whose ratio is exactly equal to the @@ -702,6 +719,25 @@ hexadecimal string representing the same number:: '0x1.d380000000000p+11' +Additional Methods on Complex +----------------------------- + +The :class:`!complex` type implements the :class:`numbers.Complex` +:term:`abstract base class`. +:class:`!complex` also has the following additional methods. + +.. classmethod:: complex.from_number(x) + + Class method to convert a number to a complex number. + + For a general Python object ``x``, ``complex.from_number(x)`` delegates to + ``x.__complex__()``. If :meth:`~object.__complex__` is not defined then it falls back + to :meth:`~object.__float__`. If :meth:`!__float__` is not defined then it falls back + to :meth:`~object.__index__`. + + .. versionadded:: 3.13 + + .. _numeric-hash: Hashing of numeric types diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index d5987ae31ce68d..cc7409ebc6267f 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -75,6 +75,11 @@ New Features Other Language Changes ====================== +* Added class methods :meth:`float.from_number` and :meth:`complex.from_number` + to convert a number to :class:`float` or :class:`complex` type correspondingly. + They raise error if the argument is a string. + (Contributed by Serhiy Storchaka in :gh:`84978`.) + * Allow the *count* argument of :meth:`str.replace` to be a keyword. (Contributed by Hugo van Kemenade in :gh:`106487`.) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-14-23-05-40.gh-issue-84978.Z0t6dg.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-14-23-05-40.gh-issue-84978.Z0t6dg.rst new file mode 100644 index 00000000000000..b1f08288f925da --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-14-23-05-40.gh-issue-84978.Z0t6dg.rst @@ -0,0 +1 @@ +Add class methods :meth:`float.from_number` and :meth:`complex.from_number`. From dd357528a382df34f1a617e8f833edf070092c13 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 15 Jul 2024 12:38:16 +0300 Subject: [PATCH 4/5] Apply suggestions from code review Co-authored-by: Mark Dickinson --- Doc/library/functions.rst | 4 ++-- Doc/whatsnew/3.13.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index ff9a8f174aaa86..624ff954c663a0 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -387,7 +387,7 @@ are always available. They are listed here in alphabetical order. to :meth:`~object.__float__`. If :meth:`!__float__` is not defined then it falls back to :meth:`~object.__index__`. - See also :meth:`complex.from_number` which only accept single numeric argument. + See also :meth:`complex.from_number` which only accepts a single numeric argument. .. note:: @@ -686,7 +686,7 @@ are always available. They are listed here in alphabetical order. ``x.__float__()``. If :meth:`~object.__float__` is not defined then it falls back to :meth:`~object.__index__`. - See also :meth:`float.from_number` which only accept numeric argument. + See also :meth:`float.from_number` which only accepts a numeric argument. If no argument is given, ``0.0`` is returned. diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 503df83241d756..a804b1e3acd147 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -77,7 +77,7 @@ Other Language Changes * Added class methods :meth:`float.from_number` and :meth:`complex.from_number` to convert a number to :class:`float` or :class:`complex` type correspondingly. - They raise error if the argument is a string. + They raise an error if the argument is a string. (Contributed by Serhiy Storchaka in :gh:`84978`.) * Allow the *count* argument of :meth:`str.replace` to be a keyword. From c90cae7a2132dd6acc9ad4020a6921772f16b526 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 15 Jul 2024 13:12:04 +0300 Subject: [PATCH 5/5] Move to 3.14. --- Doc/library/stdtypes.rst | 4 ++-- Doc/whatsnew/3.13.rst | 5 ----- Doc/whatsnew/3.14.rst | 4 ++++ 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 73bf6847a4ca65..b74cd908d7741b 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -639,7 +639,7 @@ class`. float also has the following additional methods. If :meth:`~object.__float__` is not defined then it falls back to :meth:`~object.__index__`. - .. versionadded:: 3.13 + .. versionadded:: 3.14 .. method:: float.as_integer_ratio() @@ -736,7 +736,7 @@ The :class:`!complex` type implements the :class:`numbers.Complex` to :meth:`~object.__float__`. If :meth:`!__float__` is not defined then it falls back to :meth:`~object.__index__`. - .. versionadded:: 3.13 + .. versionadded:: 3.14 .. _numeric-hash: diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 5cadcb7a9e5d09..4a9a0b77d068b3 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -422,11 +422,6 @@ free-threaded build. Other Language Changes ====================== -* Added class methods :meth:`float.from_number` and :meth:`complex.from_number` - to convert a number to :class:`float` or :class:`complex` type correspondingly. - They raise an error if the argument is a string. - (Contributed by Serhiy Storchaka in :gh:`84978`.) - * Allow the *count* argument of :meth:`str.replace` to be a keyword. (Contributed by Hugo van Kemenade in :gh:`106487`.) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index da9b45cd8e58b3..8f7b6ebd0af316 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -75,6 +75,10 @@ New Features Other Language Changes ====================== +* Added class methods :meth:`float.from_number` and :meth:`complex.from_number` + to convert a number to :class:`float` or :class:`complex` type correspondingly. + They raise an error if the argument is a string. + (Contributed by Serhiy Storchaka in :gh:`84978`.) New Modules