◐ Shell
reader mode source ↗
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
File filter
Conversations
Jump to
Diff view
Apply and reload
Show whitespace
Diff view
Apply and reload
7 changes: 6 additions & 1 deletion Doc/library/fractions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ another rational number, or from a string.

where the optional ``sign`` may be either '+' or '-' and
``numerator`` and ``denominator`` (if present) are strings of
decimal digits. In addition, any string that represents a finite
value and is accepted by the :class:`float` constructor is also
accepted by the :class:`Fraction` constructor. In either form the
input string may also have leading and/or trailing whitespace.
Expand Down Expand Up @@ -89,6 +90,10 @@ another rational number, or from a string.
and *denominator*. :func:`math.gcd` always return a :class:`int` type.
Previously, the GCD type depended on *numerator* and *denominator*.

.. attribute:: numerator

Numerator of the Fraction in lowest term.
Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.11.rst
Original file line number Diff line number Diff line change
@@ -86,6 +86,11 @@ New Modules
Improved Modules
================


Optimizations
=============
Expand Down
21 changes: 11 additions & 10 deletions Lib/fractions.py
Original file line number Diff line number Diff line change
@@ -21,17 +21,17 @@
_PyHASH_INF = sys.hash_info.inf

_RATIONAL_FORMAT = re.compile(r"""
\A\s* # optional whitespace at the start, then
(?P<sign>[-+]?) # an optional sign, then
(?=\d|\.\d) # lookahead for digit or .digit
(?P<num>\d*) # numerator (possibly empty)
(?: # followed by
(?:/(?P<denom>\d+))? # an optional denominator
| # or
(?:\.(?P<decimal>\d*))? # an optional fractional part
(?:E(?P<exp>[-+]?\d+))? # and optional exponent
)
\s*\Z # and optional whitespace to finish
""", re.VERBOSE | re.IGNORECASE)


Expand Down Expand Up @@ -122,6 +122,7 @@ def __new__(cls, numerator=0, denominator=None, *, _normalize=True):
denominator = 1
decimal = m.group('decimal')
if decimal:
scale = 10**len(decimal)
numerator = numerator * scale + int(decimal)
denominator *= scale
Expand Down
62 changes: 62 additions & 0 deletions Lib/test/test_fractions.py
Original file line number Diff line number Diff line change
@@ -173,6 +173,12 @@ def testFromString(self):
self.assertEqual((-12300, 1), _components(F("-1.23e4")))
self.assertEqual((0, 1), _components(F(" .0e+0\t")))
self.assertEqual((0, 1), _components(F("-0.000e0")))

self.assertRaisesMessage(
ZeroDivisionError, "Fraction(3, 0)",
Expand Down Expand Up @@ -210,6 +216,62 @@ def testFromString(self):
# Allow 3. and .3, but not .
ValueError, "Invalid literal for Fraction: '.'",
F, ".")

def testImmutable(self):
r = F(7, 3)
Expand Down
Toggle all file notes Toggle all file annotations