mirror of
https://github.com/python/cpython.git
synced 2025-10-21 14:12:27 +00:00
gh-84978: Add float.from_number() and complex.from_number() (GH-26827)
They are alternate constructors which only accept numbers (including objects with special methods __float__, __complex__ and __index__), but not strings.
This commit is contained in:
parent
8303d32ff5
commit
94bee45dee
10 changed files with 242 additions and 46 deletions
|
@ -32,6 +32,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):
|
||||
|
@ -181,10 +203,6 @@ class GeneralFloatCases(unittest.TestCase):
|
|||
|
||||
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.
|
||||
|
@ -206,45 +224,29 @@ class GeneralFloatCases(unittest.TestCase):
|
|||
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'):
|
||||
|
@ -277,6 +279,37 @@ class GeneralFloatCases(unittest.TestCase):
|
|||
self.assertEqual(float(u), 2.5)
|
||||
self.assertEqual(u.newarg, 3)
|
||||
|
||||
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())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue