Skip to content

Improve printf-style formatting docs for non-built-in types #142108

@1nftf

Description

@1nftf

Add a description about how Decimal behaves differently with format and % formatting in https://docs.python.org/3/library/string.html#format-specification-mini-language

For __format__, Decimal is formatted with the highest possible precision as it is.

For % formatting, Decimal is converted to float before formatting.

These behaviors have not changed since they were added.

Compare:

sys.version '%f' % 11111111111111111111.0 '%f' % Decimal('11111111111111111111.0') Decimal('11111111111111111111.0').__format__('f') '%e' % 0.0 '%e' % Decimal('0.0') Decimal('0.0').__format__('e') '%.20e' % 11111111111111111111.0 '%.20e' % Decimal('11111111111111111111.0') Decimal('11111111111111111111.0').__format__('.20e') '%.20g' % 11111111111111111111.0 '%.20g' % Decimal('11111111111111111111.0') Decimal('11111111111111111111.0').__format__('.20g')
'2.4.4 (#71, Oct 18 2006, 08:34:43) [MSC v.1310 32 bit (Intel)]' '11111111111111111000.000000' '11111111111111111000.000000' Exception '0.000000e+000' '0.000000e+000' Exception '1.11111111111111110000e+019' '1.11111111111111110000e+019' Exception '11111111111111111000' '11111111111111111000' Exception
'2.6.6 (r266:84297, Aug 24 2010, 18:13:38) [MSC v.1500 64 bit (AMD64)]' '11111111111111111000.000000' '11111111111111111000.000000' '11111111111111111111.0' '0.000000e+00' '0.000000e+00' '0e-1' '1.11111111111111110000e+19' '1.11111111111111110000e+19' '1.11111111111111111110e+19' '11111111111111111000' '11111111111111111000' '11111111111111111111'
'2.7.18 (v2.7.18:8d21aa21f2, Apr 20 2020, 13:25:05) [MSC v.1500 64 bit (AMD64)]' '11111111111111110656.000000' '11111111111111110656.000000' '11111111111111111111.0' '0.000000e+00' '0.000000e+00' '0e-1' '1.11111111111111106560e+19' '1.11111111111111106560e+19' '1.11111111111111111110e+19' '11111111111111110656' '11111111111111110656' '11111111111111111111'
'3.14.0 (tags/v3.14.0:ebf955d, Oct 7 2025, 10:06:33) [MSC v.1944 32 bit (Intel)]' '11111111111111110656.000000' '11111111111111110656.000000' '11111111111111111111.0' '0.000000e+00' '0.000000e+00' '0e-1' '1.11111111111111106560e+19' '1.11111111111111106560e+19' '1.11111111111111111110e+19' '11111111111111110656' '11111111111111110656' '11111111111111111111'
'3.14.0 (tags/v3.14.0:ebf955d, Oct 7 2025, 10:15:03) [MSC v.1944 64 bit (AMD64)]' '11111111111111110656.000000' '11111111111111110656.000000' '11111111111111111111.0' '0.000000e+00' '0.000000e+00' '0e-1' '1.11111111111111106560e+19' '1.11111111111111106560e+19' '1.11111111111111111110e+19' '11111111111111110656' '11111111111111110656' '11111111111111111111'
'3.15.0a2 (tags/v3.15.0a2:a625628, Nov 18 2025, 18:12:01) [MSC v.1944 64 bit (AMD64)]' '11111111111111110656.000000' '11111111111111110656.000000' '11111111111111111111.0' '0.000000e+00' '0.000000e+00' '0e-1' '1.11111111111111106560e+19' '1.11111111111111106560e+19' '1.11111111111111111110e+19' '11111111111111110656' '11111111111111110656' '11111111111111111111'
# ./test.py
import sys
from decimal import Decimal

for expr in (
    "sys.version",

    "'%f' % 12345123451234512345.0",
    "'%f' % Decimal('12345123451234512345.0')",
    "Decimal('12345123451234512345.0').__format__('f')",

    "'%e' % 0.0",
    "'%e' % Decimal('0.0')",
    "Decimal('0.0').__format__('e')",

    "'%.20e' % 12345123451234512345.0",
    "'%.20e' % Decimal('12345123451234512345.0')",
    "Decimal('12345123451234512345.0').__format__('.20e')",

    "'%.20g' % 12345123451234512345.0",
    "'%.20g' % Decimal('12345123451234512345.0')",
    "Decimal('12345123451234512345.0').__format__('.20g')",
):
    print(expr)
    try:
        print(repr(eval(expr)))
    except Exception:
        print('Exception')
    print('')
# ./test_runner.py
from pathlib import Path
from subprocess import run, PIPE

PYTHON_DIR_ROOT = r"C:\python_dir_root"

def print_row(row, file):
    for v in row: print(f"| {v} ", end='', file=file)
    print("|", file=file)

def print_md_table(headers, rows, file):
    print_row(headers, file=file)
    print_row(['---:'] * len(headers), file=file)
    for row in rows: print_row(row, file=file)
    print(file=file)

rows = []
for dir in Path(PYTHON_DIR_ROOT).iterdir():
    out = run([str(dir/"python.exe"), "./test.py"], stdout=PIPE).stdout
    out = out.decode('utf-8').splitlines()
    headers = [f"`{h}`" for h in out[::3]]
    rows.append(out[1::3])

with open("./test_result.md", 'w', encoding='utf-8') as fp:
    print_md_table(headers, rows, file=fp)

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    docsDocumentation in the Doc dir

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions