Rename rational.Rational to fractions.Fraction, to avoid name clash
with numbers.Rational. See issue #1682 for related discussion.
This commit is contained in:
parent
da614dcc4f
commit
d058cd2cc8
|
@ -1,29 +1,29 @@
|
|||
|
||||
:mod:`rational` --- Rational numbers
|
||||
:mod:`fractions` --- Rational numbers
|
||||
====================================
|
||||
|
||||
.. module:: rational
|
||||
.. module:: fractions
|
||||
:synopsis: Rational numbers.
|
||||
.. moduleauthor:: Jeffrey Yasskin <jyasskin at gmail.com>
|
||||
.. sectionauthor:: Jeffrey Yasskin <jyasskin at gmail.com>
|
||||
.. versionadded:: 2.6
|
||||
|
||||
|
||||
The :mod:`rational` module defines an immutable, infinite-precision
|
||||
Rational number class.
|
||||
The :mod:`fractions` module defines an immutable, infinite-precision
|
||||
Fraction number class.
|
||||
|
||||
|
||||
.. class:: Rational(numerator=0, denominator=1)
|
||||
Rational(other_rational)
|
||||
Rational(string)
|
||||
.. class:: Fraction(numerator=0, denominator=1)
|
||||
Fraction(other_fraction)
|
||||
Fraction(string)
|
||||
|
||||
The first version requires that *numerator* and *denominator* are
|
||||
instances of :class:`numbers.Integral` and returns a new
|
||||
``Rational`` representing ``numerator/denominator``. If
|
||||
``Fraction`` representing ``numerator/denominator``. If
|
||||
*denominator* is :const:`0`, raises a :exc:`ZeroDivisionError`. The
|
||||
second version requires that *other_rational* is an instance of
|
||||
second version requires that *other_fraction* is an instance of
|
||||
:class:`numbers.Rational` and returns an instance of
|
||||
:class:`Rational` with the same value. The third version expects a
|
||||
:class:`Fraction` with the same value. The third version expects a
|
||||
string of the form ``[-+]?[0-9]+(/[0-9]+)?``, optionally surrounded
|
||||
by spaces.
|
||||
|
||||
|
@ -31,39 +31,39 @@ Rational number class.
|
|||
:class:`numbers.Rational` and is immutable and hashable.
|
||||
|
||||
|
||||
.. method:: Rational.from_float(flt)
|
||||
.. method:: Fraction.from_float(flt)
|
||||
|
||||
This classmethod constructs a :class:`Rational` representing the
|
||||
This classmethod constructs a :class:`Fraction` representing the
|
||||
exact value of *flt*, which must be a :class:`float`. Beware that
|
||||
``Rational.from_float(0.3)`` is not the same value as ``Rational(3,
|
||||
``Fraction.from_float(0.3)`` is not the same value as ``Fraction(3,
|
||||
10)``
|
||||
|
||||
|
||||
.. method:: Rational.from_decimal(dec)
|
||||
.. method:: Fraction.from_decimal(dec)
|
||||
|
||||
This classmethod constructs a :class:`Rational` representing the
|
||||
This classmethod constructs a :class:`Fraction` representing the
|
||||
exact value of *dec*, which must be a
|
||||
:class:`decimal.Decimal`.
|
||||
|
||||
|
||||
.. method:: Rational.__floor__()
|
||||
.. method:: Fraction.__floor__()
|
||||
|
||||
Returns the greatest :class:`int` ``<= self``. Will be accessible
|
||||
through :func:`math.floor` in Py3k.
|
||||
|
||||
|
||||
.. method:: Rational.__ceil__()
|
||||
.. method:: Fraction.__ceil__()
|
||||
|
||||
Returns the least :class:`int` ``>= self``. Will be accessible
|
||||
through :func:`math.ceil` in Py3k.
|
||||
|
||||
|
||||
.. method:: Rational.__round__()
|
||||
Rational.__round__(ndigits)
|
||||
.. method:: Fraction.__round__()
|
||||
Fraction.__round__(ndigits)
|
||||
|
||||
The first version returns the nearest :class:`int` to ``self``,
|
||||
rounding half to even. The second version rounds ``self`` to the
|
||||
nearest multiple of ``Rational(1, 10**ndigits)`` (logically, if
|
||||
nearest multiple of ``Fraction(1, 10**ndigits)`` (logically, if
|
||||
``ndigits`` is negative), again rounding half toward even. Will be
|
||||
accessible through :func:`round` in Py3k.
|
||||
|
|
@ -106,7 +106,7 @@ Notes for type implementors
|
|||
|
||||
Implementors should be careful to make equal numbers equal and hash
|
||||
them to the same values. This may be subtle if there are two different
|
||||
extensions of the real numbers. For example, :class:`rational.Rational`
|
||||
extensions of the real numbers. For example, :class:`fractions.Fraction`
|
||||
implements :func:`hash` as follows::
|
||||
|
||||
def __hash__(self):
|
||||
|
@ -201,11 +201,11 @@ in :class:`complex`, and both :meth:`__radd__` s land there, so ``a+b
|
|||
Because most of the operations on any given type will be very similar,
|
||||
it can be useful to define a helper function which generates the
|
||||
forward and reverse instances of any given operator. For example,
|
||||
:class:`rational.Rational` uses::
|
||||
:class:`fractions.Fraction` uses::
|
||||
|
||||
def _operator_fallbacks(monomorphic_operator, fallback_operator):
|
||||
def forward(a, b):
|
||||
if isinstance(b, (int, long, Rational)):
|
||||
if isinstance(b, (int, long, Fraction)):
|
||||
return monomorphic_operator(a, b)
|
||||
elif isinstance(b, float):
|
||||
return fallback_operator(float(a), b)
|
||||
|
@ -217,7 +217,7 @@ forward and reverse instances of any given operator. For example,
|
|||
forward.__doc__ = monomorphic_operator.__doc__
|
||||
|
||||
def reverse(b, a):
|
||||
if isinstance(a, RationalAbc):
|
||||
if isinstance(a, Rational):
|
||||
# Includes ints.
|
||||
return monomorphic_operator(a, b)
|
||||
elif isinstance(a, numbers.Real):
|
||||
|
@ -233,7 +233,7 @@ forward and reverse instances of any given operator. For example,
|
|||
|
||||
def _add(a, b):
|
||||
"""a + b"""
|
||||
return Rational(a.numerator * b.denominator +
|
||||
return Fraction(a.numerator * b.denominator +
|
||||
b.numerator * a.denominator,
|
||||
a.denominator * b.denominator)
|
||||
|
||||
|
|
|
@ -578,8 +578,8 @@ and comparisons.
|
|||
|
||||
:class:`Rational` numbers derive from :class:`Real`, have
|
||||
:attr:`numerator` and :attr:`denominator` properties, and can be
|
||||
converted to floats. Python 2.6 adds a simple rational-number class
|
||||
in the :mod:`rational` module.
|
||||
converted to floats. Python 2.6 adds a simple rational-number class,
|
||||
:class:`Fraction`, in the :mod:`fractions` module.
|
||||
|
||||
:class:`Integral` numbers derive from :class:`Rational`, and
|
||||
can be shifted left and right with ``<<`` and ``>>``,
|
||||
|
@ -598,29 +598,29 @@ one, :func:`trunc`, that's been backported to Python 2.6.
|
|||
|
||||
|
||||
|
||||
The Rational Module
|
||||
The Fraction Module
|
||||
--------------------------------------------------
|
||||
|
||||
To fill out the hierarchy of numeric types, a rational-number class
|
||||
has been added as the :mod:`rational` module. Rational numbers are
|
||||
has been added as the :mod:`fractions` module. Rational numbers are
|
||||
represented as a fraction; rational numbers can exactly represent
|
||||
numbers such as two-thirds that floating-point numbers can only
|
||||
approximate.
|
||||
|
||||
The :class:`Rational` constructor takes two :class:`Integral` values
|
||||
The :class:`Fraction` constructor takes two :class:`Integral` values
|
||||
that will be the numerator and denominator of the resulting fraction. ::
|
||||
|
||||
>>> from rational import Rational
|
||||
>>> a = Rational(2, 3)
|
||||
>>> b = Rational(2, 5)
|
||||
>>> from fractions import Fraction
|
||||
>>> a = Fraction(2, 3)
|
||||
>>> b = Fraction(2, 5)
|
||||
>>> float(a), float(b)
|
||||
(0.66666666666666663, 0.40000000000000002)
|
||||
>>> a+b
|
||||
rational.Rational(16,15)
|
||||
Fraction(16,15)
|
||||
>>> a/b
|
||||
rational.Rational(5,3)
|
||||
Fraction(5,3)
|
||||
|
||||
The :mod:`rational` module is based upon an implementation by Sjoerd
|
||||
The :mod:`fractions` module is based upon an implementation by Sjoerd
|
||||
Mullender that was in Python's :file:`Demo/classes/` directory for a
|
||||
long time. This implementation was significantly updated by Jeffrey
|
||||
Yaskin.
|
||||
|
|
|
@ -9,9 +9,9 @@ import numbers
|
|||
import operator
|
||||
import re
|
||||
|
||||
__all__ = ["Rational"]
|
||||
__all__ = ["Fraction"]
|
||||
|
||||
RationalAbc = numbers.Rational
|
||||
Rational = numbers.Rational
|
||||
|
||||
|
||||
def gcd(a, b):
|
||||
|
@ -39,15 +39,15 @@ _RATIONAL_FORMAT = re.compile(r"""
|
|||
""", re.VERBOSE)
|
||||
|
||||
|
||||
class Rational(RationalAbc):
|
||||
class Fraction(Rational):
|
||||
"""This class implements rational numbers.
|
||||
|
||||
Rational(8, 6) will produce a rational number equivalent to
|
||||
Fraction(8, 6) will produce a rational number equivalent to
|
||||
4/3. Both arguments must be Integral. The numerator defaults to 0
|
||||
and the denominator defaults to 1 so that Rational(3) == 3 and
|
||||
Rational() == 0.
|
||||
and the denominator defaults to 1 so that Fraction(3) == 3 and
|
||||
Fraction() == 0.
|
||||
|
||||
Rationals can also be constructed from strings of the form
|
||||
Fractions can also be constructed from strings of the form
|
||||
'[-+]?[0-9]+((/|.)[0-9]+)?', optionally surrounded by spaces.
|
||||
|
||||
"""
|
||||
|
@ -56,13 +56,13 @@ class Rational(RationalAbc):
|
|||
|
||||
# We're immutable, so use __new__ not __init__
|
||||
def __new__(cls, numerator=0, denominator=1):
|
||||
"""Constructs a Rational.
|
||||
"""Constructs a Fraction.
|
||||
|
||||
Takes a string like '3/2' or '1.5', another Rational, or a
|
||||
Takes a string like '3/2' or '1.5', another Fraction, or a
|
||||
numerator/denominator pair.
|
||||
|
||||
"""
|
||||
self = super(Rational, cls).__new__(cls)
|
||||
self = super(Fraction, cls).__new__(cls)
|
||||
|
||||
if denominator == 1:
|
||||
if isinstance(numerator, basestring):
|
||||
|
@ -70,7 +70,7 @@ class Rational(RationalAbc):
|
|||
input = numerator
|
||||
m = _RATIONAL_FORMAT.match(input)
|
||||
if m is None:
|
||||
raise ValueError('Invalid literal for Rational: ' + input)
|
||||
raise ValueError('Invalid literal for Fraction: ' + input)
|
||||
numerator = m.group('num')
|
||||
decimal = m.group('decimal')
|
||||
if decimal:
|
||||
|
@ -87,7 +87,7 @@ class Rational(RationalAbc):
|
|||
numerator = -numerator
|
||||
|
||||
elif (not isinstance(numerator, numbers.Integral) and
|
||||
isinstance(numerator, RationalAbc)):
|
||||
isinstance(numerator, Rational)):
|
||||
# Handle copies from other rationals.
|
||||
other_rational = numerator
|
||||
numerator = other_rational.numerator
|
||||
|
@ -95,11 +95,11 @@ class Rational(RationalAbc):
|
|||
|
||||
if (not isinstance(numerator, numbers.Integral) or
|
||||
not isinstance(denominator, numbers.Integral)):
|
||||
raise TypeError("Rational(%(numerator)s, %(denominator)s):"
|
||||
raise TypeError("Fraction(%(numerator)s, %(denominator)s):"
|
||||
" Both arguments must be integral." % locals())
|
||||
|
||||
if denominator == 0:
|
||||
raise ZeroDivisionError('Rational(%s, 0)' % numerator)
|
||||
raise ZeroDivisionError('Fraction(%s, 0)' % numerator)
|
||||
|
||||
g = gcd(numerator, denominator)
|
||||
self._numerator = int(numerator // g)
|
||||
|
@ -110,15 +110,15 @@ class Rational(RationalAbc):
|
|||
def from_float(f):
|
||||
"""Converts a finite float to a rational number, exactly.
|
||||
|
||||
Beware that Rational.from_float(0.3) != Rational(3, 10).
|
||||
Beware that Fraction.from_float(0.3) != Fraction(3, 10).
|
||||
|
||||
"""
|
||||
if not isinstance(f, float):
|
||||
raise TypeError("Rational.from_float() only takes floats, "
|
||||
raise TypeError("Fraction.from_float() only takes floats, "
|
||||
"not %r (%s)" % (f, type(f).__name__))
|
||||
if math.isnan(f) or math.isinf(f):
|
||||
raise TypeError("Cannot convert %r to Rational." % f)
|
||||
return Rational(*f.as_integer_ratio())
|
||||
raise TypeError("Cannot convert %r to Fraction." % f)
|
||||
return Fraction(*f.as_integer_ratio())
|
||||
|
||||
@staticmethod
|
||||
def from_decimal(dec):
|
||||
|
@ -126,28 +126,28 @@ class Rational(RationalAbc):
|
|||
from decimal import Decimal
|
||||
if not isinstance(dec, Decimal):
|
||||
raise TypeError(
|
||||
"Rational.from_decimal() only takes Decimals, not %r (%s)" %
|
||||
"Fraction.from_decimal() only takes Decimals, not %r (%s)" %
|
||||
(dec, type(dec).__name__))
|
||||
if not dec.is_finite():
|
||||
# Catches infinities and nans.
|
||||
raise TypeError("Cannot convert %s to Rational." % dec)
|
||||
raise TypeError("Cannot convert %s to Fraction." % dec)
|
||||
sign, digits, exp = dec.as_tuple()
|
||||
digits = int(''.join(map(str, digits)))
|
||||
if sign:
|
||||
digits = -digits
|
||||
if exp >= 0:
|
||||
return Rational(digits * 10 ** exp)
|
||||
return Fraction(digits * 10 ** exp)
|
||||
else:
|
||||
return Rational(digits, 10 ** -exp)
|
||||
return Fraction(digits, 10 ** -exp)
|
||||
|
||||
@staticmethod
|
||||
def from_continued_fraction(seq):
|
||||
'Build a Rational from a continued fraction expessed as a sequence'
|
||||
'Build a Fraction from a continued fraction expessed as a sequence'
|
||||
n, d = 1, 0
|
||||
for e in reversed(seq):
|
||||
n, d = d, n
|
||||
n += e * d
|
||||
return Rational(n, d) if seq else Rational(0)
|
||||
return Fraction(n, d) if seq else Fraction(0)
|
||||
|
||||
def as_continued_fraction(self):
|
||||
'Return continued fraction expressed as a list'
|
||||
|
@ -169,7 +169,7 @@ class Rational(RationalAbc):
|
|||
if self.denominator <= max_denominator:
|
||||
return self
|
||||
cf = self.as_continued_fraction()
|
||||
result = Rational(0)
|
||||
result = Fraction(0)
|
||||
for i in range(1, len(cf)):
|
||||
new = self.from_continued_fraction(cf[:i])
|
||||
if new.denominator > max_denominator:
|
||||
|
@ -187,7 +187,7 @@ class Rational(RationalAbc):
|
|||
|
||||
def __repr__(self):
|
||||
"""repr(self)"""
|
||||
return ('Rational(%r,%r)' % (self.numerator, self.denominator))
|
||||
return ('Fraction(%r,%r)' % (self.numerator, self.denominator))
|
||||
|
||||
def __str__(self):
|
||||
"""str(self)"""
|
||||
|
@ -207,13 +207,13 @@ class Rational(RationalAbc):
|
|||
that mixed-mode operations either call an implementation whose
|
||||
author knew about the types of both arguments, or convert both
|
||||
to the nearest built in type and do the operation there. In
|
||||
Rational, that means that we define __add__ and __radd__ as:
|
||||
Fraction, that means that we define __add__ and __radd__ as:
|
||||
|
||||
def __add__(self, other):
|
||||
# Both types have numerators/denominator attributes,
|
||||
# so do the operation directly
|
||||
if isinstance(other, (int, long, Rational)):
|
||||
return Rational(self.numerator * other.denominator +
|
||||
if isinstance(other, (int, long, Fraction)):
|
||||
return Fraction(self.numerator * other.denominator +
|
||||
other.numerator * self.denominator,
|
||||
self.denominator * other.denominator)
|
||||
# float and complex don't have those operations, but we
|
||||
|
@ -228,8 +228,8 @@ class Rational(RationalAbc):
|
|||
def __radd__(self, other):
|
||||
# radd handles more types than add because there's
|
||||
# nothing left to fall back to.
|
||||
if isinstance(other, RationalAbc):
|
||||
return Rational(self.numerator * other.denominator +
|
||||
if isinstance(other, Rational):
|
||||
return Fraction(self.numerator * other.denominator +
|
||||
other.numerator * self.denominator,
|
||||
self.denominator * other.denominator)
|
||||
elif isinstance(other, Real):
|
||||
|
@ -240,32 +240,32 @@ class Rational(RationalAbc):
|
|||
|
||||
|
||||
There are 5 different cases for a mixed-type addition on
|
||||
Rational. I'll refer to all of the above code that doesn't
|
||||
refer to Rational, float, or complex as "boilerplate". 'r'
|
||||
will be an instance of Rational, which is a subtype of
|
||||
RationalAbc (r : Rational <: RationalAbc), and b : B <:
|
||||
Fraction. I'll refer to all of the above code that doesn't
|
||||
refer to Fraction, float, or complex as "boilerplate". 'r'
|
||||
will be an instance of Fraction, which is a subtype of
|
||||
Rational (r : Fraction <: Rational), and b : B <:
|
||||
Complex. The first three involve 'r + b':
|
||||
|
||||
1. If B <: Rational, int, float, or complex, we handle
|
||||
1. If B <: Fraction, int, float, or complex, we handle
|
||||
that specially, and all is well.
|
||||
2. If Rational falls back to the boilerplate code, and it
|
||||
2. If Fraction falls back to the boilerplate code, and it
|
||||
were to return a value from __add__, we'd miss the
|
||||
possibility that B defines a more intelligent __radd__,
|
||||
so the boilerplate should return NotImplemented from
|
||||
__add__. In particular, we don't handle RationalAbc
|
||||
__add__. In particular, we don't handle Rational
|
||||
here, even though we could get an exact answer, in case
|
||||
the other type wants to do something special.
|
||||
3. If B <: Rational, Python tries B.__radd__ before
|
||||
Rational.__add__. This is ok, because it was
|
||||
implemented with knowledge of Rational, so it can
|
||||
3. If B <: Fraction, Python tries B.__radd__ before
|
||||
Fraction.__add__. This is ok, because it was
|
||||
implemented with knowledge of Fraction, so it can
|
||||
handle those instances before delegating to Real or
|
||||
Complex.
|
||||
|
||||
The next two situations describe 'b + r'. We assume that b
|
||||
didn't know about Rational in its implementation, and that it
|
||||
didn't know about Fraction in its implementation, and that it
|
||||
uses similar boilerplate code:
|
||||
|
||||
4. If B <: RationalAbc, then __radd_ converts both to the
|
||||
4. If B <: Rational, then __radd_ converts both to the
|
||||
builtin rational type (hey look, that's us) and
|
||||
proceeds.
|
||||
5. Otherwise, __radd__ tries to find the nearest common
|
||||
|
@ -277,7 +277,7 @@ class Rational(RationalAbc):
|
|||
|
||||
"""
|
||||
def forward(a, b):
|
||||
if isinstance(b, (int, long, Rational)):
|
||||
if isinstance(b, (int, long, Fraction)):
|
||||
return monomorphic_operator(a, b)
|
||||
elif isinstance(b, float):
|
||||
return fallback_operator(float(a), b)
|
||||
|
@ -289,7 +289,7 @@ class Rational(RationalAbc):
|
|||
forward.__doc__ = monomorphic_operator.__doc__
|
||||
|
||||
def reverse(b, a):
|
||||
if isinstance(a, RationalAbc):
|
||||
if isinstance(a, Rational):
|
||||
# Includes ints.
|
||||
return monomorphic_operator(a, b)
|
||||
elif isinstance(a, numbers.Real):
|
||||
|
@ -305,7 +305,7 @@ class Rational(RationalAbc):
|
|||
|
||||
def _add(a, b):
|
||||
"""a + b"""
|
||||
return Rational(a.numerator * b.denominator +
|
||||
return Fraction(a.numerator * b.denominator +
|
||||
b.numerator * a.denominator,
|
||||
a.denominator * b.denominator)
|
||||
|
||||
|
@ -313,7 +313,7 @@ class Rational(RationalAbc):
|
|||
|
||||
def _sub(a, b):
|
||||
"""a - b"""
|
||||
return Rational(a.numerator * b.denominator -
|
||||
return Fraction(a.numerator * b.denominator -
|
||||
b.numerator * a.denominator,
|
||||
a.denominator * b.denominator)
|
||||
|
||||
|
@ -321,13 +321,13 @@ class Rational(RationalAbc):
|
|||
|
||||
def _mul(a, b):
|
||||
"""a * b"""
|
||||
return Rational(a.numerator * b.numerator, a.denominator * b.denominator)
|
||||
return Fraction(a.numerator * b.numerator, a.denominator * b.denominator)
|
||||
|
||||
__mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul)
|
||||
|
||||
def _div(a, b):
|
||||
"""a / b"""
|
||||
return Rational(a.numerator * b.denominator,
|
||||
return Fraction(a.numerator * b.denominator,
|
||||
a.denominator * b.numerator)
|
||||
|
||||
__truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv)
|
||||
|
@ -337,7 +337,7 @@ class Rational(RationalAbc):
|
|||
"""a // b"""
|
||||
# Will be math.floor(a / b) in 3.0.
|
||||
div = a / b
|
||||
if isinstance(div, RationalAbc):
|
||||
if isinstance(div, Rational):
|
||||
# trunc(math.floor(div)) doesn't work if the rational is
|
||||
# more precise than a float because the intermediate
|
||||
# rounding may cross an integer boundary.
|
||||
|
@ -349,7 +349,7 @@ class Rational(RationalAbc):
|
|||
"""a // b"""
|
||||
# Will be math.floor(a / b) in 3.0.
|
||||
div = a / b
|
||||
if isinstance(div, RationalAbc):
|
||||
if isinstance(div, Rational):
|
||||
# trunc(math.floor(div)) doesn't work if the rational is
|
||||
# more precise than a float because the intermediate
|
||||
# rounding may cross an integer boundary.
|
||||
|
@ -375,14 +375,14 @@ class Rational(RationalAbc):
|
|||
result will be rational.
|
||||
|
||||
"""
|
||||
if isinstance(b, RationalAbc):
|
||||
if isinstance(b, Rational):
|
||||
if b.denominator == 1:
|
||||
power = b.numerator
|
||||
if power >= 0:
|
||||
return Rational(a.numerator ** power,
|
||||
return Fraction(a.numerator ** power,
|
||||
a.denominator ** power)
|
||||
else:
|
||||
return Rational(a.denominator ** -power,
|
||||
return Fraction(a.denominator ** -power,
|
||||
a.numerator ** -power)
|
||||
else:
|
||||
# A fractional power will generally produce an
|
||||
|
@ -397,8 +397,8 @@ class Rational(RationalAbc):
|
|||
# If a is an int, keep it that way if possible.
|
||||
return a ** b.numerator
|
||||
|
||||
if isinstance(a, RationalAbc):
|
||||
return Rational(a.numerator, a.denominator) ** b
|
||||
if isinstance(a, Rational):
|
||||
return Fraction(a.numerator, a.denominator) ** b
|
||||
|
||||
if b.denominator == 1:
|
||||
return a ** b.numerator
|
||||
|
@ -406,16 +406,16 @@ class Rational(RationalAbc):
|
|||
return a ** float(b)
|
||||
|
||||
def __pos__(a):
|
||||
"""+a: Coerces a subclass instance to Rational"""
|
||||
return Rational(a.numerator, a.denominator)
|
||||
"""+a: Coerces a subclass instance to Fraction"""
|
||||
return Fraction(a.numerator, a.denominator)
|
||||
|
||||
def __neg__(a):
|
||||
"""-a"""
|
||||
return Rational(-a.numerator, a.denominator)
|
||||
return Fraction(-a.numerator, a.denominator)
|
||||
|
||||
def __abs__(a):
|
||||
"""abs(a)"""
|
||||
return Rational(abs(a.numerator), a.denominator)
|
||||
return Fraction(abs(a.numerator), a.denominator)
|
||||
|
||||
def __trunc__(a):
|
||||
"""trunc(a)"""
|
||||
|
@ -445,7 +445,7 @@ class Rational(RationalAbc):
|
|||
|
||||
def __eq__(a, b):
|
||||
"""a == b"""
|
||||
if isinstance(b, RationalAbc):
|
||||
if isinstance(b, Rational):
|
||||
return (a.numerator == b.numerator and
|
||||
a.denominator == b.denominator)
|
||||
if isinstance(b, numbers.Complex) and b.imag == 0:
|
||||
|
@ -472,7 +472,7 @@ class Rational(RationalAbc):
|
|||
if isinstance(b, float):
|
||||
b = a.from_float(b)
|
||||
try:
|
||||
# XXX: If b <: Real but not <: RationalAbc, this is likely
|
||||
# XXX: If b <: Real but not <: Rational, this is likely
|
||||
# to fall back to a float. If the actual values differ by
|
||||
# less than MIN_FLOAT, this could falsely call them equal,
|
||||
# which would make <= inconsistent with ==. Better ways of
|
||||
|
@ -480,7 +480,7 @@ class Rational(RationalAbc):
|
|||
diff = a - b
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
if isinstance(diff, RationalAbc):
|
||||
if isinstance(diff, Rational):
|
||||
return op(diff.numerator, 0)
|
||||
return op(diff, 0)
|
||||
|
||||
|
@ -510,11 +510,11 @@ class Rational(RationalAbc):
|
|||
return (self.__class__, (str(self),))
|
||||
|
||||
def __copy__(self):
|
||||
if type(self) == Rational:
|
||||
if type(self) == Fraction:
|
||||
return self # I'm immutable; therefore I am my own clone
|
||||
return self.__class__(self.numerator, self.denominator)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
if type(self) == Rational:
|
||||
if type(self) == Fraction:
|
||||
return self # My components are also immutable
|
||||
return self.__class__(self.numerator, self.denominator)
|
|
@ -5,7 +5,7 @@ from test.test_support import fcmp, have_unicode, TESTFN, unlink, \
|
|||
run_unittest, run_with_locale
|
||||
from operator import neg
|
||||
|
||||
import sys, warnings, cStringIO, random, rational, UserDict
|
||||
import sys, warnings, cStringIO, random, fractions, UserDict
|
||||
warnings.filterwarnings("ignore", "hex../oct.. of negative int",
|
||||
FutureWarning, __name__)
|
||||
warnings.filterwarnings("ignore", "integer argument expected",
|
||||
|
@ -703,7 +703,7 @@ class BuiltinTest(unittest.TestCase):
|
|||
n, d = f.as_integer_ratio()
|
||||
self.assertEqual(float(n).__truediv__(d), f)
|
||||
|
||||
R = rational.Rational
|
||||
R = fractions.Fraction
|
||||
self.assertEqual(R(0, 1),
|
||||
R(*float(0.0).as_integer_ratio()))
|
||||
self.assertEqual(R(5, 2),
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
"""Tests for Lib/rational.py."""
|
||||
"""Tests for Lib/fractions.py."""
|
||||
|
||||
from decimal import Decimal
|
||||
from test.test_support import run_unittest, verbose
|
||||
import math
|
||||
import operator
|
||||
import rational
|
||||
import fractions
|
||||
import unittest
|
||||
from copy import copy, deepcopy
|
||||
from cPickle import dumps, loads
|
||||
R = rational.Rational
|
||||
gcd = rational.gcd
|
||||
R = fractions.Fraction
|
||||
gcd = fractions.gcd
|
||||
|
||||
|
||||
class GcdTest(unittest.TestCase):
|
||||
|
@ -31,7 +31,7 @@ def _components(r):
|
|||
return (r.numerator, r.denominator)
|
||||
|
||||
|
||||
class RationalTest(unittest.TestCase):
|
||||
class FractionTest(unittest.TestCase):
|
||||
|
||||
def assertTypedEquals(self, expected, actual):
|
||||
"""Asserts that both the types and values are the same."""
|
||||
|
@ -60,7 +60,7 @@ class RationalTest(unittest.TestCase):
|
|||
self.assertEquals((7, 15), _components(R(7, 15)))
|
||||
self.assertEquals((10**23, 1), _components(R(10**23)))
|
||||
|
||||
self.assertRaisesMessage(ZeroDivisionError, "Rational(12, 0)",
|
||||
self.assertRaisesMessage(ZeroDivisionError, "Fraction(12, 0)",
|
||||
R, 12, 0)
|
||||
self.assertRaises(TypeError, R, 1.5)
|
||||
self.assertRaises(TypeError, R, 1.5 + 3j)
|
||||
|
@ -83,41 +83,41 @@ class RationalTest(unittest.TestCase):
|
|||
|
||||
|
||||
self.assertRaisesMessage(
|
||||
ZeroDivisionError, "Rational(3, 0)",
|
||||
ZeroDivisionError, "Fraction(3, 0)",
|
||||
R, "3/0")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Rational: 3/",
|
||||
ValueError, "Invalid literal for Fraction: 3/",
|
||||
R, "3/")
|
||||
self.assertRaisesMessage(
|
||||
ValueError, "Invalid literal for Rational: 3 /2",
|
||||
ValueError, "Invalid literal for Fraction: 3 /2",
|
||||
R, "3 /2")
|
||||
self.assertRaisesMessage(
|
||||
# Denominators don't need a sign.
|
||||
ValueError, "Invalid literal for Rational: 3/+2",
|
||||
ValueError, "Invalid literal for Fraction: 3/+2",
|
||||
R, "3/+2")
|
||||
self.assertRaisesMessage(
|
||||
# Imitate float's parsing.
|
||||
ValueError, "Invalid literal for Rational: + 3/2",
|
||||
ValueError, "Invalid literal for Fraction: + 3/2",
|
||||
R, "+ 3/2")
|
||||
self.assertRaisesMessage(
|
||||
# Avoid treating '.' as a regex special character.
|
||||
ValueError, "Invalid literal for Rational: 3a2",
|
||||
ValueError, "Invalid literal for Fraction: 3a2",
|
||||
R, "3a2")
|
||||
self.assertRaisesMessage(
|
||||
# Only parse ordinary decimals, not scientific form.
|
||||
ValueError, "Invalid literal for Rational: 3.2e4",
|
||||
ValueError, "Invalid literal for Fraction: 3.2e4",
|
||||
R, "3.2e4")
|
||||
self.assertRaisesMessage(
|
||||
# Don't accept combinations of decimals and rationals.
|
||||
ValueError, "Invalid literal for Rational: 3/7.2",
|
||||
# Don't accept combinations of decimals and fractions.
|
||||
ValueError, "Invalid literal for Fraction: 3/7.2",
|
||||
R, "3/7.2")
|
||||
self.assertRaisesMessage(
|
||||
# Don't accept combinations of decimals and rationals.
|
||||
ValueError, "Invalid literal for Rational: 3.2/7",
|
||||
# Don't accept combinations of decimals and fractions.
|
||||
ValueError, "Invalid literal for Fraction: 3.2/7",
|
||||
R, "3.2/7")
|
||||
self.assertRaisesMessage(
|
||||
# Allow 3. and .3, but not .
|
||||
ValueError, "Invalid literal for Rational: .",
|
||||
ValueError, "Invalid literal for Fraction: .",
|
||||
R, ".")
|
||||
|
||||
def testImmutable(self):
|
||||
|
@ -138,7 +138,7 @@ class RationalTest(unittest.TestCase):
|
|||
|
||||
def testFromFloat(self):
|
||||
self.assertRaisesMessage(
|
||||
TypeError, "Rational.from_float() only takes floats, not 3 (int)",
|
||||
TypeError, "Fraction.from_float() only takes floats, not 3 (int)",
|
||||
R.from_float, 3)
|
||||
|
||||
self.assertEquals((0, 1), _components(R.from_float(-0.0)))
|
||||
|
@ -154,19 +154,19 @@ class RationalTest(unittest.TestCase):
|
|||
inf = 1e1000
|
||||
nan = inf - inf
|
||||
self.assertRaisesMessage(
|
||||
TypeError, "Cannot convert inf to Rational.",
|
||||
TypeError, "Cannot convert inf to Fraction.",
|
||||
R.from_float, inf)
|
||||
self.assertRaisesMessage(
|
||||
TypeError, "Cannot convert -inf to Rational.",
|
||||
TypeError, "Cannot convert -inf to Fraction.",
|
||||
R.from_float, -inf)
|
||||
self.assertRaisesMessage(
|
||||
TypeError, "Cannot convert nan to Rational.",
|
||||
TypeError, "Cannot convert nan to Fraction.",
|
||||
R.from_float, nan)
|
||||
|
||||
def testFromDecimal(self):
|
||||
self.assertRaisesMessage(
|
||||
TypeError,
|
||||
"Rational.from_decimal() only takes Decimals, not 3 (int)",
|
||||
"Fraction.from_decimal() only takes Decimals, not 3 (int)",
|
||||
R.from_decimal, 3)
|
||||
self.assertEquals(R(0), R.from_decimal(Decimal("-0")))
|
||||
self.assertEquals(R(5, 10), R.from_decimal(Decimal("0.5")))
|
||||
|
@ -176,16 +176,16 @@ class RationalTest(unittest.TestCase):
|
|||
R.from_decimal(Decimal("0." + "9" * 30)))
|
||||
|
||||
self.assertRaisesMessage(
|
||||
TypeError, "Cannot convert Infinity to Rational.",
|
||||
TypeError, "Cannot convert Infinity to Fraction.",
|
||||
R.from_decimal, Decimal("inf"))
|
||||
self.assertRaisesMessage(
|
||||
TypeError, "Cannot convert -Infinity to Rational.",
|
||||
TypeError, "Cannot convert -Infinity to Fraction.",
|
||||
R.from_decimal, Decimal("-inf"))
|
||||
self.assertRaisesMessage(
|
||||
TypeError, "Cannot convert NaN to Rational.",
|
||||
TypeError, "Cannot convert NaN to Fraction.",
|
||||
R.from_decimal, Decimal("nan"))
|
||||
self.assertRaisesMessage(
|
||||
TypeError, "Cannot convert sNaN to Rational.",
|
||||
TypeError, "Cannot convert sNaN to Fraction.",
|
||||
R.from_decimal, Decimal("snan"))
|
||||
|
||||
def testFromContinuedFraction(self):
|
||||
|
@ -301,7 +301,7 @@ class RationalTest(unittest.TestCase):
|
|||
# Decimal refuses mixed comparisons.
|
||||
self.assertRaisesMessage(
|
||||
TypeError,
|
||||
"unsupported operand type(s) for +: 'Rational' and 'Decimal'",
|
||||
"unsupported operand type(s) for +: 'Fraction' and 'Decimal'",
|
||||
operator.add, R(3,11), Decimal('3.1415926'))
|
||||
self.assertNotEquals(R(5, 2), Decimal('2.5'))
|
||||
|
||||
|
@ -363,7 +363,7 @@ class RationalTest(unittest.TestCase):
|
|||
self.assertFalse(R(5, 2) == 2)
|
||||
|
||||
def testStringification(self):
|
||||
self.assertEquals("Rational(7,3)", repr(R(7, 3)))
|
||||
self.assertEquals("Fraction(7,3)", repr(R(7, 3)))
|
||||
self.assertEquals("7/3", str(R(7, 3)))
|
||||
self.assertEquals("7", str(R(7, 1)))
|
||||
|
||||
|
@ -406,7 +406,7 @@ class RationalTest(unittest.TestCase):
|
|||
self.assertEqual(id(r), id(deepcopy(r)))
|
||||
|
||||
def test_main():
|
||||
run_unittest(RationalTest, GcdTest)
|
||||
run_unittest(FractionTest, GcdTest)
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_main()
|
|
@ -400,6 +400,10 @@ Core and builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Rename rational.py to fractions.py and the rational.Rational class
|
||||
to fractions.Fraction, to avoid the name clash with the abstract
|
||||
base class numbers.Rational. See discussion in issue #1682.
|
||||
|
||||
- The pickletools module now provides an optimize() function
|
||||
that eliminates unused PUT opcodes from a pickle string.
|
||||
|
||||
|
|
Loading…
Reference in New Issue