mirror of
https://github.com/python/cpython.git
synced 2025-09-30 12:21:51 +00:00
Merged revisions 60481,60485,60489-60492,60494-60496,60498-60499,60501-60503,60505-60506,60508-60509,60523-60524,60532,60543,60545,60547-60548,60552,60554,60556-60559,60561-60562,60569,60571-60572,60574,60576-60583,60585-60586,60589,60591,60594-60595,60597-60598,60600-60601,60606-60612,60615,60617,60619-60621,60623-60625,60627-60629,60631,60633,60635,60647,60650,60652,60654,60656,60658-60659,60664-60666,60668-60670,60672,60676,60678,60680-60683,60685-60686,60688,60690,60692-60694,60697-60706,60708-60712,60714-60724 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r60701 | georg.brandl | 2008-02-09 22:36:15 +0100 (Sat, 09 Feb 2008) | 2 lines Needs only 2.4 now. ........ r60702 | georg.brandl | 2008-02-09 22:38:54 +0100 (Sat, 09 Feb 2008) | 2 lines Docs are rst now. ........ r60703 | georg.brandl | 2008-02-09 23:00:00 +0100 (Sat, 09 Feb 2008) | 2 lines Fix link. ........ r60704 | georg.brandl | 2008-02-10 00:09:25 +0100 (Sun, 10 Feb 2008) | 2 lines Fix for newest doctools. ........ r60709 | raymond.hettinger | 2008-02-10 08:21:09 +0100 (Sun, 10 Feb 2008) | 1 line Clarify that decimal also supports fixed-point arithmetic. ........ r60710 | nick.coghlan | 2008-02-10 08:32:52 +0100 (Sun, 10 Feb 2008) | 1 line Add missing NEWS entry for r60695 ........ r60712 | mark.dickinson | 2008-02-10 15:58:38 +0100 (Sun, 10 Feb 2008) | 3 lines Turn classmethods into staticmethods, and avoid calling the constructor of subclasses of Rational. (See discussion in issue #1682.) ........ r60715 | mark.dickinson | 2008-02-10 16:19:58 +0100 (Sun, 10 Feb 2008) | 2 lines Typos in decimal comment and documentation ........ r60716 | skip.montanaro | 2008-02-10 16:31:54 +0100 (Sun, 10 Feb 2008) | 2 lines Get the saying right. ;-) ........ r60717 | skip.montanaro | 2008-02-10 16:32:16 +0100 (Sun, 10 Feb 2008) | 2 lines whoops - revert ........ r60718 | mark.dickinson | 2008-02-10 20:23:36 +0100 (Sun, 10 Feb 2008) | 2 lines Remove reference to Rational ........ r60719 | raymond.hettinger | 2008-02-10 21:35:16 +0100 (Sun, 10 Feb 2008) | 1 line Complete an open todo on pickletools -- add a pickle optimizer. ........ r60721 | mark.dickinson | 2008-02-10 22:29:51 +0100 (Sun, 10 Feb 2008) | 3 lines Rename rational.Rational to fractions.Fraction, to avoid name clash with numbers.Rational. See issue #1682 for related discussion. ........ r60722 | christian.heimes | 2008-02-11 03:26:22 +0100 (Mon, 11 Feb 2008) | 1 line The test requires the network resource ........ r60723 | mark.dickinson | 2008-02-11 04:11:55 +0100 (Mon, 11 Feb 2008) | 3 lines Put an extra space into the repr of a Fraction: Fraction(1, 2) instead of Fraction(1,2). ........
This commit is contained in:
parent
ba99c58872
commit
3feef61742
15 changed files with 190 additions and 146 deletions
|
@ -4,7 +4,6 @@ Complex.py Complex numbers
|
||||||
Dates.py Date manipulation package by Tim Peters
|
Dates.py Date manipulation package by Tim Peters
|
||||||
Dbm.py Wrapper around built-in dbm, supporting arbitrary values
|
Dbm.py Wrapper around built-in dbm, supporting arbitrary values
|
||||||
Range.py Example of a generator: re-implement built-in range()
|
Range.py Example of a generator: re-implement built-in range()
|
||||||
Rat.py Rational numbers
|
|
||||||
Rev.py Yield the reverse of a sequence
|
Rev.py Yield the reverse of a sequence
|
||||||
Vec.py A simple vector class
|
Vec.py A simple vector class
|
||||||
bitvec.py A bit-vector class by Jan-Hein B\"uhrman
|
bitvec.py A bit-vector class by Jan-Hein B\"uhrman
|
||||||
|
|
|
@ -14,7 +14,7 @@ those familiar with the previous docs written in LaTeX.
|
||||||
Building the docs
|
Building the docs
|
||||||
=================
|
=================
|
||||||
|
|
||||||
You need to install Python 2.5.1 or higher (but Python 3.0 is not supported yet);
|
You need to install Python 2.4 or higher (but Python 3.0 is not supported yet);
|
||||||
the toolset used to build the docs are written in Python. The toolset used
|
the toolset used to build the docs are written in Python. The toolset used
|
||||||
to build the documentation is called *Sphinx*, it is not included in this
|
to build the documentation is called *Sphinx*, it is not included in this
|
||||||
tree, but maintained separately in the Python Subversion repository. Also
|
tree, but maintained separately in the Python Subversion repository. Also
|
||||||
|
@ -55,7 +55,7 @@ Available make targets are:
|
||||||
|
|
||||||
* "latex", which builds LaTeX source files that can be run with "pdflatex"
|
* "latex", which builds LaTeX source files that can be run with "pdflatex"
|
||||||
to produce PDF documents.
|
to produce PDF documents.
|
||||||
|
|
||||||
* "linkcheck", which checks all external references to see whether they are
|
* "linkcheck", which checks all external references to see whether they are
|
||||||
broken, redirected or malformed, and outputs this information to stdout
|
broken, redirected or malformed, and outputs this information to stdout
|
||||||
as well as a plain-text (.txt) file.
|
as well as a plain-text (.txt) file.
|
||||||
|
|
22
Doc/conf.py
22
Doc/conf.py
|
@ -38,17 +38,17 @@ today = ''
|
||||||
today_fmt = '%B %d, %Y'
|
today_fmt = '%B %d, %Y'
|
||||||
|
|
||||||
# List of files that shouldn't be included in the build.
|
# List of files that shouldn't be included in the build.
|
||||||
unused_files = [
|
unused_docs = [
|
||||||
'whatsnew/2.0.rst',
|
'whatsnew/2.0',
|
||||||
'whatsnew/2.1.rst',
|
'whatsnew/2.1',
|
||||||
'whatsnew/2.2.rst',
|
'whatsnew/2.2',
|
||||||
'whatsnew/2.3.rst',
|
'whatsnew/2.3',
|
||||||
'whatsnew/2.4.rst',
|
'whatsnew/2.4',
|
||||||
'whatsnew/2.5.rst',
|
'whatsnew/2.5',
|
||||||
'whatsnew/2.6.rst',
|
'whatsnew/2.6',
|
||||||
'maclib/scrap.rst',
|
'maclib/scrap',
|
||||||
'library/xmllib.rst',
|
'library/xmllib',
|
||||||
'library/xml.etree.rst',
|
'library/xml.etree',
|
||||||
]
|
]
|
||||||
|
|
||||||
# Relative filename of the reference count data file.
|
# Relative filename of the reference count data file.
|
||||||
|
|
|
@ -179,7 +179,7 @@ and add the following to the module initialization function::
|
||||||
|
|
||||||
MyObject_Type.ob_type = &PyType_Type;
|
MyObject_Type.ob_type = &PyType_Type;
|
||||||
|
|
||||||
Refer to section 3 of the `Python FAQ <http://www.python.org/doc/FAQ.html>`_ for
|
Refer to section 3 of the `Python FAQ <http://www.python.org/doc/faq>`_ for
|
||||||
details on why you must do this.
|
details on why you must do this.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
:mod:`decimal` --- Decimal floating point arithmetic
|
:mod:`decimal` --- Decimal fixed point and floating point arithmetic
|
||||||
====================================================
|
====================================================================
|
||||||
|
|
||||||
.. module:: decimal
|
.. module:: decimal
|
||||||
:synopsis: Implementation of the General Decimal Arithmetic Specification.
|
:synopsis: Implementation of the General Decimal Arithmetic Specification.
|
||||||
|
@ -16,6 +16,11 @@
|
||||||
The :mod:`decimal` module provides support for decimal floating point
|
The :mod:`decimal` module provides support for decimal floating point
|
||||||
arithmetic. It offers several advantages over the :class:`float` datatype:
|
arithmetic. It offers several advantages over the :class:`float` datatype:
|
||||||
|
|
||||||
|
* Decimal "is based on a floating-point model which was designed with people
|
||||||
|
in mind, and necessarily has a paramount guiding principle -- computers must
|
||||||
|
provide an arithmetic that works in the same way as the arithmetic that
|
||||||
|
people learn at school." -- excerpt from the decimal arithmetic specification.
|
||||||
|
|
||||||
* Decimal numbers can be represented exactly. In contrast, numbers like
|
* Decimal numbers can be represented exactly. In contrast, numbers like
|
||||||
:const:`1.1` do not have an exact representation in binary floating point. End
|
:const:`1.1` do not have an exact representation in binary floating point. End
|
||||||
users typically would not expect :const:`1.1` to display as
|
users typically would not expect :const:`1.1` to display as
|
||||||
|
@ -25,7 +30,7 @@ arithmetic. It offers several advantages over the :class:`float` datatype:
|
||||||
+ 0.1 + 0.1 - 0.3`` is exactly equal to zero. In binary floating point, the result
|
+ 0.1 + 0.1 - 0.3`` is exactly equal to zero. In binary floating point, the result
|
||||||
is :const:`5.5511151231257827e-017`. While near to zero, the differences
|
is :const:`5.5511151231257827e-017`. While near to zero, the differences
|
||||||
prevent reliable equality testing and differences can accumulate. For this
|
prevent reliable equality testing and differences can accumulate. For this
|
||||||
reason, decimal would be preferred in accounting applications which have strict
|
reason, decimal is preferred in accounting applications which have strict
|
||||||
equality invariants.
|
equality invariants.
|
||||||
|
|
||||||
* The decimal module incorporates a notion of significant places so that ``1.30
|
* The decimal module incorporates a notion of significant places so that ``1.30
|
||||||
|
@ -50,6 +55,13 @@ arithmetic. It offers several advantages over the :class:`float` datatype:
|
||||||
standards. While the built-in float type exposes only a modest portion of its
|
standards. While the built-in float type exposes only a modest portion of its
|
||||||
capabilities, the decimal module exposes all required parts of the standard.
|
capabilities, the decimal module exposes all required parts of the standard.
|
||||||
When needed, the programmer has full control over rounding and signal handling.
|
When needed, the programmer has full control over rounding and signal handling.
|
||||||
|
This includes an option to enforce exact arithmetic by using exceptions
|
||||||
|
to block any inexact operations.
|
||||||
|
|
||||||
|
* The decimal module was designed to support "without prejudice, both exact
|
||||||
|
unrounded decimal arithmetic (sometimes called fixed-point arithmetic)
|
||||||
|
and rounded floating-point arithmetic." -- excerpt from the decimal
|
||||||
|
arithmetic specification.
|
||||||
|
|
||||||
The module design is centered around three concepts: the decimal number, the
|
The module design is centered around three concepts: the decimal number, the
|
||||||
context for arithmetic, and signals.
|
context for arithmetic, and signals.
|
||||||
|
@ -832,7 +844,7 @@ described below. In addition, the module provides three pre-made contexts:
|
||||||
:const:`ROUND_HALF_EVEN`. All flags are cleared. No traps are enabled (so that
|
:const:`ROUND_HALF_EVEN`. All flags are cleared. No traps are enabled (so that
|
||||||
exceptions are not raised during computations).
|
exceptions are not raised during computations).
|
||||||
|
|
||||||
Because the trapped are disabled, this context is useful for applications that
|
Because the traps are disabled, this context is useful for applications that
|
||||||
prefer to have result value of :const:`NaN` or :const:`Infinity` instead of
|
prefer to have result value of :const:`NaN` or :const:`Infinity` instead of
|
||||||
raising exceptions. This allows an application to complete a run in the
|
raising exceptions. This allows an application to complete a run in the
|
||||||
presence of conditions that would otherwise halt the program.
|
presence of conditions that would otherwise halt the program.
|
||||||
|
@ -1245,7 +1257,7 @@ quiet or signaling :const:`NaN` always returns :const:`False` (even when doing
|
||||||
:const:`True`. An attempt to compare two Decimals using any of the ``<``,
|
:const:`True`. An attempt to compare two Decimals using any of the ``<``,
|
||||||
``<=``, ``>`` or ``>=`` operators will raise the :exc:`InvalidOperation` signal
|
``<=``, ``>`` or ``>=`` operators will raise the :exc:`InvalidOperation` signal
|
||||||
if either operand is a :const:`NaN`, and return :const:`False` if this signal is
|
if either operand is a :const:`NaN`, and return :const:`False` if this signal is
|
||||||
trapped. Note that the General Decimal Arithmetic specification does not
|
not trapped. Note that the General Decimal Arithmetic specification does not
|
||||||
specify the behavior of direct comparisons; these rules for comparisons
|
specify the behavior of direct comparisons; these rules for comparisons
|
||||||
involving a :const:`NaN` were taken from the IEEE 854 standard (see Table 3 in
|
involving a :const:`NaN` were taken from the IEEE 854 standard (see Table 3 in
|
||||||
section 5.7). To ensure strict standards-compliance, use the :meth:`compare`
|
section 5.7). To ensure strict standards-compliance, use the :meth:`compare`
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
|
|
||||||
:mod:`rational` --- Rational numbers
|
:mod:`fractions` --- Rational numbers
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
.. module:: rational
|
.. module:: fractions
|
||||||
:synopsis: Rational numbers.
|
:synopsis: Rational numbers.
|
||||||
.. moduleauthor:: Jeffrey Yasskin <jyasskin at gmail.com>
|
.. moduleauthor:: Jeffrey Yasskin <jyasskin at gmail.com>
|
||||||
.. sectionauthor:: Jeffrey Yasskin <jyasskin at gmail.com>
|
.. sectionauthor:: Jeffrey Yasskin <jyasskin at gmail.com>
|
||||||
.. versionadded:: 2.6
|
.. versionadded:: 2.6
|
||||||
|
|
||||||
|
|
||||||
The :mod:`rational` module defines an immutable, infinite-precision
|
The :mod:`fractions` module defines an immutable, infinite-precision
|
||||||
Rational number class.
|
Rational number class.
|
||||||
|
|
||||||
|
|
||||||
.. class:: Rational(numerator=0, denominator=1)
|
.. class:: Fraction(numerator=0, denominator=1)
|
||||||
Rational(other_rational)
|
Fraction(other_fraction)
|
||||||
Rational(string)
|
Fraction(string)
|
||||||
|
|
||||||
The first version requires that *numerator* and *denominator* are
|
The first version requires that *numerator* and *denominator* are
|
||||||
instances of :class:`numbers.Integral` and returns a new
|
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
|
*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:`numbers.Fraction` and returns an instance of
|
||||||
:class:`Rational` with the same value. The third version expects a
|
:class:`Rational` with the same value. The third version expects a
|
||||||
string of the form ``[-+]?[0-9]+(/[0-9]+)?``, optionally surrounded
|
string of the form ``[-+]?[0-9]+(/[0-9]+)?``, optionally surrounded
|
||||||
by spaces.
|
by spaces.
|
||||||
|
@ -31,39 +31,39 @@ Rational number class.
|
||||||
:class:`numbers.Rational` and is immutable and hashable.
|
: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
|
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 ``Rational(3,
|
||||||
10)``
|
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
|
exact value of *dec*, which must be a
|
||||||
:class:`decimal.Decimal`.
|
:class:`decimal.Decimal`.
|
||||||
|
|
||||||
|
|
||||||
.. method:: Rational.__floor__()
|
.. method:: Fraction.__floor__()
|
||||||
|
|
||||||
Returns the greatest :class:`int` ``<= self``. Will be accessible
|
Returns the greatest :class:`int` ``<= self``. Will be accessible
|
||||||
through :func:`math.floor` in Py3k.
|
through :func:`math.floor` in Py3k.
|
||||||
|
|
||||||
|
|
||||||
.. method:: Rational.__ceil__()
|
.. method:: Fraction.__ceil__()
|
||||||
|
|
||||||
Returns the least :class:`int` ``>= self``. Will be accessible
|
Returns the least :class:`int` ``>= self``. Will be accessible
|
||||||
through :func:`math.ceil` in Py3k.
|
through :func:`math.ceil` in Py3k.
|
||||||
|
|
||||||
|
|
||||||
.. method:: Rational.__round__()
|
.. method:: Fraction.__round__()
|
||||||
Rational.__round__(ndigits)
|
Fraction.__round__(ndigits)
|
||||||
|
|
||||||
The first version returns the nearest :class:`int` to ``self``,
|
The first version returns the nearest :class:`int` to ``self``,
|
||||||
rounding half to even. The second version rounds ``self`` to the
|
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
|
``ndigits`` is negative), again rounding half toward even. Will be
|
||||||
accessible through :func:`round` in Py3k.
|
accessible through :func:`round` in Py3k.
|
||||||
|
|
|
@ -104,7 +104,7 @@ Notes for type implementors
|
||||||
|
|
||||||
Implementors should be careful to make equal numbers equal and hash
|
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
|
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::
|
implements :func:`hash` as follows::
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
|
@ -199,11 +199,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,
|
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
|
it can be useful to define a helper function which generates the
|
||||||
forward and reverse instances of any given operator. For example,
|
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 _operator_fallbacks(monomorphic_operator, fallback_operator):
|
||||||
def forward(a, b):
|
def forward(a, b):
|
||||||
if isinstance(b, (int, long, Rational)):
|
if isinstance(b, (int, long, Fraction)):
|
||||||
return monomorphic_operator(a, b)
|
return monomorphic_operator(a, b)
|
||||||
elif isinstance(b, float):
|
elif isinstance(b, float):
|
||||||
return fallback_operator(float(a), b)
|
return fallback_operator(float(a), b)
|
||||||
|
@ -215,7 +215,7 @@ forward and reverse instances of any given operator. For example,
|
||||||
forward.__doc__ = monomorphic_operator.__doc__
|
forward.__doc__ = monomorphic_operator.__doc__
|
||||||
|
|
||||||
def reverse(b, a):
|
def reverse(b, a):
|
||||||
if isinstance(a, RationalAbc):
|
if isinstance(a, Rational):
|
||||||
# Includes ints.
|
# Includes ints.
|
||||||
return monomorphic_operator(a, b)
|
return monomorphic_operator(a, b)
|
||||||
elif isinstance(a, numbers.Real):
|
elif isinstance(a, numbers.Real):
|
||||||
|
@ -231,7 +231,7 @@ forward and reverse instances of any given operator. For example,
|
||||||
|
|
||||||
def _add(a, b):
|
def _add(a, b):
|
||||||
"""a + b"""
|
"""a + b"""
|
||||||
return Rational(a.numerator * b.denominator +
|
return Fraction(a.numerator * b.denominator +
|
||||||
b.numerator * a.denominator,
|
b.numerator * a.denominator,
|
||||||
a.denominator * b.denominator)
|
a.denominator * b.denominator)
|
||||||
|
|
||||||
|
|
|
@ -33,3 +33,10 @@ probably won't find the :mod:`pickletools` module relevant.
|
||||||
the opcode's argument; *pos* is the position at which this opcode is located.
|
the opcode's argument; *pos* is the position at which this opcode is located.
|
||||||
*pickle* can be a string or a file-like object.
|
*pickle* can be a string or a file-like object.
|
||||||
|
|
||||||
|
.. function:: optimize(picklestring)
|
||||||
|
|
||||||
|
Returns a new equivalent pickle string after eliminating unused ``PUT``
|
||||||
|
opcodes. The optimized pickle is shorter, takes less transmission time,
|
||||||
|
requires less storage space, and unpickles more efficiently.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6
|
||||||
|
|
|
@ -578,8 +578,8 @@ and comparisons.
|
||||||
|
|
||||||
:class:`Rational` numbers derive from :class:`Real`, have
|
:class:`Rational` numbers derive from :class:`Real`, have
|
||||||
:attr:`numerator` and :attr:`denominator` properties, and can be
|
:attr:`numerator` and :attr:`denominator` properties, and can be
|
||||||
converted to floats. Python 2.6 adds a simple rational-number class
|
converted to floats. Python 2.6 adds a simple rational-number class,
|
||||||
in the :mod:`rational` module.
|
:class:`Fraction`, in the :mod:`fractions` module.
|
||||||
|
|
||||||
:class:`Integral` numbers derive from :class:`Rational`, and
|
:class:`Integral` numbers derive from :class:`Rational`, and
|
||||||
can be shifted left and right with ``<<`` 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
|
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
|
represented as a fraction; rational numbers can exactly represent
|
||||||
numbers such as two-thirds that floating-point numbers can only
|
numbers such as two-thirds that floating-point numbers can only
|
||||||
approximate.
|
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. ::
|
that will be the numerator and denominator of the resulting fraction. ::
|
||||||
|
|
||||||
>>> from rational import Rational
|
>>> from fractions import Fraction
|
||||||
>>> a = Rational(2, 3)
|
>>> a = Fraction(2, 3)
|
||||||
>>> b = Rational(2, 5)
|
>>> b = Fraction(2, 5)
|
||||||
>>> float(a), float(b)
|
>>> float(a), float(b)
|
||||||
(0.66666666666666663, 0.40000000000000002)
|
(0.66666666666666663, 0.40000000000000002)
|
||||||
>>> a+b
|
>>> a+b
|
||||||
rational.Rational(16,15)
|
Fraction(16, 15)
|
||||||
>>> a/b
|
>>> 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
|
Mullender that was in Python's :file:`Demo/classes/` directory for a
|
||||||
long time. This implementation was significantly updated by Jeffrey
|
long time. This implementation was significantly updated by Jeffrey
|
||||||
Yaskin.
|
Yaskin.
|
||||||
|
|
|
@ -802,7 +802,7 @@ class Decimal(_numbers.Real, _numbers.Inexact):
|
||||||
# != comparisons involving a NaN always return True
|
# != comparisons involving a NaN always return True
|
||||||
# <, >, <= and >= comparisons involving a (quiet or signaling)
|
# <, >, <= and >= comparisons involving a (quiet or signaling)
|
||||||
# NaN signal InvalidOperation, and return False if the
|
# NaN signal InvalidOperation, and return False if the
|
||||||
# InvalidOperation is trapped.
|
# InvalidOperation is not trapped.
|
||||||
#
|
#
|
||||||
# This behavior is designed to conform as closely as possible to
|
# This behavior is designed to conform as closely as possible to
|
||||||
# that specified by IEEE 754.
|
# that specified by IEEE 754.
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
# Originally contributed by Sjoerd Mullender.
|
# Originally contributed by Sjoerd Mullender.
|
||||||
# Significantly modified by Jeffrey Yasskin <jyasskin at gmail.com>.
|
# Significantly modified by Jeffrey Yasskin <jyasskin at gmail.com>.
|
||||||
|
|
||||||
"""Rational, infinite-precision, real numbers."""
|
"""Fraction, infinite-precision, real numbers."""
|
||||||
|
|
||||||
import math
|
import math
|
||||||
import numbers
|
import numbers
|
||||||
import operator
|
import operator
|
||||||
import re
|
import re
|
||||||
|
|
||||||
__all__ = ["Rational"]
|
__all__ = ["Fraction"]
|
||||||
|
|
||||||
RationalAbc = numbers.Rational
|
|
||||||
|
|
||||||
|
|
||||||
def gcd(a, b):
|
def gcd(a, b):
|
||||||
|
@ -38,15 +37,15 @@ _RATIONAL_FORMAT = re.compile(r"""
|
||||||
""", re.VERBOSE)
|
""", re.VERBOSE)
|
||||||
|
|
||||||
|
|
||||||
class Rational(RationalAbc):
|
class Fraction(numbers.Rational):
|
||||||
"""This class implements rational numbers.
|
"""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
|
4/3. Both arguments must be Integral. The numerator defaults to 0
|
||||||
and the denominator defaults to 1 so that Rational(3) == 3 and
|
and the denominator defaults to 1 so that Fraction(3) == 3 and
|
||||||
Rational() == 0.
|
Fraction() == 0.
|
||||||
|
|
||||||
Rationals can also be constructed from strings of the form
|
Fraction can also be constructed from strings of the form
|
||||||
'[-+]?[0-9]+((/|.)[0-9]+)?', optionally surrounded by spaces.
|
'[-+]?[0-9]+((/|.)[0-9]+)?', optionally surrounded by spaces.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -61,7 +60,7 @@ class Rational(RationalAbc):
|
||||||
numerator/denominator pair.
|
numerator/denominator pair.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self = super(Rational, cls).__new__(cls)
|
self = super(Fraction, cls).__new__(cls)
|
||||||
|
|
||||||
if denominator == 1:
|
if denominator == 1:
|
||||||
if isinstance(numerator, str):
|
if isinstance(numerator, str):
|
||||||
|
@ -69,7 +68,7 @@ class Rational(RationalAbc):
|
||||||
input = numerator
|
input = numerator
|
||||||
m = _RATIONAL_FORMAT.match(input)
|
m = _RATIONAL_FORMAT.match(input)
|
||||||
if m is None:
|
if m is None:
|
||||||
raise ValueError('Invalid literal for Rational: ' + input)
|
raise ValueError('Invalid literal for Fraction: ' + input)
|
||||||
numerator = m.group('num')
|
numerator = m.group('num')
|
||||||
decimal = m.group('decimal')
|
decimal = m.group('decimal')
|
||||||
if decimal:
|
if decimal:
|
||||||
|
@ -86,7 +85,7 @@ class Rational(RationalAbc):
|
||||||
numerator = -numerator
|
numerator = -numerator
|
||||||
|
|
||||||
elif (not isinstance(numerator, numbers.Integral) and
|
elif (not isinstance(numerator, numbers.Integral) and
|
||||||
isinstance(numerator, RationalAbc)):
|
isinstance(numerator, numbers.Rational)):
|
||||||
# Handle copies from other rationals.
|
# Handle copies from other rationals.
|
||||||
other_rational = numerator
|
other_rational = numerator
|
||||||
numerator = other_rational.numerator
|
numerator = other_rational.numerator
|
||||||
|
@ -94,11 +93,11 @@ class Rational(RationalAbc):
|
||||||
|
|
||||||
if (not isinstance(numerator, numbers.Integral) or
|
if (not isinstance(numerator, numbers.Integral) or
|
||||||
not isinstance(denominator, numbers.Integral)):
|
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())
|
" Both arguments must be integral." % locals())
|
||||||
|
|
||||||
if denominator == 0:
|
if denominator == 0:
|
||||||
raise ZeroDivisionError('Rational(%s, 0)' % numerator)
|
raise ZeroDivisionError('Fraction(%s, 0)' % numerator)
|
||||||
|
|
||||||
g = gcd(numerator, denominator)
|
g = gcd(numerator, denominator)
|
||||||
self._numerator = int(numerator // g)
|
self._numerator = int(numerator // g)
|
||||||
|
@ -109,7 +108,7 @@ class Rational(RationalAbc):
|
||||||
def from_float(cls, f):
|
def from_float(cls, f):
|
||||||
"""Converts a finite float to a rational number, exactly.
|
"""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):
|
if not isinstance(f, float):
|
||||||
|
@ -141,7 +140,7 @@ class Rational(RationalAbc):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_continued_fraction(cls, seq):
|
def from_continued_fraction(cls, 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
|
n, d = 1, 0
|
||||||
for e in reversed(seq):
|
for e in reversed(seq):
|
||||||
n, d = d, n
|
n, d = d, n
|
||||||
|
@ -168,7 +167,7 @@ class Rational(RationalAbc):
|
||||||
if self.denominator <= max_denominator:
|
if self.denominator <= max_denominator:
|
||||||
return self
|
return self
|
||||||
cf = self.as_continued_fraction()
|
cf = self.as_continued_fraction()
|
||||||
result = Rational(0)
|
result = Fraction(0)
|
||||||
for i in range(1, len(cf)):
|
for i in range(1, len(cf)):
|
||||||
new = self.from_continued_fraction(cf[:i])
|
new = self.from_continued_fraction(cf[:i])
|
||||||
if new.denominator > max_denominator:
|
if new.denominator > max_denominator:
|
||||||
|
@ -186,7 +185,7 @@ class Rational(RationalAbc):
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""repr(self)"""
|
"""repr(self)"""
|
||||||
return ('Rational(%r,%r)' % (self.numerator, self.denominator))
|
return ('Fraction(%r,%r)' % (self.numerator, self.denominator))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""str(self)"""
|
"""str(self)"""
|
||||||
|
@ -206,13 +205,13 @@ class Rational(RationalAbc):
|
||||||
that mixed-mode operations either call an implementation whose
|
that mixed-mode operations either call an implementation whose
|
||||||
author knew about the types of both arguments, or convert both
|
author knew about the types of both arguments, or convert both
|
||||||
to the nearest built in type and do the operation there. In
|
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):
|
def __add__(self, other):
|
||||||
# Both types have numerators/denominator attributes,
|
# Both types have numerators/denominator attributes,
|
||||||
# so do the operation directly
|
# so do the operation directly
|
||||||
if isinstance(other, (int, Rational)):
|
if isinstance(other, (int, Fraction)):
|
||||||
return Rational(self.numerator * other.denominator +
|
return Fraction(self.numerator * other.denominator +
|
||||||
other.numerator * self.denominator,
|
other.numerator * self.denominator,
|
||||||
self.denominator * other.denominator)
|
self.denominator * other.denominator)
|
||||||
# float and complex don't have those operations, but we
|
# float and complex don't have those operations, but we
|
||||||
|
@ -227,8 +226,8 @@ class Rational(RationalAbc):
|
||||||
def __radd__(self, other):
|
def __radd__(self, other):
|
||||||
# radd handles more types than add because there's
|
# radd handles more types than add because there's
|
||||||
# nothing left to fall back to.
|
# nothing left to fall back to.
|
||||||
if isinstance(other, RationalAbc):
|
if isinstance(other, numbers.Rational):
|
||||||
return Rational(self.numerator * other.denominator +
|
return Fraction(self.numerator * other.denominator +
|
||||||
other.numerator * self.denominator,
|
other.numerator * self.denominator,
|
||||||
self.denominator * other.denominator)
|
self.denominator * other.denominator)
|
||||||
elif isinstance(other, Real):
|
elif isinstance(other, Real):
|
||||||
|
@ -239,32 +238,32 @@ class Rational(RationalAbc):
|
||||||
|
|
||||||
|
|
||||||
There are 5 different cases for a mixed-type addition on
|
There are 5 different cases for a mixed-type addition on
|
||||||
Rational. I'll refer to all of the above code that doesn't
|
Fraction. I'll refer to all of the above code that doesn't
|
||||||
refer to Rational, float, or complex as "boilerplate". 'r'
|
refer to Fraction, float, or complex as "boilerplate". 'r'
|
||||||
will be an instance of Rational, which is a subtype of
|
will be an instance of Fraction, which is a subtype of
|
||||||
RationalAbc (r : Rational <: RationalAbc), and b : B <:
|
Rational (r : Fraction <: Rational), and b : B <:
|
||||||
Complex. The first three involve 'r + 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.
|
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
|
were to return a value from __add__, we'd miss the
|
||||||
possibility that B defines a more intelligent __radd__,
|
possibility that B defines a more intelligent __radd__,
|
||||||
so the boilerplate should return NotImplemented from
|
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
|
here, even though we could get an exact answer, in case
|
||||||
the other type wants to do something special.
|
the other type wants to do something special.
|
||||||
3. If B <: Rational, Python tries B.__radd__ before
|
3. If B <: Fraction, Python tries B.__radd__ before
|
||||||
Rational.__add__. This is ok, because it was
|
Fraction.__add__. This is ok, because it was
|
||||||
implemented with knowledge of Rational, so it can
|
implemented with knowledge of Fraction, so it can
|
||||||
handle those instances before delegating to Real or
|
handle those instances before delegating to Real or
|
||||||
Complex.
|
Complex.
|
||||||
|
|
||||||
The next two situations describe 'b + r'. We assume that b
|
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:
|
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
|
builtin rational type (hey look, that's us) and
|
||||||
proceeds.
|
proceeds.
|
||||||
5. Otherwise, __radd__ tries to find the nearest common
|
5. Otherwise, __radd__ tries to find the nearest common
|
||||||
|
@ -276,7 +275,7 @@ class Rational(RationalAbc):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def forward(a, b):
|
def forward(a, b):
|
||||||
if isinstance(b, (int, Rational)):
|
if isinstance(b, (int, Fraction)):
|
||||||
return monomorphic_operator(a, b)
|
return monomorphic_operator(a, b)
|
||||||
elif isinstance(b, float):
|
elif isinstance(b, float):
|
||||||
return fallback_operator(float(a), b)
|
return fallback_operator(float(a), b)
|
||||||
|
@ -288,7 +287,7 @@ class Rational(RationalAbc):
|
||||||
forward.__doc__ = monomorphic_operator.__doc__
|
forward.__doc__ = monomorphic_operator.__doc__
|
||||||
|
|
||||||
def reverse(b, a):
|
def reverse(b, a):
|
||||||
if isinstance(a, RationalAbc):
|
if isinstance(a, numbers.Rational):
|
||||||
# Includes ints.
|
# Includes ints.
|
||||||
return monomorphic_operator(a, b)
|
return monomorphic_operator(a, b)
|
||||||
elif isinstance(a, numbers.Real):
|
elif isinstance(a, numbers.Real):
|
||||||
|
@ -304,7 +303,7 @@ class Rational(RationalAbc):
|
||||||
|
|
||||||
def _add(a, b):
|
def _add(a, b):
|
||||||
"""a + b"""
|
"""a + b"""
|
||||||
return Rational(a.numerator * b.denominator +
|
return Fraction(a.numerator * b.denominator +
|
||||||
b.numerator * a.denominator,
|
b.numerator * a.denominator,
|
||||||
a.denominator * b.denominator)
|
a.denominator * b.denominator)
|
||||||
|
|
||||||
|
@ -312,7 +311,7 @@ class Rational(RationalAbc):
|
||||||
|
|
||||||
def _sub(a, b):
|
def _sub(a, b):
|
||||||
"""a - b"""
|
"""a - b"""
|
||||||
return Rational(a.numerator * b.denominator -
|
return Fraction(a.numerator * b.denominator -
|
||||||
b.numerator * a.denominator,
|
b.numerator * a.denominator,
|
||||||
a.denominator * b.denominator)
|
a.denominator * b.denominator)
|
||||||
|
|
||||||
|
@ -320,13 +319,13 @@ class Rational(RationalAbc):
|
||||||
|
|
||||||
def _mul(a, b):
|
def _mul(a, b):
|
||||||
"""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)
|
__mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul)
|
||||||
|
|
||||||
def _div(a, b):
|
def _div(a, b):
|
||||||
"""a / b"""
|
"""a / b"""
|
||||||
return Rational(a.numerator * b.denominator,
|
return Fraction(a.numerator * b.denominator,
|
||||||
a.denominator * b.numerator)
|
a.denominator * b.numerator)
|
||||||
|
|
||||||
__truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv)
|
__truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv)
|
||||||
|
@ -357,14 +356,14 @@ class Rational(RationalAbc):
|
||||||
result will be rational.
|
result will be rational.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if isinstance(b, RationalAbc):
|
if isinstance(b, numbers.Rational):
|
||||||
if b.denominator == 1:
|
if b.denominator == 1:
|
||||||
power = b.numerator
|
power = b.numerator
|
||||||
if power >= 0:
|
if power >= 0:
|
||||||
return Rational(a.numerator ** power,
|
return Fraction(a.numerator ** power,
|
||||||
a.denominator ** power)
|
a.denominator ** power)
|
||||||
else:
|
else:
|
||||||
return Rational(a.denominator ** -power,
|
return Fraction(a.denominator ** -power,
|
||||||
a.numerator ** -power)
|
a.numerator ** -power)
|
||||||
else:
|
else:
|
||||||
# A fractional power will generally produce an
|
# A fractional power will generally produce an
|
||||||
|
@ -379,8 +378,8 @@ class Rational(RationalAbc):
|
||||||
# If a is an int, keep it that way if possible.
|
# If a is an int, keep it that way if possible.
|
||||||
return a ** b.numerator
|
return a ** b.numerator
|
||||||
|
|
||||||
if isinstance(a, RationalAbc):
|
if isinstance(a, numbers.Rational):
|
||||||
return Rational(a.numerator, a.denominator) ** b
|
return Fraction(a.numerator, a.denominator) ** b
|
||||||
|
|
||||||
if b.denominator == 1:
|
if b.denominator == 1:
|
||||||
return a ** b.numerator
|
return a ** b.numerator
|
||||||
|
@ -388,16 +387,16 @@ class Rational(RationalAbc):
|
||||||
return a ** float(b)
|
return a ** float(b)
|
||||||
|
|
||||||
def __pos__(a):
|
def __pos__(a):
|
||||||
"""+a: Coerces a subclass instance to Rational"""
|
"""+a: Coerces a subclass instance to Fraction"""
|
||||||
return Rational(a.numerator, a.denominator)
|
return Fraction(a.numerator, a.denominator)
|
||||||
|
|
||||||
def __neg__(a):
|
def __neg__(a):
|
||||||
"""-a"""
|
"""-a"""
|
||||||
return Rational(-a.numerator, a.denominator)
|
return Fraction(-a.numerator, a.denominator)
|
||||||
|
|
||||||
def __abs__(a):
|
def __abs__(a):
|
||||||
"""abs(a)"""
|
"""abs(a)"""
|
||||||
return Rational(abs(a.numerator), a.denominator)
|
return Fraction(abs(a.numerator), a.denominator)
|
||||||
|
|
||||||
def __trunc__(a):
|
def __trunc__(a):
|
||||||
"""trunc(a)"""
|
"""trunc(a)"""
|
||||||
|
@ -433,12 +432,12 @@ class Rational(RationalAbc):
|
||||||
return floor + 1
|
return floor + 1
|
||||||
shift = 10**abs(ndigits)
|
shift = 10**abs(ndigits)
|
||||||
# See _operator_fallbacks.forward to check that the results of
|
# See _operator_fallbacks.forward to check that the results of
|
||||||
# these operations will always be Rational and therefore have
|
# these operations will always be Fraction and therefore have
|
||||||
# round().
|
# round().
|
||||||
if ndigits > 0:
|
if ndigits > 0:
|
||||||
return Rational(round(self * shift), shift)
|
return Fraction(round(self * shift), shift)
|
||||||
else:
|
else:
|
||||||
return Rational(round(self / shift) * shift)
|
return Fraction(round(self / shift) * shift)
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
"""hash(self)
|
"""hash(self)
|
||||||
|
@ -461,7 +460,7 @@ class Rational(RationalAbc):
|
||||||
|
|
||||||
def __eq__(a, b):
|
def __eq__(a, b):
|
||||||
"""a == b"""
|
"""a == b"""
|
||||||
if isinstance(b, RationalAbc):
|
if isinstance(b, numbers.Rational):
|
||||||
return (a.numerator == b.numerator and
|
return (a.numerator == b.numerator and
|
||||||
a.denominator == b.denominator)
|
a.denominator == b.denominator)
|
||||||
if isinstance(b, numbers.Complex) and b.imag == 0:
|
if isinstance(b, numbers.Complex) and b.imag == 0:
|
||||||
|
@ -488,7 +487,7 @@ class Rational(RationalAbc):
|
||||||
if isinstance(b, float):
|
if isinstance(b, float):
|
||||||
b = a.from_float(b)
|
b = a.from_float(b)
|
||||||
try:
|
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
|
# to fall back to a float. If the actual values differ by
|
||||||
# less than MIN_FLOAT, this could falsely call them equal,
|
# less than MIN_FLOAT, this could falsely call them equal,
|
||||||
# which would make <= inconsistent with ==. Better ways of
|
# which would make <= inconsistent with ==. Better ways of
|
||||||
|
@ -496,7 +495,7 @@ class Rational(RationalAbc):
|
||||||
diff = a - b
|
diff = a - b
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
if isinstance(diff, RationalAbc):
|
if isinstance(diff, numbers.Rational):
|
||||||
return op(diff.numerator, 0)
|
return op(diff.numerator, 0)
|
||||||
return op(diff, 0)
|
return op(diff, 0)
|
||||||
|
|
||||||
|
@ -526,11 +525,11 @@ class Rational(RationalAbc):
|
||||||
return (self.__class__, (str(self),))
|
return (self.__class__, (str(self),))
|
||||||
|
|
||||||
def __copy__(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 # I'm immutable; therefore I am my own clone
|
||||||
return self.__class__(self.numerator, self.denominator)
|
return self.__class__(self.numerator, self.denominator)
|
||||||
|
|
||||||
def __deepcopy__(self, memo):
|
def __deepcopy__(self, memo):
|
||||||
if type(self) == Rational:
|
if type(self) == Fraction:
|
||||||
return self # My components are also immutable
|
return self # My components are also immutable
|
||||||
return self.__class__(self.numerator, self.denominator)
|
return self.__class__(self.numerator, self.denominator)
|
|
@ -14,9 +14,7 @@ import codecs
|
||||||
import pickle
|
import pickle
|
||||||
import re
|
import re
|
||||||
|
|
||||||
__all__ = ['dis',
|
__all__ = ['dis', 'genops', 'optimize']
|
||||||
'genops',
|
|
||||||
]
|
|
||||||
|
|
||||||
bytes_types = pickle.bytes_types
|
bytes_types = pickle.bytes_types
|
||||||
|
|
||||||
|
@ -1835,6 +1833,33 @@ def genops(pickle):
|
||||||
assert opcode.name == 'STOP'
|
assert opcode.name == 'STOP'
|
||||||
break
|
break
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# A pickle optimizer.
|
||||||
|
|
||||||
|
def optimize(p):
|
||||||
|
'Optimize a pickle string by removing unused PUT opcodes'
|
||||||
|
gets = set() # set of args used by a GET opcode
|
||||||
|
puts = [] # (arg, startpos, stoppos) for the PUT opcodes
|
||||||
|
prevpos = None # set to pos if previous opcode was a PUT
|
||||||
|
for opcode, arg, pos in genops(p):
|
||||||
|
if prevpos is not None:
|
||||||
|
puts.append((prevarg, prevpos, pos))
|
||||||
|
prevpos = None
|
||||||
|
if 'PUT' in opcode.name:
|
||||||
|
prevarg, prevpos = arg, pos
|
||||||
|
elif 'GET' in opcode.name:
|
||||||
|
gets.add(arg)
|
||||||
|
|
||||||
|
# Copy the pickle string except for PUTS without a corresponding GET
|
||||||
|
s = []
|
||||||
|
i = 0
|
||||||
|
for arg, start, stop in puts:
|
||||||
|
j = stop if (arg in gets) else start
|
||||||
|
s.append(p[i:j])
|
||||||
|
i = stop
|
||||||
|
s.append(p[i:])
|
||||||
|
return ''.join(s)
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# A symbolic pickle disassembler.
|
# A symbolic pickle disassembler.
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ from test.test_support import fcmp, TESTFN, unlink, run_unittest, \
|
||||||
run_with_locale
|
run_with_locale
|
||||||
from operator import neg
|
from operator import neg
|
||||||
|
|
||||||
import sys, warnings, random, collections, io, rational
|
import sys, warnings, random, collections, io, rational, fractions
|
||||||
warnings.filterwarnings("ignore", "hex../oct.. of negative int",
|
warnings.filterwarnings("ignore", "hex../oct.. of negative int",
|
||||||
FutureWarning, __name__)
|
FutureWarning, __name__)
|
||||||
warnings.filterwarnings("ignore", "integer argument expected",
|
warnings.filterwarnings("ignore", "integer argument expected",
|
||||||
|
@ -607,7 +607,7 @@ class BuiltinTest(unittest.TestCase):
|
||||||
n, d = f.as_integer_ratio()
|
n, d = f.as_integer_ratio()
|
||||||
self.assertEqual(float(n).__truediv__(d), f)
|
self.assertEqual(float(n).__truediv__(d), f)
|
||||||
|
|
||||||
R = rational.Rational
|
R = fractions.Fraction
|
||||||
self.assertEqual(R(0, 1),
|
self.assertEqual(R(0, 1),
|
||||||
R(*float(0.0).as_integer_ratio()))
|
R(*float(0.0).as_integer_ratio()))
|
||||||
self.assertEqual(R(5, 2),
|
self.assertEqual(R(5, 2),
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
"""Tests for Lib/rational.py."""
|
"""Tests for Lib/fractions.py."""
|
||||||
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from test.test_support import run_unittest, verbose
|
from test.test_support import run_unittest, verbose
|
||||||
import math
|
import math
|
||||||
import operator
|
import operator
|
||||||
import rational
|
import fractions
|
||||||
import unittest
|
import unittest
|
||||||
from copy import copy, deepcopy
|
from copy import copy, deepcopy
|
||||||
from pickle import dumps, loads
|
from pickle import dumps, loads
|
||||||
R = rational.Rational
|
R = fractions.Fraction
|
||||||
gcd = rational.gcd
|
gcd = fractions.gcd
|
||||||
|
|
||||||
|
|
||||||
class GcdTest(unittest.TestCase):
|
class GcdTest(unittest.TestCase):
|
||||||
|
@ -31,7 +31,7 @@ def _components(r):
|
||||||
return (r.numerator, r.denominator)
|
return (r.numerator, r.denominator)
|
||||||
|
|
||||||
|
|
||||||
class RationalTest(unittest.TestCase):
|
class FractionTest(unittest.TestCase):
|
||||||
|
|
||||||
def assertTypedEquals(self, expected, actual):
|
def assertTypedEquals(self, expected, actual):
|
||||||
"""Asserts that both the types and values are the same."""
|
"""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((7, 15), _components(R(7, 15)))
|
||||||
self.assertEquals((10**23, 1), _components(R(10**23)))
|
self.assertEquals((10**23, 1), _components(R(10**23)))
|
||||||
|
|
||||||
self.assertRaisesMessage(ZeroDivisionError, "Rational(12, 0)",
|
self.assertRaisesMessage(ZeroDivisionError, "Fraction(12, 0)",
|
||||||
R, 12, 0)
|
R, 12, 0)
|
||||||
self.assertRaises(TypeError, R, 1.5)
|
self.assertRaises(TypeError, R, 1.5)
|
||||||
self.assertRaises(TypeError, R, 1.5 + 3j)
|
self.assertRaises(TypeError, R, 1.5 + 3j)
|
||||||
|
@ -81,41 +81,41 @@ class RationalTest(unittest.TestCase):
|
||||||
self.assertEquals((3, 5), _components(R(" .6 ")))
|
self.assertEquals((3, 5), _components(R(" .6 ")))
|
||||||
|
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
ZeroDivisionError, "Rational(3, 0)",
|
ZeroDivisionError, "Fraction(3, 0)",
|
||||||
R, "3/0")
|
R, "3/0")
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
ValueError, "Invalid literal for Rational: 3/",
|
ValueError, "Invalid literal for Fraction: 3/",
|
||||||
R, "3/")
|
R, "3/")
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
ValueError, "Invalid literal for Rational: 3 /2",
|
ValueError, "Invalid literal for Fraction: 3 /2",
|
||||||
R, "3 /2")
|
R, "3 /2")
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
# Denominators don't need a sign.
|
# Denominators don't need a sign.
|
||||||
ValueError, "Invalid literal for Rational: 3/+2",
|
ValueError, "Invalid literal for Fraction: 3/+2",
|
||||||
R, "3/+2")
|
R, "3/+2")
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
# Imitate float's parsing.
|
# Imitate float's parsing.
|
||||||
ValueError, "Invalid literal for Rational: + 3/2",
|
ValueError, "Invalid literal for Fraction: + 3/2",
|
||||||
R, "+ 3/2")
|
R, "+ 3/2")
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
# Avoid treating '.' as a regex special character.
|
# Avoid treating '.' as a regex special character.
|
||||||
ValueError, "Invalid literal for Rational: 3a2",
|
ValueError, "Invalid literal for Fraction: 3a2",
|
||||||
R, "3a2")
|
R, "3a2")
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
# Only parse ordinary decimals, not scientific form.
|
# Only parse ordinary decimals, not scientific form.
|
||||||
ValueError, "Invalid literal for Rational: 3.2e4",
|
ValueError, "Invalid literal for Fraction: 3.2e4",
|
||||||
R, "3.2e4")
|
R, "3.2e4")
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
# Don't accept combinations of decimals and rationals.
|
# Don't accept combinations of decimals and rationals.
|
||||||
ValueError, "Invalid literal for Rational: 3/7.2",
|
ValueError, "Invalid literal for Fraction: 3/7.2",
|
||||||
R, "3/7.2")
|
R, "3/7.2")
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
# Don't accept combinations of decimals and rationals.
|
# Don't accept combinations of decimals and rationals.
|
||||||
ValueError, "Invalid literal for Rational: 3.2/7",
|
ValueError, "Invalid literal for Fraction: 3.2/7",
|
||||||
R, "3.2/7")
|
R, "3.2/7")
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
# Allow 3. and .3, but not .
|
# Allow 3. and .3, but not .
|
||||||
ValueError, "Invalid literal for Rational: .",
|
ValueError, "Invalid literal for Fraction: .",
|
||||||
R, ".")
|
R, ".")
|
||||||
|
|
||||||
def testImmutable(self):
|
def testImmutable(self):
|
||||||
|
@ -136,7 +136,7 @@ class RationalTest(unittest.TestCase):
|
||||||
|
|
||||||
def testFromFloat(self):
|
def testFromFloat(self):
|
||||||
self.assertRaisesMessage(
|
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)
|
R.from_float, 3)
|
||||||
|
|
||||||
self.assertEquals((0, 1), _components(R.from_float(-0.0)))
|
self.assertEquals((0, 1), _components(R.from_float(-0.0)))
|
||||||
|
@ -152,19 +152,19 @@ class RationalTest(unittest.TestCase):
|
||||||
inf = 1e1000
|
inf = 1e1000
|
||||||
nan = inf - inf
|
nan = inf - inf
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
TypeError, "Cannot convert inf to Rational.",
|
TypeError, "Cannot convert inf to Fraction.",
|
||||||
R.from_float, inf)
|
R.from_float, inf)
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
TypeError, "Cannot convert -inf to Rational.",
|
TypeError, "Cannot convert -inf to Fraction.",
|
||||||
R.from_float, -inf)
|
R.from_float, -inf)
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
TypeError, "Cannot convert nan to Rational.",
|
TypeError, "Cannot convert nan to Fraction.",
|
||||||
R.from_float, nan)
|
R.from_float, nan)
|
||||||
|
|
||||||
def testFromDecimal(self):
|
def testFromDecimal(self):
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
TypeError,
|
TypeError,
|
||||||
"Rational.from_decimal() only takes Decimals, not 3 (int)",
|
"Fraction.from_decimal() only takes Decimals, not 3 (int)",
|
||||||
R.from_decimal, 3)
|
R.from_decimal, 3)
|
||||||
self.assertEquals(R(0), R.from_decimal(Decimal("-0")))
|
self.assertEquals(R(0), R.from_decimal(Decimal("-0")))
|
||||||
self.assertEquals(R(5, 10), R.from_decimal(Decimal("0.5")))
|
self.assertEquals(R(5, 10), R.from_decimal(Decimal("0.5")))
|
||||||
|
@ -174,16 +174,16 @@ class RationalTest(unittest.TestCase):
|
||||||
R.from_decimal(Decimal("0." + "9" * 30)))
|
R.from_decimal(Decimal("0." + "9" * 30)))
|
||||||
|
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
TypeError, "Cannot convert Infinity to Rational.",
|
TypeError, "Cannot convert Infinity to Fraction.",
|
||||||
R.from_decimal, Decimal("inf"))
|
R.from_decimal, Decimal("inf"))
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
TypeError, "Cannot convert -Infinity to Rational.",
|
TypeError, "Cannot convert -Infinity to Fraction.",
|
||||||
R.from_decimal, Decimal("-inf"))
|
R.from_decimal, Decimal("-inf"))
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
TypeError, "Cannot convert NaN to Rational.",
|
TypeError, "Cannot convert NaN to Fraction.",
|
||||||
R.from_decimal, Decimal("nan"))
|
R.from_decimal, Decimal("nan"))
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
TypeError, "Cannot convert sNaN to Rational.",
|
TypeError, "Cannot convert sNaN to Fraction.",
|
||||||
R.from_decimal, Decimal("snan"))
|
R.from_decimal, Decimal("snan"))
|
||||||
|
|
||||||
def testFromContinuedFraction(self):
|
def testFromContinuedFraction(self):
|
||||||
|
@ -316,7 +316,7 @@ class RationalTest(unittest.TestCase):
|
||||||
# Decimal refuses mixed comparisons.
|
# Decimal refuses mixed comparisons.
|
||||||
self.assertRaisesMessage(
|
self.assertRaisesMessage(
|
||||||
TypeError,
|
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'))
|
operator.add, R(3,11), Decimal('3.1415926'))
|
||||||
self.assertNotEquals(R(5, 2), Decimal('2.5'))
|
self.assertNotEquals(R(5, 2), Decimal('2.5'))
|
||||||
|
|
||||||
|
@ -378,7 +378,7 @@ class RationalTest(unittest.TestCase):
|
||||||
self.assertFalse(R(5, 2) == 2)
|
self.assertFalse(R(5, 2) == 2)
|
||||||
|
|
||||||
def testStringification(self):
|
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/3", str(R(7, 3)))
|
||||||
self.assertEquals("7", str(R(7, 1)))
|
self.assertEquals("7", str(R(7, 1)))
|
||||||
|
|
||||||
|
@ -421,7 +421,7 @@ class RationalTest(unittest.TestCase):
|
||||||
self.assertEqual(id(r), id(deepcopy(r)))
|
self.assertEqual(id(r), id(deepcopy(r)))
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
run_unittest(RationalTest, GcdTest)
|
run_unittest(FractionTest, GcdTest)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test_main()
|
test_main()
|
|
@ -1182,6 +1182,8 @@ defdict_reduce(defdictobject *dd)
|
||||||
static PyMethodDef defdict_methods[] = {
|
static PyMethodDef defdict_methods[] = {
|
||||||
{"__missing__", (PyCFunction)defdict_missing, METH_O,
|
{"__missing__", (PyCFunction)defdict_missing, METH_O,
|
||||||
defdict_missing_doc},
|
defdict_missing_doc},
|
||||||
|
{"copy", (PyCFunction)defdict_copy, METH_NOARGS,
|
||||||
|
defdict_copy_doc},
|
||||||
{"__copy__", (PyCFunction)defdict_copy, METH_NOARGS,
|
{"__copy__", (PyCFunction)defdict_copy, METH_NOARGS,
|
||||||
defdict_copy_doc},
|
defdict_copy_doc},
|
||||||
{"__reduce__", (PyCFunction)defdict_reduce, METH_NOARGS,
|
{"__reduce__", (PyCFunction)defdict_reduce, METH_NOARGS,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue