Repository navigation
Implement __format__ for Fraction #67790
Description
Activity
Since Decimal supports __format__, it would be nice that Fraction did too.
- addedstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
on Mar 7, 2015 Here's a patch that adds Fraction.__format__ implementation, test cases and documentation.
- addedtype-featureA feature request or enhancementA feature request or enhancement
on Mar 7, 2015 >>> from fractions import Fraction as F >>> format(F(1, 3), '.30f') '0.333333333333333333333333333300'
Serhiy Storchaka wrote: >>>> from fractions import Fraction as F >>>> format(F(1, 3), '.30f') > '0.333333333333333333333333333300'
Good catch! I'll try to fix this and add some more test cases.
I'm not sure it needs fixing: it follows from the definition of using Decimal(num) / Decimal(denom). Plus, it's controllable with a decimal context:
>>> from decimal import localcontext >>> with localcontext() as ctx: ... ctx.prec = 100 ... format(F(1, 3), '.30f') ... '0.333333333333333333333333333333' >>>
For all of the tests, I suggest using format(value, str) instead of ''.format(value). It more directly tests Fraction.__format__.
In general I think adding Fraction.__format__ is a good idea, and I think converting to Decimal is reasonable for the specified codes. My only question is what to do when "natively" formatting Fractions themselves. We might want to support field widths, padding, etc.
I’ve never actually used the Fraction class, but I doubt its behaviour should depend on whatever settings are in the current decimal context. Maybe you can extract the precision out of the format string, and base the internal decimal object on that.
Eric V. Smith wrote:
I'm not sure it needs fixing: it follows from the definition of using Decimal(num) / Decimal(denom). Plus, it's controllable with a decimal context:
Hmm... Even though it's tempting to agree with you and just ignore the
precision bug, but to be honest I have to agree with Martin Panter
here. Depending on the current decimal context is not the way of
"Least Surprise" when formatting Fractions.For all of the tests, I suggest using format(value, str) instead of ''.format(value). It more directly tests Fraction.__format__.
I agree. Will change those.
In general I think adding Fraction.__format__ is a good idea, and I think converting to Decimal is reasonable for the specified codes. My only question is what to do when "natively" formatting Fractions themselves. We might want to support field widths, padding, etc.
Thanks! Actually I already tried to support field widths, padding and
such. (See the test cases.) Or what do you mean?Here's the next round of the patch.
For formatting fractions with any given precision I had to parse the precision from format specifier and at this point it seemed easier to just create a general parser for the Format Specification Mini-Language. In this patch it is implemented in fractions._parse_format_specifier function, but maybe this kind of general function should be moved to better place and be documented and exported. What do you think?
Regarding sharing fractions._parse_format_specifier(), perhaps have a look at _pydecimal._parse_format_specifier()
Martin Panter wrote:
Regarding sharing fractions._parse_format_specifier(), perhaps have a look at _pydecimal._parse_format_specifier()
I did find that, but since it was a private function in private
module, I was unsure if I can use it here. The _pydecimal one parser
also does more stuff that I need.Version 3 of the patch. Changes to v2:
- Use raw-strings for the regexps.
- Make the specifier regexp more robust with \A, \Z and re.DOTALL.
- Add more test cases; especially g and e formats and negative fractions.
>>> from fractions import Fraction as F >>> format(F(4, 27), 'f') '0.1481481' >>> format(F(4, 27), '.1f') '0.2'
15 remaining items
I understand double rounding to mean incorrectly rounding something like 0.149999 up to 0.2. It should be rounded once to 1 decimal place (0.1). If you temporarily round it to a higher number of places before rounding to 1 place, you’re doing it wrong. So you might have to ensure that any rounding done before formatting step exactly matches the rounding specified in the formatting.
It wouldn't be too bad if Py and C version of Decimal.__format__ had
same interface. What do you think?Let's discuss that in a separate issue.
[DefaultContext]
I don't understand what do you mean with this. Is this something that
I'm doing wrong in my patch or just another (related?) issue?Decimal.DefaultContext has global scope and currently affects
Context() creation, unless you specify all parameters.Done for float-style formatting in #100161. I'm planning to make a new PR that adds support for the
dpresentation format before closing this issue.- added a commit that references this issue
on Oct 25, 2023 I'm planning to make a new PR that adds support for the
dpresentation format before closing this issue.See #111320.
- added a commit that references this issue
on Dec 16, 2023 @mdickinson, #111320 was merged. From the issue thread it seems one could be closed.
@skirpichev It could indeed! Thanks.
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:
Linked PRs