msg265191 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2016-05-09 13:46 |
The float constructor can return an instance of float subclass. >>> class FloatSubclass(float): ... pass ... >>> class BadFloat: ... def __float__(self): ... return FloatSubclass(1.2) ... >>> type(float(BadFloat())) <class '__main__.FloatSubclass'> Comparing with other types, complex() always returns complex: >>> class ComplexSubclass(complex): ... pass ... >>> class BadComplex: ... def __complex__(self): ... return ComplexSubclass(1.2, 3.4) ... >>> type(complex(BadComplex())) <class 'complex'> And int() can return an instance of int subclass, but this behavior is deprecated: >>> class BadInt: ... def __int__(self): ... return True ... >>> int(BadInt()) __main__:1: DeprecationWarning: __int__ returned non-int (type bool). The ability to return an instance of a strict subclass of int is deprecated, and may be removed in a future version of Python. True May be we should either deprecate __float__ returning non-float (as for int), or convert the result to exact float (as for complex). The constructor of float subclass always returns an instance of correct type. >>> class FloatSubclass2(float): ... pass ... >>> type(FloatSubclass2(BadFloat())) <class '__main__.FloatSubclass2'> |
|
|
msg265267 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2016-05-10 19:08 |
Proposed patch makes float() always returning exact float. |
|
|
msg265295 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2016-05-11 08:05 |
+1 for the idea, and the patch LGTM. I was initially a bit confused by the wording of the warning: presumably, we're not going to change Python to make returning an instance of a strict float subclass from __float__ illegal (I don't really see how that would be possible); we're just going to check the return type at the internal call sites to __float__ and raise if we get something other than an exact float. That is, I'd still expect this code to work on future versions of Python: >>> class MyFloat(float): pass ... >>> class A: ... def __float__(self): return MyFloat() ... >>> a = A() >>> a.__float__() 0.0 But these would both become an error in Python 3.7 (say): >>> float(a) 0.0 >>> math.sqrt(a) 0.0 Does that match your thinking? We should probably add issues for checking and fixing other places that __float__ is used internally (like the math module). |
|
|
msg265297 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2016-05-11 08:59 |
The warning message is copied from __int__. As I understand, the conclusion of the Python-Dev discussion is that __int__, __float__, __complex__, etc should return exact int, float, complex, not subclasses. I have another patch that adds a warning for __complex__, and I am working on patches for other special methods. If my understanding is wrong, we should remove the deprecation warning for __int__. |
|
|
msg265298 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2016-05-11 09:45 |
> As I understand, the conclusion of the Python-Dev discussion is that __int__, __float__, __complex__, etc should return exact int, float, complex, not subclasses. Agreed; that matches my understanding. I'm only observing that it would be difficult (and likely undesirable) to actually enforce that `__int__` itself always returns an exact int: I'm not sure where that check would/could take place, and I'd expect that a direct user-level call to `my_object.__int__` probably wouldn't be subject to such a check. What we *can* do is check that the result of the `nb_int` call is always an int in the places we use it. Or we could even go further, and write custom slot_nb_float and slot_nb_int functions in Objects/typeobject.c that incorporates those checks. What I don't think we can do is check that a *direct* call to `__int__` or `__float__` always returns something of the exact type. |
|
|
msg265299 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2016-05-11 10:20 |
Here is updated patch. Differences: * Deprecation warning is now emitted in functions accepting floats (like math.sqrt). * Improved error messages. Now reported wrong type name and a type of wrong __float__ method. * float() now returns the same object for exact float argument. Could you propose better warning message? |
|
|
msg265316 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2016-05-11 14:05 |
Can you please attach the new patch? |
|
|
msg265318 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2016-05-11 14:54 |
Oh, sorry, how could I miss it? |
|
|
msg267096 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2016-06-03 12:27 |
Ping. |
|
|
msg267101 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2016-06-03 14:11 |
float_exact2.patch LGTM |
|
|
msg267129 - (view) |
Author: Roundup Robot (python-dev)  |
Date: 2016-06-03 18:43 |
New changeset 050e5f803999 by Serhiy Storchaka in branch 'default': Issue #26983: float() now always return an instance of exact float. https://hg.python.org/cpython/rev/050e5f803999 |
|
|
msg267130 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2016-06-03 18:44 |
Thank you for your review Mark. |
|
|
msg267521 - (view) |
Author: SilentGhost (SilentGhost) *  |
Date: 2016-06-06 08:08 |
test_format resulted in semi-failure due to this change. The attached patch fixes the issue. |
|
|
msg267523 - (view) |
Author: Roundup Robot (python-dev)  |
Date: 2016-06-06 10:00 |
New changeset 6216fb8afa53 by Serhiy Storchaka in branch 'default': Issue #26983: Fixed test_format failure. https://hg.python.org/cpython/rev/6216fb8afa53 |
|
|
msg267524 - (view) |
Author: Serhiy Storchaka (serhiy.storchaka) *  |
Date: 2016-06-06 10:01 |
My failure. Thank you for your report and patch SilentGhost. |
|
|