msg205647 - (view) |
Author: João Bernardo (JBernardo) * |
Date: 2013-12-09 04:24 |
From the docs for built-in function "round":
"If ndigits is omitted, it defaults to zero"
(http://docs.python.org/3/library/functions.html#round)
But, the only way to get an integer from `round` is by not having the second argument (ndigits):
>>> round(3.5)
4
>>> round(3.5, 1)
3.5
>>> round(3.5, 0)
4.0
>>> round(3.5, -1)
0.0
>>> round(3.5, None)
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
round(3.5, None)
TypeError: 'NoneType' object cannot be interpreted as an integer
Either the docs are wrong or the behavior is wrong. I think it's easier to fix the former...
But also there should be a way to make round return an integer (e.g. passing `None` as 2nd argument)
|
msg205650 - (view) |
Author: Vajrasky Kok (vajrasky) * |
Date: 2013-12-09 06:52 |
Here is the preliminary patch.
After patch:
round(1.23, 0) => 1 not 1.0
round(4.67, 0) => 5 not 5.0
|
msg205651 - (view) |
Author: Mark Dickinson (mark.dickinson) * |
Date: 2013-12-09 08:30 |
> After patch:
> round(1.23, 0) => 1 not 1.0
> round(4.67, 0) => 5 not 5.0
Please no! Two-argument round should continue to return a float in all cases.
The docs should be fixed.
|
msg205652 - (view) |
Author: Mark Dickinson (mark.dickinson) * |
Date: 2013-12-09 08:32 |
> But also there should be a way to make round return an integer
I don't understand. There's already a way to make round return an integer: don't pass a second argument.
|
msg205653 - (view) |
Author: Vajrasky Kok (vajrasky) * |
Date: 2013-12-09 08:56 |
Okay, here is the patch to fix the doc.
|
msg205682 - (view) |
Author: Mark Dickinson (mark.dickinson) * |
Date: 2013-12-09 12:04 |
Thanks. It's inaccurate to say that a float is returned in general, though: for most builtin numeric types, what's returned has the same type as its input. So rounding a Decimal to two places gives a Decimal on output, etc. (That's already explained in the next paragraph.)
|
msg205683 - (view) |
Author: Mark Dickinson (mark.dickinson) * |
Date: 2013-12-09 12:06 |
How about just removing the mention of 'defaults to zero', and say something like: "if ndigits is omitted, returns the nearest int to its input"
|
msg205695 - (view) |
Author: João Bernardo (JBernardo) * |
Date: 2013-12-09 14:14 |
> I don't understand. There's already a way to make round return an integer: don't pass a second argument.
If this function were to be written in Python, it would be something like:
def round(number, ndigits=0):
...
or
def round(number, ndigits=None):
...
But in C you can forge the signature to whatever you want and parse the arguments accordingly. In Python there's always a way to get the default behavior by passing the default argument, but in C it may not exist (in this case `PyObject *o_ndigits = NULL;`)
So, I propose the default value being `None`, so this behavior can be achieved using a second argument.
|
msg205699 - (view) |
Author: Vajrasky Kok (vajrasky) * |
Date: 2013-12-09 14:55 |
Here is the updated doc fix.
Anyway, why not round(1.2) -> 1.0 in the first place? Just curious.
|
msg205703 - (view) |
Author: João Bernardo (JBernardo) * |
Date: 2013-12-09 15:25 |
> Anyway, why not round(1.2) -> 1.0 in the first place? Just curious.
It was the behavior on Python 2.x, but somehow when they changed the rounding method to nearest even number this happened... I think it's too late to change back the return type.
|
msg205704 - (view) |
Author: R. David Murray (r.david.murray) * |
Date: 2013-12-09 15:31 |
Do you have any real-world motivating use case for None? Not just theoretical consistency with what a Python version of the function would look like. (I'm not saying we shouldn't consider supporting None as a low priority change, I'm just trying to figure out where you'd ever need it in the real world.)
|
msg205706 - (view) |
Author: João Bernardo (JBernardo) * |
Date: 2013-12-09 15:44 |
Not really. Just consistency:
For the same reason
' foo '.strip(None)
works... To avoid special casing the function call when you already have a variable to hold the argument.
|
msg205708 - (view) |
Author: R. David Murray (r.david.murray) * |
Date: 2013-12-09 16:06 |
Right, but None in that case has real world utility, since you might have the the value in a variable. But you are hardly going to hold int-or-not in a variable, especially a variable that is really about the number of places in the float result...
|
msg205729 - (view) |
Author: Mark Dickinson (mark.dickinson) * |
Date: 2013-12-09 19:07 |
> Anyway, why not round(1.2) -> 1.0 in the first place? Just curious.
All this changed as part of PEP 3141. I wasn't watching Python 3 development closely back then, but I *think* at least part of the motivation was to provide a way to get away from the use of `int` to truncate a float to its integer part: the argument goes that a simple type conversion shouldn't throw away information, and that if you want a transformation from float to int that throws away information you should ask for it explicitly. So `math.trunc` was born as the preferred way to truncate a float to an int, and `math.floor`, `math.ceil` and `round` became alternative float -> int conversion methods. That entailed those functions returning ints.
<off-topic> In the case of `math.floor` and `math.ceil` at least, I think this is regrettable. There are plenty of places where you just want a float -> float floor or ceiling, and Python no longer has a cheap operation for that available: floor as a float-to-float operation is cheap; floor as a float-to-long-integer operation is significantly more costly.
In the case of `round`, we still have `round(x, 0)` available as a cheap float->float conversion, so it's less of a problem. And I hardly ever use `trunc`, so I don't care about that case. </off-topic>
|
msg205770 - (view) |
Author: Vajrasky Kok (vajrasky) * |
Date: 2013-12-10 04:42 |
In case we want to add consistency with None ndigits, here is the patch adding support for None value for ndigits parameter.
This one looks like a low-risk addition but since Python 3.4 is in beta phase....
|
msg206162 - (view) |
Author: Terry J. Reedy (terry.reedy) * |
Date: 2013-12-14 02:18 |
The docstring is better than the current doc as it says that the default precision is 0, without calling that the default for ndigits.
''' round(number[, ndigits]) -> number
Round a number to a given precision in decimal digits (default 0 digits).
This returns an int when called with one argument, otherwise the
same type as the number. ndigits may be negative.'''
---
Sidenote: To write round in Python, one could easily write
_sentinel = object
def round(number, ndigits=_sentinel):
if ndigits is _sentinel: ...
which makes ndigits positional-or-keyword, and almost optional-with-no-default, as _sentinel is close enough to being a default that cannot be passed in. This is a standard idiom. One who was really picky about having no default could use
def round(number, *args, **kwds): ...
and look for len(args) == 1 xor kwds.keys() == {'ndigits'}.
|
msg241152 - (view) |
Author: Roundup Robot (python-dev) |
Date: 2015-04-15 20:16 |
New changeset e3cc75b1000b by Steve Dower in branch 'default':
Issue 19933: Provide default argument for ndigits in round. Patch by Vajrasky Kok.
https://hg.python.org/cpython/rev/e3cc75b1000b
|
|
Date |
User |
Action |
Args |
2022-04-11 14:57:55 | admin | set | github: 64132 |
2015-04-15 20:16:44 | steve.dower | set | status: open -> closed resolution: fixed versions:
+ Python 3.5, - Python 3.4 |
2015-04-15 20:16:20 | python-dev | set | nosy:
+ python-dev messages:
+ msg241152
|
2013-12-14 02:18:07 | terry.reedy | set | nosy:
+ terry.reedy messages:
+ msg206162
|
2013-12-10 04:42:34 | vajrasky | set | files:
+ fix_doc_ndigits_round_and_add_None_ndigits.patch
messages:
+ msg205770 |
2013-12-09 19:07:00 | mark.dickinson | set | messages:
+ msg205729 |
2013-12-09 16:06:47 | r.david.murray | set | messages:
+ msg205708 |
2013-12-09 15:44:54 | JBernardo | set | messages:
+ msg205706 |
2013-12-09 15:31:59 | r.david.murray | set | nosy:
+ r.david.murray messages:
+ msg205704
|
2013-12-09 15:25:04 | JBernardo | set | messages:
+ msg205703 |
2013-12-09 14:55:18 | vajrasky | set | files:
+ fix_doc_round_ndigits_v2.patch
messages:
+ msg205699 |
2013-12-09 14:14:09 | JBernardo | set | messages:
+ msg205695 |
2013-12-09 12:06:37 | mark.dickinson | set | messages:
+ msg205683 |
2013-12-09 12:04:29 | mark.dickinson | set | messages:
+ msg205682 |
2013-12-09 08:58:06 | vajrasky | set | files:
+ fix_doc_round_ndigits.patch |
2013-12-09 08:57:58 | vajrasky | set | files:
- fix_doc_round_ndigits.patch |
2013-12-09 08:57:22 | vajrasky | set | files:
+ fix_doc_round_ndigits.patch |
2013-12-09 08:57:09 | vajrasky | set | files:
- fix_doc_round_ndigits.patch |
2013-12-09 08:56:39 | vajrasky | set | files:
+ fix_doc_round_ndigits.patch
messages:
+ msg205653 |
2013-12-09 08:32:07 | mark.dickinson | set | messages:
+ msg205652 |
2013-12-09 08:30:47 | mark.dickinson | set | messages:
+ msg205651 |
2013-12-09 06:53:13 | vajrasky | set | nosy:
+ mark.dickinson
|
2013-12-09 06:52:30 | vajrasky | set | files:
+ fix_round_with_zero_ndigits.patch
nosy:
+ vajrasky messages:
+ msg205650
keywords:
+ patch |
2013-12-09 04:24:20 | JBernardo | create | |