msg274205 - (view) |
Author: Jonatan Skogsfors (Jonatan Skogsfors) |
Date: 2016-09-02 06:52 |
Theo error handling for round is different for float and int. Python 3.5.1 (default, Apr 18 2016, 11:46:32) [GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.29)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> round(1.0, None) 1 >>> round(1, None) Traceback (most recent call last): File "", line 1, in TypeError: 'NoneType' object cannot be interpreted as an integer |
|
|
msg274208 - (view) |
Author: Raymond Hettinger (rhettinger) *  |
Date: 2016-09-02 08:13 |
The different data types make different choices: >>> from decimal import Decimal >>> from fractions import Fraction >>> (1).__round__(None) Traceback (most recent call last): File "<pyshell#39>", line 1, in (1).__round__(None) TypeError: 'NoneType' object cannot be interpreted as an integer >>> (1.0).__round__(None) 1 >>> Decimal(1).__round__(None) Traceback (most recent call last): File "<pyshell#41>", line 1, in Decimal(1).__round__(None) TypeError: optional arg must be an integer >>> Fraction(1, 1).__round__(None) 1 >>> from _pydecimal import Decimal >>> Decimal(1).__round__(None) 1 For Fraction and _pydecimal, the behavior comes from using None as a placeholder (which is common and normal in pure python code). For float there is explicit code to test for the None case. For int, the None test was omitted (perhaps a mistake) and the error is raised by PyNumber_Index. Looking through tests, only Lib/test/test_float.py tests for None being allowable. Elsewhere, it seems to be an implementation detail. The old Python 2 version of the round() function never let None be passed in (because it used PyArg_ParseTupleAndKeywords(args, kwds, "d|i:round"). That logic seems to get lost in the Python 3 version when __round__ was introduced. To resolve the differences, I think the round() function should explicitly check for None and replace it with zero before calling the underling __round__ functions where we would allow variable according the needs of the implementation. |
|
|
msg274212 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2016-09-02 08:50 |
> I think the round() function should explicitly check for None and replace it with zero That would be a change in behaviour: `round(x)` is not the same as `round(x, 0)`. For most types, `round(x)` returns an `int`, while `round(x, 0)` returns something of the same type as `x`. Instead, I think we should add the check for `None` to `int`s `__round__` implementation. >>> round(1.3, 0) 1.0 >>> round(1.3) 1 >>> round(1.3, None) 1 |
|
|
msg274213 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2016-09-02 08:52 |
Ah, sorry; now that I've looked at the patch, I see I misunderstood. You're not replacing None with zero; you're replacing it with NULL. Patch LGTM. |
|
|
msg274214 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2016-09-02 08:55 |
The test could be strengthened to add a check that the types of `round(x)` and `round(x, None)` match. |
|
|
msg274265 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2016-09-02 17:44 |
For the record, the float behaviour was changed (for Python 3.5) in http://bugs.python.org/issue19933. There didn't seem to be any particularly strong motivation for that change, but it's done now. |
|
|
msg274289 - (view) |
Author: Roundup Robot (python-dev)  |
Date: 2016-09-03 08:55 |
New changeset c3c4d8e4ca1a by Raymond Hettinger in branch '3.5': Issue 27936: Fix inconsistent round() behavior between float and int https://hg.python.org/cpython/rev/c3c4d8e4ca1a |
|
|
msg274376 - (view) |
Author: Roundup Robot (python-dev)  |
Date: 2016-09-04 18:29 |
New changeset 7108f2a708c9 by Raymond Hettinger in branch '3.5': Issue 27936: Update doc for round() to indicate that None is an allowable argument. https://hg.python.org/cpython/rev/7108f2a708c9 |
|
|