10000 bpo-44258: support PEP 515 for Fraction's initialization from string by skirpichev · Pull Request #26422 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-44258: support PEP 515 for Fraction's initialization from string #26422

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 7, 2021
Prev Previous commit
Next Next commit
regexps's version
  • Loading branch information
skirpichev committed May 28, 2021
commit 8c96355b0916b227434efa3c333ac1b483df9f7b
68 changes: 32 additions & 36 deletions Lib/fractions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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[_\d]*))? # an optional denominator
| # or
(?:\.(?P<decimal>[_\d]*))? # an optional fractional part
(?:E(?P<exp>[-+]?[_\d]+))? # and optional exponent
\A\s* # optional whitespace at the start,
(?P<sign>[-+]?) # an optional sign, then
(?=\d|\.\d) # lookahead for digit or .digit
(?P<num>((\d+_?)*\d|\d*)) # numerator (possibly empty)
(?: # followed by
(?:/(?P<den>(\d+_?)*\d+))? # an optional denominator
| # or
(?:\.(?P<decimal>((\d+_?)*\d|\d*)))? # an optional fractional part
(?:E(?P<exp>[-+]?(\d+_?)*\d+))? # and optional exponent
)
\s*\Z # and optional whitespace to finish
\s*\Z # and optional whitespace to finish
""", re.VERBOSE | re.IGNORECASE)


Expand Down Expand Up @@ -114,32 +114,28 @@ def __new__(cls, numerator=0, denominator=None, *, _normalize=True):
if m is None:
raise ValueError('Invalid literal for Fraction: %r' %
numerator)
try:
numerator_copy = numerator
numerator = int(m.group('num') or '0')
denom = m.group('denom')
if denom:
denominator = int(denom)
else:
denominator = 1
decimal = m.group('decimal')
if decimal:
decimal = int(decimal)
scale = 10**len(str(decimal))
numerator = numerator * scale + decimal
denominator *= scale
exp = m.group('exp')
if exp:
exp = int(exp)
if exp >= 0:
numerator *= 10**exp
else:
denominator *= 10**-exp
if m.group('sign') == '-':
numerator = -numerator
except ValueError:
raise ValueError('Invalid literal for Fraction: %r' %
numerator_copy)
numerator = int(m.group('num') or '0')
denominator = m.group('den')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest reverting this set of changes; IIUC they're not needed for this PR, and I don't see any particular advantage to the rename. (In fact, I prefer the version where we don't have the same local name referring to both a string and an int.)

Copy link
Contributor Author
@skirpichev skirpichev May 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any particular advantage to the rename.

Naming of patterns seems to be more consistent in this case: num/den vs num/denom.

But you are right, this is not related to the PR. I'll revert.

I prefer the version where we don't have the same local name referring to both a string and an int

I don't think there are. We have den/denom for strings and denominator - which is an integer.

This patch may be better:

diff --git a/Lib/fractions.py b/Lib/fractions.py
index 180cd94c28..1268b6bd27 100644
--- a/Lib/fractions.py
+++ b/Lib/fractions.py
@@ -26,7 +26,7 @@
     (?=\d|\.\d)                           # lookahead for digit or .digit
     (?P<num>\d*|\d+(_\d+)*)               # numerator (possibly empty)
     (?:                                   # followed by
-       (?:/(?P<denom>\d+(_\d+)*))?        # an optional denominator
+       (?:/(?P<den>\d+(_\d+)*))?          # an optional denominator
     |                                     # or
        (?:\.(?P<decimal>d*|\d+(_\d+)*))?  # an optional fractional part
        (?:E(?P<exp>[-+]?\d+(_\d+)*))?     # and optional exponent
@@ -115,9 +115,9 @@ def __new__(cls, numerator=0, denominator=None, *, _normalize=True):
                     raise ValueError('Invalid literal for Fraction: %r' %
                                      numerator)
                 numerator = int(m.group('num') or '0')
-                denom = m.group('denom')
-                if denom:
-                    denominator = int(denom)
+                den = m.group('den')
+                if den:
+                    denominator = int(den)
                 else:
                     denominator = 1
                     decimal = m.group('decimal')

if denominator:
denominator = int(denominator)
else:
denominator = 1
decimal = m.group('decimal')
if decimal:
decimal = int(decimal)
scale = 10**len(str(decimal))
numerator = numerator * scale + decimal
denominator *= scale
exp = m.group('exp')
if exp:
exp = int(exp)
if exp >= 0:
numerator *= 10**exp
else:
denominator *= 10**-exp
if m.group('sign') == '-':
numerator = -numerator

else:
raise TypeError("argument should be a string "
"or a Rational instance")
Expand Down
0