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 is missing __ceil__() and __floor__(), required by numbers.Real #82810
Comments
The numbers.Real ABC requires the __ceil__ and __floor__ methods (https://github.com/python/cpython/blob/v3.8.0/Lib/numbers.py#L178-L186), however, the float type does not have them. In regular Python, this is not a problem, because math.ceil() and math.floor() special-case float and work on it directly, and numbers.Real is implemented on float by explicitly registering it (so it's not checked that all required methods are implemented). Where it becomes a (minor) problem is in typeshed, where the type checker *does* check that all abstract methods are implemented. So, because float is missing these two, typeshed cannot have float implement numbers.Real. Refs: python/typeshed#3195 |
Ran, do you want to work on this or can i take it? |
You can take it - thanks! |
If float.__ceil__ is only needed for typeshed, maybe add a special case for typeshed? I have doubts about adding a C code which is never even executed. |
My reading of the PR is that it *would* be executed: the math module first looks for the __floor__ special method, then falls back to using the libm floor if that doesn't exist. Am I missing something? |
Oh, you are right. I misunderstood the original issue and thought that the code first checks PyFloat_Check() or PyFloat_CheckExact(). If float.__ceil__ will be executed it will add significant overhead for creating and executing the method object. |
Yes, I'd definitely like to see timings; I think Victor already asked for those on the PR. |
$ ./python -m pyperf timeit -s "from math import floor" --duplicate 100 "floor(12345.6)"
Before: Mean +- std dev: 52.5 ns +- 2.6 ns
After: Mean +- std dev: 71.0 ns +- 1.7 ns
$ ./python -m pyperf timeit -s "from math import ceil" --duplicate 100 "ceil(12345.6)"
Before: Mean +- std dev: 51.2 ns +- 1.5 ns
After: Mean +- std dev: 74.4 ns +- 2.2 ns |
However, this is an instance of a general problem: whenever we want to strongly type (via dunders) protocols that specialcase builtin types, we will have to choose between three options:
Do we have a preference for a "default" position when we encounter such problems in the future? Of course, we can override it on a case-by-case basis in the presence of good arguments, but still, a default would be nice to have. I don't know much about static typing (which is why I loved Python until this typing craze happened:), but it seems to me that we might have another option: we can currently say that a type might be a virtual subclass of an abstract class in more than one way, right? For example, we still support old-style iterators (via __getitem__ and IndexError), IIRC. So, can we say that a type can implement numbers.Real also in two ways: by having some dunders, or by being (a literal or a subtype of) float? |
Thanks Batuhan Taşkaya for the implementation, and thanks Ran Benita for the feature request :-) |
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: