diff -r 7d90bf4780ff Lib/fractions.py --- a/Lib/fractions.py Mon Aug 22 18:07:02 2016 +0300 +++ b/Lib/fractions.py Tue Aug 23 13:39:40 2016 +0300 @@ -81,7 +81,7 @@ class Fraction(numbers.Rational): __slots__ = ('_numerator', '_denominator') # We're immutable, so use __new__ not __init__ - def __new__(cls, numerator=0, denominator=None, _normalize=True): + def __new__(cls, numerator=0, denominator=None): """Constructs a Rational. Takes a string like '3/2' or '1.5', another Rational instance, a @@ -176,18 +176,16 @@ class Fraction(numbers.Rational): if denominator == 0: raise ZeroDivisionError('Fraction(%s, 0)' % numerator) - if _normalize: - if type(numerator) is int is type(denominator): - # *very* normal case - g = math.gcd(numerator, denominator) - if denominator < 0: - g = -g - else: - g = _gcd(numerator, denominator) - numerator //= g - denominator //= g - self._numerator = numerator - self._denominator = denominator + + if type(numerator) is int is type(denominator): + # *very* normal case + g = math.gcd(numerator, denominator) + if denominator < 0: + g = -g + else: + g = _gcd(numerator, denominator) + self._numerator = numerator // g + self._denominator = denominator // g return self @classmethod @@ -457,17 +455,19 @@ class Fraction(numbers.Rational): if b.denominator == 1: power = b.numerator if power >= 0: - return Fraction(a._numerator ** power, - a._denominator ** power, - _normalize=False) - elif a._numerator >= 0: - return Fraction(a._denominator ** -power, - a._numerator ** -power, - _normalize=False) + return _from_normalized( + a._numerator ** power, + a._denominator ** power) + elif a._numerator > 0: + return _from_normalized( + a._denominator ** -power, + a._numerator ** -power) + elif a._numerator < 0: + return _from_normalized( + (-a._denominator) ** -power, + (-a._numerator) ** -power) else: - return Fraction((-a._denominator) ** -power, - (-a._numerator) ** -power, - _normalize=False) + raise ZeroDivisionError(f'{a!r} cannot be raised to a negative power') else: # A fractional power will generally produce an # irrational number. @@ -491,15 +491,15 @@ class Fraction(numbers.Rational): def __pos__(a): """+a: Coerces a subclass instance to Fraction""" - return Fraction(a._numerator, a._denominator, _normalize=False) + return _from_normalized(a._numerator, a._denominator) def __neg__(a): """-a""" - return Fraction(-a._numerator, a._denominator, _normalize=False) + return _from_normalized(-a._numerator, a._denominator) def __abs__(a): """abs(a)""" - return Fraction(abs(a._numerator), a._denominator, _normalize=False) + return _from_normalized(abs(a._numerator), a._denominator) def __trunc__(a): """trunc(a)""" @@ -641,3 +641,12 @@ class Fraction(numbers.Rational): if type(self) == Fraction: return self # My components are also immutable return self.__class__(self._numerator, self._denominator) + + +def _from_normalized(numerator, denominator): + self = super(Fraction, Fraction).__new__(Fraction) + assert type(numerator) is int is type(denominator) + assert denominator != 0 + self._numerator = numerator + self._denominator = denominator + return self diff -r 7d90bf4780ff Lib/test/test_fractions.py --- a/Lib/test/test_fractions.py Mon Aug 22 18:07:02 2016 +0300 +++ b/Lib/test/test_fractions.py Tue Aug 23 13:39:40 2016 +0300 @@ -150,6 +150,8 @@ class FractionTest(unittest.TestCase): self.assertRaises(TypeError, F, "3/2", 3) self.assertRaises(TypeError, F, 3, 0j) self.assertRaises(TypeError, F, 3, 1j) + self.assertRaises(TypeError, F, 7, 3, 1) + self.assertRaises(TypeError, F, 7, 3, 0) @requires_IEEE_754 def testInitFromFloat(self):