Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
1ddf1d84
Kaydet (Commit)
1ddf1d84
authored
Şub 29, 2008
tarafından
Mark Dickinson
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Add __format__ method to Decimal, to support PEP 3101
üst
b4cbc98c
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
335 additions
and
0 deletions
+335
-0
decimal.py
Lib/decimal.py
+240
-0
test_decimal.py
Lib/test/test_decimal.py
+93
-0
NEWS
Misc/NEWS
+2
-0
No files found.
Lib/decimal.py
Dosyayı görüntüle @
1ddf1d84
...
...
@@ -2380,6 +2380,29 @@ class Decimal(object):
coeff
=
str
(
int
(
coeff
)
+
1
)
return
_dec_from_triple
(
self
.
_sign
,
coeff
,
exp
)
def
_round
(
self
,
places
,
rounding
):
"""Round a nonzero, nonspecial Decimal to a fixed number of
significant figures, using the given rounding mode.
Infinities, NaNs and zeros are returned unaltered.
This operation is quiet: it raises no flags, and uses no
information from the context.
"""
if
places
<=
0
:
raise
ValueError
(
"argument should be at least 1 in _round"
)
if
self
.
_is_special
or
not
self
:
return
Decimal
(
self
)
ans
=
self
.
_rescale
(
self
.
adjusted
()
+
1
-
places
,
rounding
)
# it can happen that the rescale alters the adjusted exponent;
# for example when rounding 99.97 to 3 significant figures.
# When this happens we end up with an extra 0 at the end of
# the number; a second rescale fixes this.
if
ans
.
adjusted
()
!=
self
.
adjusted
():
ans
=
ans
.
_rescale
(
ans
.
adjusted
()
+
1
-
places
,
rounding
)
return
ans
def
to_integral_exact
(
self
,
rounding
=
None
,
context
=
None
):
"""Rounds to a nearby integer.
...
...
@@ -3431,6 +3454,95 @@ class Decimal(object):
return
self
# My components are also immutable
return
self
.
__class__
(
str
(
self
))
# PEP 3101 support. See also _parse_format_specifier and _format_align
def
__format__
(
self
,
specifier
,
context
=
None
):
"""Format a Decimal class according to the given specifier.
The specifier should be a standard format specifier, with the
form described in PEP 3101. Formatting types 'e', 'E', 'f',
'F', 'g', 'G', and '
%
' are supported. If the formatting type
is omitted it defaults to 'g' or 'G', depending on the value
of context.capitals.
At this time the 'n' format specifier type (which is supposed
to use the current locale) is not supported.
"""
# Note: PEP 3101 says that if the type is not present then
# there should be at least one digit after the decimal point.
# We take the liberty of ignoring this requirement for
# Decimal---it's presumably there to make sure that
# format(float, '') behaves similarly to str(float).
if
context
is
None
:
context
=
getcontext
()
spec
=
_parse_format_specifier
(
specifier
)
# special values don't care about the type or precision...
if
self
.
_is_special
:
return
_format_align
(
str
(
self
),
spec
)
# a type of None defaults to 'g' or 'G', depending on context
# if type is '%', adjust exponent of self accordingly
if
spec
[
'type'
]
is
None
:
spec
[
'type'
]
=
[
'g'
,
'G'
][
context
.
capitals
]
elif
spec
[
'type'
]
==
'
%
'
:
self
=
_dec_from_triple
(
self
.
_sign
,
self
.
_int
,
self
.
_exp
+
2
)
# round if necessary, taking rounding mode from the context
rounding
=
context
.
rounding
precision
=
spec
[
'precision'
]
if
precision
is
not
None
:
if
spec
[
'type'
]
in
'eE'
:
self
=
self
.
_round
(
precision
+
1
,
rounding
)
elif
spec
[
'type'
]
in
'gG'
:
if
len
(
self
.
_int
)
>
precision
:
self
=
self
.
_round
(
precision
,
rounding
)
elif
spec
[
'type'
]
in
'fF
%
'
:
self
=
self
.
_rescale
(
-
precision
,
rounding
)
# special case: zeros with a positive exponent can't be
# represented in fixed point; rescale them to 0e0.
elif
not
self
and
self
.
_exp
>
0
and
spec
[
'type'
]
in
'fF
%
'
:
self
=
self
.
_rescale
(
0
,
rounding
)
# figure out placement of the decimal point
leftdigits
=
self
.
_exp
+
len
(
self
.
_int
)
if
spec
[
'type'
]
in
'fF
%
'
:
dotplace
=
leftdigits
elif
spec
[
'type'
]
in
'eE'
:
if
not
self
and
precision
is
not
None
:
dotplace
=
1
-
precision
else
:
dotplace
=
1
elif
spec
[
'type'
]
in
'gG'
:
if
self
.
_exp
<=
0
and
leftdigits
>
-
6
:
dotplace
=
leftdigits
else
:
dotplace
=
1
# figure out main part of numeric string...
if
dotplace
<=
0
:
num
=
'0.'
+
'0'
*
(
-
dotplace
)
+
self
.
_int
elif
dotplace
>=
len
(
self
.
_int
):
# make sure we're not padding a '0' with extra zeros on the right
assert
dotplace
==
len
(
self
.
_int
)
or
self
.
_int
!=
'0'
num
=
self
.
_int
+
'0'
*
(
dotplace
-
len
(
self
.
_int
))
else
:
num
=
self
.
_int
[:
dotplace
]
+
'.'
+
self
.
_int
[
dotplace
:]
# ...then the trailing exponent, or trailing '%'
if
leftdigits
!=
dotplace
or
spec
[
'type'
]
in
'eE'
:
echar
=
{
'E'
:
'E'
,
'e'
:
'e'
,
'G'
:
'E'
,
'g'
:
'e'
}[
spec
[
'type'
]]
num
=
num
+
"{0}{1:+}"
.
format
(
echar
,
leftdigits
-
dotplace
)
elif
spec
[
'type'
]
==
'
%
'
:
num
=
num
+
'
%
'
# add sign
if
self
.
_sign
==
1
:
num
=
'-'
+
num
return
_format_align
(
num
,
spec
)
def
_dec_from_triple
(
sign
,
coefficient
,
exponent
,
special
=
False
):
"""Create a decimal instance directly, without any validation,
normalization (e.g. removal of leading zeros) or argument
...
...
@@ -5250,8 +5362,136 @@ _parser = re.compile(r""" # A numeric string consists of:
_all_zeros
=
re
.
compile
(
'0*$'
)
.
match
_exact_half
=
re
.
compile
(
'50*$'
)
.
match
##### PEP3101 support functions ##############################################
# The functions parse_format_specifier and format_align have little to do
# with the Decimal class, and could potentially be reused for other pure
# Python numeric classes that want to implement __format__
#
# A format specifier for Decimal looks like:
#
# [[fill]align][sign][0][minimumwidth][.precision][type]
#
_parse_format_specifier_regex
=
re
.
compile
(
r"""\A
(?:
(?P<fill>.)?
(?P<align>[<>=^])
)?
(?P<sign>[-+ ])?
(?P<zeropad>0)?
(?P<minimumwidth>(?!0)\d+)?
(?:\.(?P<precision>0|(?!0)\d+))?
(?P<type>[eEfFgG
%
])?
\Z
"""
,
re
.
VERBOSE
)
del
re
def
_parse_format_specifier
(
format_spec
):
"""Parse and validate a format specifier.
Turns a standard numeric format specifier into a dict, with the
following entries:
fill: fill character to pad field to minimum width
align: alignment type, either '<', '>', '=' or '^'
sign: either '+', '-' or ' '
minimumwidth: nonnegative integer giving minimum width
precision: nonnegative integer giving precision, or None
type: one of the characters 'eEfFgG
%
', or None
unicode: either True or False (always True for Python 3.x)
"""
m
=
_parse_format_specifier_regex
.
match
(
format_spec
)
if
m
is
None
:
raise
ValueError
(
"Invalid format specifier: "
+
format_spec
)
# get the dictionary
format_dict
=
m
.
groupdict
()
# defaults for fill and alignment
fill
=
format_dict
[
'fill'
]
align
=
format_dict
[
'align'
]
if
format_dict
.
pop
(
'zeropad'
)
is
not
None
:
# in the face of conflict, refuse the temptation to guess
if
fill
is
not
None
and
fill
!=
'0'
:
raise
ValueError
(
"Fill character conflicts with '0'"
" in format specifier: "
+
format_spec
)
if
align
is
not
None
and
align
!=
'='
:
raise
ValueError
(
"Alignment conflicts with '0' in "
"format specifier: "
+
format_spec
)
fill
=
'0'
align
=
'='
format_dict
[
'fill'
]
=
fill
or
' '
format_dict
[
'align'
]
=
align
or
'<'
if
format_dict
[
'sign'
]
is
None
:
format_dict
[
'sign'
]
=
'-'
# turn minimumwidth and precision entries into integers.
# minimumwidth defaults to 0; precision remains None if not given
format_dict
[
'minimumwidth'
]
=
int
(
format_dict
[
'minimumwidth'
]
or
'0'
)
if
format_dict
[
'precision'
]
is
not
None
:
format_dict
[
'precision'
]
=
int
(
format_dict
[
'precision'
])
# if format type is 'g' or 'G' then a precision of 0 makes little
# sense; convert it to 1. Same if format type is unspecified.
if
format_dict
[
'precision'
]
==
0
:
if
format_dict
[
'type'
]
in
'gG'
or
format_dict
[
'type'
]
is
None
:
format_dict
[
'precision'
]
=
1
# record whether return type should be str or unicode
format_dict
[
'unicode'
]
=
isinstance
(
format_spec
,
unicode
)
return
format_dict
def
_format_align
(
body
,
spec_dict
):
"""Given an unpadded, non-aligned numeric string, add padding and
aligment to conform with the given format specifier dictionary (as
output from parse_format_specifier).
It's assumed that if body is negative then it starts with '-'.
Any leading sign ('-' or '+') is stripped from the body before
applying the alignment and padding rules, and replaced in the
appropriate position.
"""
# figure out the sign; we only examine the first character, so if
# body has leading whitespace the results may be surprising.
if
len
(
body
)
>
0
and
body
[
0
]
in
'-+'
:
sign
=
body
[
0
]
body
=
body
[
1
:]
else
:
sign
=
''
if
sign
!=
'-'
:
if
spec_dict
[
'sign'
]
in
' +'
:
sign
=
spec_dict
[
'sign'
]
else
:
sign
=
''
# how much extra space do we have to play with?
minimumwidth
=
spec_dict
[
'minimumwidth'
]
fill
=
spec_dict
[
'fill'
]
padding
=
fill
*
(
max
(
minimumwidth
-
(
len
(
sign
+
body
)),
0
))
align
=
spec_dict
[
'align'
]
if
align
==
'<'
:
result
=
padding
+
sign
+
body
elif
align
==
'>'
:
result
=
sign
+
body
+
padding
elif
align
==
'='
:
result
=
sign
+
padding
+
body
else
:
#align == '^'
half
=
len
(
padding
)
//
2
result
=
padding
[:
half
]
+
sign
+
body
+
padding
[
half
:]
# make sure that result is unicode if necessary
if
spec_dict
[
'unicode'
]:
result
=
unicode
(
result
)
return
result
##### Useful Constants (internal use only) ################################
...
...
Lib/test/test_decimal.py
Dosyayı görüntüle @
1ddf1d84
...
...
@@ -615,6 +615,98 @@ class DecimalImplicitConstructionTest(unittest.TestCase):
self
.
assertEqual
(
eval
(
'Decimal(10)'
+
sym
+
'E()'
),
'10'
+
rop
+
'str'
)
class
DecimalFormatTest
(
unittest
.
TestCase
):
'''Unit tests for the format function.'''
def
test_formatting
(
self
):
# triples giving a format, a Decimal, and the expected result
test_values
=
[
(
'e'
,
'0E-15'
,
'0e-15'
),
(
'e'
,
'2.3E-15'
,
'2.3e-15'
),
(
'e'
,
'2.30E+2'
,
'2.30e+2'
),
# preserve significant zeros
(
'e'
,
'2.30000E-15'
,
'2.30000e-15'
),
(
'e'
,
'1.23456789123456789e40'
,
'1.23456789123456789e+40'
),
(
'e'
,
'1.5'
,
'1.5e+0'
),
(
'e'
,
'0.15'
,
'1.5e-1'
),
(
'e'
,
'0.015'
,
'1.5e-2'
),
(
'e'
,
'0.0000000000015'
,
'1.5e-12'
),
(
'e'
,
'15.0'
,
'1.50e+1'
),
(
'e'
,
'-15'
,
'-1.5e+1'
),
(
'e'
,
'0'
,
'0e+0'
),
(
'e'
,
'0E1'
,
'0e+1'
),
(
'e'
,
'0.0'
,
'0e-1'
),
(
'e'
,
'0.00'
,
'0e-2'
),
(
'.6e'
,
'0E-15'
,
'0.000000e-9'
),
(
'.6e'
,
'0'
,
'0.000000e+6'
),
(
'.6e'
,
'9.999999'
,
'9.999999e+0'
),
(
'.6e'
,
'9.9999999'
,
'1.000000e+1'
),
(
'.6e'
,
'-1.23e5'
,
'-1.230000e+5'
),
(
'.6e'
,
'1.23456789e-3'
,
'1.234568e-3'
),
(
'f'
,
'0'
,
'0'
),
(
'f'
,
'0.0'
,
'0.0'
),
(
'f'
,
'0E-2'
,
'0.00'
),
(
'f'
,
'0.00E-8'
,
'0.0000000000'
),
(
'f'
,
'0E1'
,
'0'
),
# loses exponent information
(
'f'
,
'3.2E1'
,
'32'
),
(
'f'
,
'3.2E2'
,
'320'
),
(
'f'
,
'3.20E2'
,
'320'
),
(
'f'
,
'3.200E2'
,
'320.0'
),
(
'f'
,
'3.2E-6'
,
'0.0000032'
),
(
'.6f'
,
'0E-15'
,
'0.000000'
),
# all zeros treated equally
(
'.6f'
,
'0E1'
,
'0.000000'
),
(
'.6f'
,
'0'
,
'0.000000'
),
(
'.0f'
,
'0'
,
'0'
),
# no decimal point
(
'.0f'
,
'0e-2'
,
'0'
),
(
'.0f'
,
'3.14159265'
,
'3'
),
(
'.1f'
,
'3.14159265'
,
'3.1'
),
(
'.4f'
,
'3.14159265'
,
'3.1416'
),
(
'.6f'
,
'3.14159265'
,
'3.141593'
),
(
'.7f'
,
'3.14159265'
,
'3.1415926'
),
# round-half-even!
(
'.8f'
,
'3.14159265'
,
'3.14159265'
),
(
'.9f'
,
'3.14159265'
,
'3.141592650'
),
(
'g'
,
'0'
,
'0'
),
(
'g'
,
'0.0'
,
'0.0'
),
(
'g'
,
'0E1'
,
'0e+1'
),
(
'G'
,
'0E1'
,
'0E+1'
),
(
'g'
,
'0E-5'
,
'0.00000'
),
(
'g'
,
'0E-6'
,
'0.000000'
),
(
'g'
,
'0E-7'
,
'0e-7'
),
(
'g'
,
'-0E2'
,
'-0e+2'
),
(
'.0g'
,
'3.14159265'
,
'3'
),
# 0 sig fig -> 1 sig fig
(
'.1g'
,
'3.14159265'
,
'3'
),
(
'.2g'
,
'3.14159265'
,
'3.1'
),
(
'.5g'
,
'3.14159265'
,
'3.1416'
),
(
'.7g'
,
'3.14159265'
,
'3.141593'
),
(
'.8g'
,
'3.14159265'
,
'3.1415926'
),
# round-half-even!
(
'.9g'
,
'3.14159265'
,
'3.14159265'
),
(
'.10g'
,
'3.14159265'
,
'3.14159265'
),
# don't pad
(
'
%
'
,
'0E1'
,
'0
%
'
),
(
'
%
'
,
'0E0'
,
'0
%
'
),
(
'
%
'
,
'0E-1'
,
'0
%
'
),
(
'
%
'
,
'0E-2'
,
'0
%
'
),
(
'
%
'
,
'0E-3'
,
'0.0
%
'
),
(
'
%
'
,
'0E-4'
,
'0.00
%
'
),
(
'.3
%
'
,
'0'
,
'0.000
%
'
),
# all zeros treated equally
(
'.3
%
'
,
'0E10'
,
'0.000
%
'
),
(
'.3
%
'
,
'0E-10'
,
'0.000
%
'
),
(
'.3
%
'
,
'2.34'
,
'234.000
%
'
),
(
'.3
%
'
,
'1.234567'
,
'123.457
%
'
),
(
'.0
%
'
,
'1.23'
,
'123
%
'
),
(
'e'
,
'NaN'
,
'NaN'
),
(
'f'
,
'-NaN123'
,
'-NaN123'
),
(
'+g'
,
'NaN456'
,
'+NaN456'
),
(
'.3e'
,
'Inf'
,
'Infinity'
),
(
'.16f'
,
'-Inf'
,
'-Infinity'
),
(
'.0g'
,
'-sNaN'
,
'-sNaN'
),
(
''
,
'1.00'
,
'1.00'
),
]
for
fmt
,
d
,
result
in
test_values
:
self
.
assertEqual
(
format
(
Decimal
(
d
),
fmt
),
result
)
class
DecimalArithmeticOperatorsTest
(
unittest
.
TestCase
):
'''Unit tests for all arithmetic operators, binary and unary.'''
...
...
@@ -1363,6 +1455,7 @@ def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
DecimalExplicitConstructionTest
,
DecimalImplicitConstructionTest
,
DecimalArithmeticOperatorsTest
,
DecimalFormatTest
,
DecimalUseOfContextTest
,
DecimalUsabilityTest
,
DecimalPythonAPItests
,
...
...
Misc/NEWS
Dosyayı görüntüle @
1ddf1d84
...
...
@@ -441,6 +441,8 @@ Core and builtins
Library
-------
- Add a __format__ method to Decimal, to support PEP 3101.
- Add a timing parameter when using trace.Trace to print out timestamps.
- #1627: httplib now ignores negative Content-Length headers.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment