New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
float() can return not exact float instance #71170
Comments
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'> |
Proposed patch makes float() always returning exact float. |
+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). |
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__. |
Agreed; that matches my understanding. I'm only observing that it would be difficult (and likely undesirable) to actually enforce that 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 |
Here is updated patch. Differences:
Could you propose better warning message? |
Can you please attach the new patch? |
Oh, sorry, how could I miss it? |
Ping. |
float_exact2.patch LGTM |
New changeset 050e5f803999 by Serhiy Storchaka in branch 'default': |
Thank you for your review Mark. |
test_format resulted in semi-failure due to this change. The attached patch fixes the issue. |
New changeset 6216fb8afa53 by Serhiy Storchaka in branch 'default': |
My failure. Thank you for your report and patch SilentGhost. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: