667 lines
55 KiB
HTML
667 lines
55 KiB
HTML
|
|
|||
|
<!DOCTYPE html>
|
|||
|
<html lang="en">
|
|||
|
<head>
|
|||
|
<meta charset="utf-8">
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
<meta name="color-scheme" content="light dark">
|
|||
|
<title>PEP 3141 – A Type Hierarchy for Numbers | peps.python.org</title>
|
|||
|
<link rel="shortcut icon" href="../_static/py.png">
|
|||
|
<link rel="canonical" href="https://peps.python.org/pep-3141/">
|
|||
|
<link rel="stylesheet" href="../_static/style.css" type="text/css">
|
|||
|
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
|
|||
|
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
|
|||
|
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
|
|||
|
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
|
|||
|
<meta property="og:title" content='PEP 3141 – A Type Hierarchy for Numbers | peps.python.org'>
|
|||
|
<meta property="og:description" content="This proposal defines a hierarchy of Abstract Base Classes (ABCs) (PEP 3119) to represent number-like classes. It proposes a hierarchy of Number :> Complex :> Real :> Rational :> Integral where A :> B means “A is a supertype of B”. The hierarchy is insp...">
|
|||
|
<meta property="og:type" content="website">
|
|||
|
<meta property="og:url" content="https://peps.python.org/pep-3141/">
|
|||
|
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
|
|||
|
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
|
|||
|
<meta property="og:image:alt" content="Python PEPs">
|
|||
|
<meta property="og:image:width" content="200">
|
|||
|
<meta property="og:image:height" content="200">
|
|||
|
<meta name="description" content="This proposal defines a hierarchy of Abstract Base Classes (ABCs) (PEP 3119) to represent number-like classes. It proposes a hierarchy of Number :> Complex :> Real :> Rational :> Integral where A :> B means “A is a supertype of B”. The hierarchy is insp...">
|
|||
|
<meta name="theme-color" content="#3776ab">
|
|||
|
</head>
|
|||
|
<body>
|
|||
|
|
|||
|
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
|||
|
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
|
|||
|
<title>Following system colour scheme</title>
|
|||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
|||
|
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|||
|
<circle cx="12" cy="12" r="9"></circle>
|
|||
|
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
|
|||
|
</svg>
|
|||
|
</symbol>
|
|||
|
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
|
|||
|
<title>Selected dark colour scheme</title>
|
|||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
|||
|
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|||
|
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
|
|||
|
</svg>
|
|||
|
</symbol>
|
|||
|
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
|
|||
|
<title>Selected light colour scheme</title>
|
|||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
|||
|
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|||
|
<circle cx="12" cy="12" r="5"></circle>
|
|||
|
<line x1="12" y1="1" x2="12" y2="3"></line>
|
|||
|
<line x1="12" y1="21" x2="12" y2="23"></line>
|
|||
|
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
|||
|
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
|||
|
<line x1="1" y1="12" x2="3" y2="12"></line>
|
|||
|
<line x1="21" y1="12" x2="23" y2="12"></line>
|
|||
|
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
|||
|
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
|||
|
</svg>
|
|||
|
</symbol>
|
|||
|
</svg>
|
|||
|
<script>
|
|||
|
|
|||
|
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
|
|||
|
</script>
|
|||
|
<section id="pep-page-section">
|
|||
|
<header>
|
|||
|
<h1>Python Enhancement Proposals</h1>
|
|||
|
<ul class="breadcrumbs">
|
|||
|
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li>
|
|||
|
<li><a href="../pep-0000/">PEP Index</a> » </li>
|
|||
|
<li>PEP 3141</li>
|
|||
|
</ul>
|
|||
|
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
|
|||
|
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
|
|||
|
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
|
|||
|
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
|
|||
|
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
|
|||
|
</button>
|
|||
|
</header>
|
|||
|
<article>
|
|||
|
<section id="pep-content">
|
|||
|
<h1 class="page-title">PEP 3141 – A Type Hierarchy for Numbers</h1>
|
|||
|
<dl class="rfc2822 field-list simple">
|
|||
|
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
|||
|
<dd class="field-odd">Jeffrey Yasskin <jyasskin at google.com></dd>
|
|||
|
<dt class="field-even">Status<span class="colon">:</span></dt>
|
|||
|
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
|
|||
|
<dt class="field-odd">Type<span class="colon">:</span></dt>
|
|||
|
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
|
|||
|
<dt class="field-even">Created<span class="colon">:</span></dt>
|
|||
|
<dd class="field-even">23-Apr-2007</dd>
|
|||
|
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
|
|||
|
<dd class="field-odd">3.0</dd>
|
|||
|
<dt class="field-even">Post-History<span class="colon">:</span></dt>
|
|||
|
<dd class="field-even">25-Apr-2007, 16-May-2007, 02-Aug-2007</dd>
|
|||
|
</dl>
|
|||
|
<hr class="docutils" />
|
|||
|
<section id="contents">
|
|||
|
<details><summary>Table of Contents</summary><ul class="simple">
|
|||
|
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
|||
|
<li><a class="reference internal" href="#rationale">Rationale</a></li>
|
|||
|
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
|||
|
<li><a class="reference internal" href="#numeric-classes">Numeric Classes</a></li>
|
|||
|
<li><a class="reference internal" href="#changes-to-operations-and-magic-methods">Changes to operations and __magic__ methods</a></li>
|
|||
|
<li><a class="reference internal" href="#notes-for-type-implementors">Notes for type implementors</a><ul>
|
|||
|
<li><a class="reference internal" href="#adding-more-numeric-abcs">Adding More Numeric ABCs</a></li>
|
|||
|
<li><a class="reference internal" href="#implementing-the-arithmetic-operations">Implementing the arithmetic operations</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#rejected-alternatives">Rejected Alternatives</a></li>
|
|||
|
<li><a class="reference internal" href="#the-decimal-type">The Decimal Type</a></li>
|
|||
|
<li><a class="reference internal" href="#references">References</a></li>
|
|||
|
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
|
|||
|
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
|||
|
</ul>
|
|||
|
</details></section>
|
|||
|
<section id="abstract">
|
|||
|
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
|
|||
|
<p>This proposal defines a hierarchy of Abstract Base Classes (ABCs) (PEP
|
|||
|
3119) to represent number-like classes. It proposes a hierarchy of
|
|||
|
<code class="docutils literal notranslate"><span class="pre">Number</span> <span class="pre">:></span> <span class="pre">Complex</span> <span class="pre">:></span> <span class="pre">Real</span> <span class="pre">:></span> <span class="pre">Rational</span> <span class="pre">:></span> <span class="pre">Integral</span></code> where <code class="docutils literal notranslate"><span class="pre">A</span> <span class="pre">:></span> <span class="pre">B</span></code>
|
|||
|
means “A is a supertype of B”. The hierarchy is inspired by Scheme’s
|
|||
|
numeric tower <a class="footnote-reference brackets" href="#schemetower" id="id1">[3]</a>.</p>
|
|||
|
</section>
|
|||
|
<section id="rationale">
|
|||
|
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
|
|||
|
<p>Functions that take numbers as arguments should be able to determine
|
|||
|
the properties of those numbers, and if and when overloading based on
|
|||
|
types is added to the language, should be overloadable based on the
|
|||
|
types of the arguments. For example, slicing requires its arguments to
|
|||
|
be <code class="docutils literal notranslate"><span class="pre">Integrals</span></code>, and the functions in the <code class="docutils literal notranslate"><span class="pre">math</span></code> module require
|
|||
|
their arguments to be <code class="docutils literal notranslate"><span class="pre">Real</span></code>.</p>
|
|||
|
</section>
|
|||
|
<section id="specification">
|
|||
|
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
|
|||
|
<p>This PEP specifies a set of Abstract Base Classes, and suggests a
|
|||
|
general strategy for implementing some of the methods. It uses
|
|||
|
terminology from <a class="pep reference internal" href="../pep-3119/" title="PEP 3119 – Introducing Abstract Base Classes">PEP 3119</a>, but the hierarchy is intended to be
|
|||
|
meaningful for any systematic method of defining sets of classes.</p>
|
|||
|
<p>The type checks in the standard library should use these classes
|
|||
|
instead of the concrete built-ins.</p>
|
|||
|
<section id="numeric-classes">
|
|||
|
<h3><a class="toc-backref" href="#numeric-classes" role="doc-backlink">Numeric Classes</a></h3>
|
|||
|
<p>We begin with a Number class to make it easy for people to be fuzzy
|
|||
|
about what kind of number they expect. This class only helps with
|
|||
|
overloading; it doesn’t provide any operations.</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Number</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ABCMeta</span><span class="p">):</span> <span class="k">pass</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>Most implementations of complex numbers will be hashable, but if you
|
|||
|
need to rely on that, you’ll have to check it explicitly: mutable
|
|||
|
numbers are supported by this hierarchy.</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Complex</span><span class="p">(</span><span class="n">Number</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Complex defines the operations that work on the builtin complex type.</span>
|
|||
|
|
|||
|
<span class="sd"> In short, those are: conversion to complex, bool(), .real, .imag,</span>
|
|||
|
<span class="sd"> +, -, *, /, **, abs(), .conjugate(), ==, and !=.</span>
|
|||
|
|
|||
|
<span class="sd"> If it is given heterogeneous arguments, and doesn't have special</span>
|
|||
|
<span class="sd"> knowledge about them, it should fall back to the builtin complex</span>
|
|||
|
<span class="sd"> type as described below.</span>
|
|||
|
<span class="sd"> """</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__complex__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Return a builtin complex instance."""</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__bool__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""True if self != 0."""</span>
|
|||
|
<span class="k">return</span> <span class="bp">self</span> <span class="o">!=</span> <span class="mi">0</span>
|
|||
|
|
|||
|
<span class="nd">@abstractproperty</span>
|
|||
|
<span class="k">def</span> <span class="nf">real</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Retrieve the real component of this number.</span>
|
|||
|
|
|||
|
<span class="sd"> This should subclass Real.</span>
|
|||
|
<span class="sd"> """</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractproperty</span>
|
|||
|
<span class="k">def</span> <span class="nf">imag</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Retrieve the imaginary component of this number.</span>
|
|||
|
|
|||
|
<span class="sd"> This should subclass Real.</span>
|
|||
|
<span class="sd"> """</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__add__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__radd__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__neg__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__pos__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Coerces self to whatever class defines the method."""</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__sub__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="bp">self</span> <span class="o">+</span> <span class="o">-</span><span class="n">other</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__rsub__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="o">-</span><span class="bp">self</span> <span class="o">+</span> <span class="n">other</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__mul__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__rmul__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="nf">__div__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""a/b; should promote to float or complex when necessary."""</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="nf">__rdiv__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__pow__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">exponent</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""a**b; should promote to float or complex when necessary."""</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__rpow__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">base</span><span class="p">):</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__abs__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Returns the Real distance from 0."""</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="nf">conjugate</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""(x+y*i).conjugate() returns (x-y*i)."""</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="c1"># __ne__ is inherited from object and negates whatever __eq__ does.</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>The <code class="docutils literal notranslate"><span class="pre">Real</span></code> ABC indicates that the value is on the real line, and
|
|||
|
supports the operations of the <code class="docutils literal notranslate"><span class="pre">float</span></code> builtin. Real numbers are
|
|||
|
totally ordered except for NaNs (which this PEP basically ignores).</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Real</span><span class="p">(</span><span class="n">Complex</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""To Complex, Real adds the operations that work on real numbers.</span>
|
|||
|
|
|||
|
<span class="sd"> In short, those are: conversion to float, trunc(), math.floor(),</span>
|
|||
|
<span class="sd"> math.ceil(), round(), divmod(), //, %, <, <=, >, and >=.</span>
|
|||
|
|
|||
|
<span class="sd"> Real also provides defaults for some of the derived operations.</span>
|
|||
|
<span class="sd"> """</span>
|
|||
|
|
|||
|
<span class="c1"># XXX What to do about the __int__ implementation that's</span>
|
|||
|
<span class="c1"># currently present on float? Get rid of it?</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__float__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Any Real can be converted to a native float object."""</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="nf">__trunc__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Truncates self to an Integral.</span>
|
|||
|
|
|||
|
<span class="sd"> Returns an Integral i such that:</span>
|
|||
|
<span class="sd"> * i>=0 iff self>0;</span>
|
|||
|
<span class="sd"> * abs(i) <= abs(self);</span>
|
|||
|
<span class="sd"> * for any Integral j satisfying the first two conditions,</span>
|
|||
|
<span class="sd"> abs(i) >= abs(j) [i.e. i has "maximal" abs among those].</span>
|
|||
|
<span class="sd"> i.e. "truncate towards 0".</span>
|
|||
|
<span class="sd"> """</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="nf">__floor__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Finds the greatest Integral <= self."""</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="nf">__ceil__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Finds the least Integral >= self."""</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__round__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ndigits</span><span class="p">:</span><span class="n">Integral</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Rounds self to ndigits decimal places, defaulting to 0.</span>
|
|||
|
|
|||
|
<span class="sd"> If ndigits is omitted or None, returns an Integral,</span>
|
|||
|
<span class="sd"> otherwise returns a Real, preferably of the same type as</span>
|
|||
|
<span class="sd"> self. Types may choose which direction to round half. For</span>
|
|||
|
<span class="sd"> example, float rounds half toward even.</span>
|
|||
|
|
|||
|
<span class="sd"> """</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__divmod__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""The pair (self // other, self % other).</span>
|
|||
|
|
|||
|
<span class="sd"> Sometimes this can be computed faster than the pair of</span>
|
|||
|
<span class="sd"> operations.</span>
|
|||
|
<span class="sd"> """</span>
|
|||
|
<span class="k">return</span> <span class="p">(</span><span class="bp">self</span> <span class="o">//</span> <span class="n">other</span><span class="p">,</span> <span class="bp">self</span> <span class="o">%</span> <span class="n">other</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__rdivmod__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""The pair (self // other, self % other).</span>
|
|||
|
|
|||
|
<span class="sd"> Sometimes this can be computed faster than the pair of</span>
|
|||
|
<span class="sd"> operations.</span>
|
|||
|
<span class="sd"> """</span>
|
|||
|
<span class="k">return</span> <span class="p">(</span><span class="n">other</span> <span class="o">//</span> <span class="bp">self</span><span class="p">,</span> <span class="n">other</span> <span class="o">%</span> <span class="bp">self</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__floordiv__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""The floor() of self/other. Integral."""</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__rfloordiv__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""The floor() of other/self."""</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__mod__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""self % other</span>
|
|||
|
|
|||
|
<span class="sd"> See</span>
|
|||
|
<span class="sd"> https://mail.python.org/pipermail/python-3000/2006-May/001735.html</span>
|
|||
|
<span class="sd"> and consider using "self/other - trunc(self/other)"</span>
|
|||
|
<span class="sd"> instead if you're worried about round-off errors.</span>
|
|||
|
<span class="sd"> """</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__rmod__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""other % self"""</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__lt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""< on Reals defines a total ordering, except perhaps for NaN."""</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__le__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="c1"># __gt__ and __ge__ are automatically done by reversing the arguments.</span>
|
|||
|
<span class="c1"># (But __le__ is not computed as the opposite of __gt__!)</span>
|
|||
|
|
|||
|
<span class="c1"># Concrete implementations of Complex abstract methods.</span>
|
|||
|
<span class="c1"># Subclasses may override these, but don't have to.</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__complex__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">complex</span><span class="p">(</span><span class="nb">float</span><span class="p">(</span><span class="bp">self</span><span class="p">))</span>
|
|||
|
|
|||
|
<span class="nd">@property</span>
|
|||
|
<span class="k">def</span> <span class="nf">real</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="o">+</span><span class="bp">self</span>
|
|||
|
|
|||
|
<span class="nd">@property</span>
|
|||
|
<span class="k">def</span> <span class="nf">imag</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="mi">0</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="nf">conjugate</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Conjugate is a no-op for Reals."""</span>
|
|||
|
<span class="k">return</span> <span class="o">+</span><span class="bp">self</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>We should clean up Demo/classes/Rat.py and promote it into
|
|||
|
rational.py in the standard library. Then it will implement the
|
|||
|
Rational ABC.</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Rational</span><span class="p">(</span><span class="n">Real</span><span class="p">,</span> <span class="n">Exact</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">""".numerator and .denominator should be in lowest terms."""</span>
|
|||
|
|
|||
|
<span class="nd">@abstractproperty</span>
|
|||
|
<span class="k">def</span> <span class="nf">numerator</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="nd">@abstractproperty</span>
|
|||
|
<span class="k">def</span> <span class="nf">denominator</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="c1"># Concrete implementation of Real's conversion to float.</span>
|
|||
|
<span class="c1"># (This invokes Integer.__div__().)</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__float__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">numerator</span> <span class="o">/</span> <span class="bp">self</span><span class="o">.</span><span class="n">denominator</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>And finally integers:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Integral</span><span class="p">(</span><span class="n">Rational</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Integral adds a conversion to int and the bit-string operations."""</span>
|
|||
|
|
|||
|
<span class="nd">@abstractmethod</span>
|
|||
|
<span class="k">def</span> <span class="fm">__int__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="k">raise</span> <span class="ne">NotImplementedError</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__index__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""__index__() exists because float has __int__()."""</span>
|
|||
|
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__lshift__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o"><<</span> <span class="nb">int</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__rlshift__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="o"><<</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__rshift__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">>></span> <span class="nb">int</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__rrshift__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="o">>></span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__and__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">&</span> <span class="nb">int</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__rand__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="o">&</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__xor__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">^</span> <span class="nb">int</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__rxor__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="o">^</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__or__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">|</span> <span class="nb">int</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__ror__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="o">|</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__invert__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="o">~</span><span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="c1"># Concrete implementations of Rational and Real abstract methods.</span>
|
|||
|
<span class="k">def</span> <span class="fm">__float__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""float(self) == float(int(self))"""</span>
|
|||
|
<span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">))</span>
|
|||
|
|
|||
|
<span class="nd">@property</span>
|
|||
|
<span class="k">def</span> <span class="nf">numerator</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Integers are their own numerators."""</span>
|
|||
|
<span class="k">return</span> <span class="o">+</span><span class="bp">self</span>
|
|||
|
|
|||
|
<span class="nd">@property</span>
|
|||
|
<span class="k">def</span> <span class="nf">denominator</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="w"> </span><span class="sd">"""Integers have a denominator of 1."""</span>
|
|||
|
<span class="k">return</span> <span class="mi">1</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
<section id="changes-to-operations-and-magic-methods">
|
|||
|
<h3><a class="toc-backref" href="#changes-to-operations-and-magic-methods" role="doc-backlink">Changes to operations and __magic__ methods</a></h3>
|
|||
|
<p>To support more precise narrowing from float to int (and more
|
|||
|
generally, from Real to Integral), we propose the following new
|
|||
|
__magic__ methods, to be called from the corresponding library
|
|||
|
functions. All of these return Integrals rather than Reals.</p>
|
|||
|
<ol class="arabic simple">
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">__trunc__(self)</span></code>, called from a new builtin <code class="docutils literal notranslate"><span class="pre">trunc(x)</span></code>, which
|
|||
|
returns the Integral closest to <code class="docutils literal notranslate"><span class="pre">x</span></code> between 0 and <code class="docutils literal notranslate"><span class="pre">x</span></code>.</li>
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">__floor__(self)</span></code>, called from <code class="docutils literal notranslate"><span class="pre">math.floor(x)</span></code>, which returns
|
|||
|
the greatest Integral <code class="docutils literal notranslate"><span class="pre"><=</span> <span class="pre">x</span></code>.</li>
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">__ceil__(self)</span></code>, called from <code class="docutils literal notranslate"><span class="pre">math.ceil(x)</span></code>, which returns the
|
|||
|
least Integral <code class="docutils literal notranslate"><span class="pre">>=</span> <span class="pre">x</span></code>.</li>
|
|||
|
<li><code class="docutils literal notranslate"><span class="pre">__round__(self)</span></code>, called from <code class="docutils literal notranslate"><span class="pre">round(x)</span></code>, which returns the
|
|||
|
Integral closest to <code class="docutils literal notranslate"><span class="pre">x</span></code>, rounding half as the type chooses.
|
|||
|
<code class="docutils literal notranslate"><span class="pre">float</span></code> will change in 3.0 to round half toward even. There is
|
|||
|
also a 2-argument version, <code class="docutils literal notranslate"><span class="pre">__round__(self,</span> <span class="pre">ndigits)</span></code>, called
|
|||
|
from <code class="docutils literal notranslate"><span class="pre">round(x,</span> <span class="pre">ndigits)</span></code>, which should return a Real.</li>
|
|||
|
</ol>
|
|||
|
<p>In 2.6, <code class="docutils literal notranslate"><span class="pre">math.floor</span></code>, <code class="docutils literal notranslate"><span class="pre">math.ceil</span></code>, and <code class="docutils literal notranslate"><span class="pre">round</span></code> will continue to
|
|||
|
return floats.</p>
|
|||
|
<p>The <code class="docutils literal notranslate"><span class="pre">int()</span></code> conversion implemented by <code class="docutils literal notranslate"><span class="pre">float</span></code> is equivalent to
|
|||
|
<code class="docutils literal notranslate"><span class="pre">trunc()</span></code>. In general, the <code class="docutils literal notranslate"><span class="pre">int()</span></code> conversion should try
|
|||
|
<code class="docutils literal notranslate"><span class="pre">__int__()</span></code> first and if it is not found, try <code class="docutils literal notranslate"><span class="pre">__trunc__()</span></code>.</p>
|
|||
|
<p><code class="docutils literal notranslate"><span class="pre">complex.__{divmod,mod,floordiv,int,float}__</span></code> also go away. It would
|
|||
|
be nice to provide a nice error message to help confused porters, but
|
|||
|
not appearing in <code class="docutils literal notranslate"><span class="pre">help(complex)</span></code> is more important.</p>
|
|||
|
</section>
|
|||
|
<section id="notes-for-type-implementors">
|
|||
|
<h3><a class="toc-backref" href="#notes-for-type-implementors" role="doc-backlink">Notes for type implementors</a></h3>
|
|||
|
<p>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, a complex type
|
|||
|
could reasonably implement hash() as follows:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="fm">__hash__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">hash</span><span class="p">(</span><span class="nb">complex</span><span class="p">(</span><span class="bp">self</span><span class="p">))</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>but should be careful of any values that fall outside of the built in
|
|||
|
complex’s range or precision.</p>
|
|||
|
<section id="adding-more-numeric-abcs">
|
|||
|
<h4><a class="toc-backref" href="#adding-more-numeric-abcs" role="doc-backlink">Adding More Numeric ABCs</a></h4>
|
|||
|
<p>There are, of course, more possible ABCs for numbers, and this would
|
|||
|
be a poor hierarchy if it precluded the possibility of adding
|
|||
|
those. You can add <code class="docutils literal notranslate"><span class="pre">MyFoo</span></code> between <code class="docutils literal notranslate"><span class="pre">Complex</span></code> and <code class="docutils literal notranslate"><span class="pre">Real</span></code> with:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyFoo</span><span class="p">(</span><span class="n">Complex</span><span class="p">):</span> <span class="o">...</span>
|
|||
|
<span class="n">MyFoo</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">Real</span><span class="p">)</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
<section id="implementing-the-arithmetic-operations">
|
|||
|
<h4><a class="toc-backref" href="#implementing-the-arithmetic-operations" role="doc-backlink">Implementing the arithmetic operations</a></h4>
|
|||
|
<p>We want to implement the arithmetic operations so 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. For subtypes of Integral, this means that
|
|||
|
__add__ and __radd__ should be defined as:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyIntegral</span><span class="p">(</span><span class="n">Integral</span><span class="p">):</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__add__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">MyIntegral</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="n">do_my_adding_stuff</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">)</span>
|
|||
|
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">OtherTypeIKnowAbout</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="n">do_my_other_adding_stuff</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">)</span>
|
|||
|
<span class="k">else</span><span class="p">:</span>
|
|||
|
<span class="k">return</span> <span class="bp">NotImplemented</span>
|
|||
|
|
|||
|
<span class="k">def</span> <span class="fm">__radd__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
|||
|
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">MyIntegral</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="n">do_my_adding_stuff</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span>
|
|||
|
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">OtherTypeIKnowAbout</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="n">do_my_other_adding_stuff</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span>
|
|||
|
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">Integral</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="o">+</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
|||
|
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">Real</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="o">+</span> <span class="nb">float</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
|||
|
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">Complex</span><span class="p">):</span>
|
|||
|
<span class="k">return</span> <span class="nb">complex</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="o">+</span> <span class="nb">complex</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
|||
|
<span class="k">else</span><span class="p">:</span>
|
|||
|
<span class="k">return</span> <span class="bp">NotImplemented</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>There are 5 different cases for a mixed-type operation on subclasses
|
|||
|
of Complex. I’ll refer to all of the above code that doesn’t refer to
|
|||
|
MyIntegral and OtherTypeIKnowAbout as “boilerplate”. <code class="docutils literal notranslate"><span class="pre">a</span></code> will be an
|
|||
|
instance of <code class="docutils literal notranslate"><span class="pre">A</span></code>, which is a subtype of <code class="docutils literal notranslate"><span class="pre">Complex</span></code> (<code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">:</span> <span class="pre">A</span> <span class="pre"><:</span>
|
|||
|
<span class="pre">Complex</span></code>), and <code class="docutils literal notranslate"><span class="pre">b</span> <span class="pre">:</span> <span class="pre">B</span> <span class="pre"><:</span> <span class="pre">Complex</span></code>. I’ll consider <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">+</span> <span class="pre">b</span></code>:</p>
|
|||
|
<ol class="arabic simple">
|
|||
|
<li>If A defines an __add__ which accepts b, all is well.</li>
|
|||
|
<li>If A 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__. (Or A may not implement __add__ at
|
|||
|
all.)</li>
|
|||
|
<li>Then B’s __radd__ gets a chance. If it accepts a, all is well.</li>
|
|||
|
<li>If it falls back to the boilerplate, there are no more possible
|
|||
|
methods to try, so this is where the default implementation
|
|||
|
should live.</li>
|
|||
|
<li>If B <: A, Python tries B.__radd__ before A.__add__. This is
|
|||
|
ok, because it was implemented with knowledge of A, so it can
|
|||
|
handle those instances before delegating to Complex.</li>
|
|||
|
</ol>
|
|||
|
<p>If <code class="docutils literal notranslate"><span class="pre">A<:Complex</span></code> and <code class="docutils literal notranslate"><span class="pre">B<:Real</span></code> without sharing any other knowledge,
|
|||
|
then the appropriate shared operation is the one involving the built
|
|||
|
in complex, and both __radd__s land there, so <code class="docutils literal notranslate"><span class="pre">a+b</span> <span class="pre">==</span> <span class="pre">b+a</span></code>.</p>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<section id="rejected-alternatives">
|
|||
|
<h2><a class="toc-backref" href="#rejected-alternatives" role="doc-backlink">Rejected Alternatives</a></h2>
|
|||
|
<p>The initial version of this PEP defined an algebraic hierarchy
|
|||
|
inspired by a Haskell Numeric Prelude <a class="footnote-reference brackets" href="#numericprelude" id="id2">[2]</a> including
|
|||
|
MonoidUnderPlus, AdditiveGroup, Ring, and Field, and mentioned several
|
|||
|
other possible algebraic types before getting to the numbers. We had
|
|||
|
expected this to be useful to people using vectors and matrices, but
|
|||
|
the NumPy community really wasn’t interested, and we ran into the
|
|||
|
issue that even if <code class="docutils literal notranslate"><span class="pre">x</span></code> is an instance of <code class="docutils literal notranslate"><span class="pre">X</span> <span class="pre"><:</span> <span class="pre">MonoidUnderPlus</span></code>
|
|||
|
and <code class="docutils literal notranslate"><span class="pre">y</span></code> is an instance of <code class="docutils literal notranslate"><span class="pre">Y</span> <span class="pre"><:</span> <span class="pre">MonoidUnderPlus</span></code>, <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">+</span> <span class="pre">y</span></code> may
|
|||
|
still not make sense.</p>
|
|||
|
<p>Then we gave the numbers a much more branching structure to include
|
|||
|
things like the Gaussian Integers and Z/nZ, which could be Complex but
|
|||
|
wouldn’t necessarily support things like division. The community
|
|||
|
decided that this was too much complication for Python, so I’ve now
|
|||
|
scaled back the proposal to resemble the Scheme numeric tower much
|
|||
|
more closely.</p>
|
|||
|
</section>
|
|||
|
<section id="the-decimal-type">
|
|||
|
<h2><a class="toc-backref" href="#the-decimal-type" role="doc-backlink">The Decimal Type</a></h2>
|
|||
|
<p>After consultation with its authors it has been decided that the
|
|||
|
<code class="docutils literal notranslate"><span class="pre">Decimal</span></code> type should not at this time be made part of the numeric
|
|||
|
tower.</p>
|
|||
|
</section>
|
|||
|
<section id="references">
|
|||
|
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
|
|||
|
<aside class="footnote-list brackets">
|
|||
|
<aside class="footnote brackets" id="classtree" role="doc-footnote">
|
|||
|
<dt class="label" id="classtree">[1]</dt>
|
|||
|
<dd>Possible Python 3K Class Tree?, wiki page by Bill Janssen
|
|||
|
(<a class="reference external" href="http://wiki.python.org/moin/AbstractBaseClasses">http://wiki.python.org/moin/AbstractBaseClasses</a>)</aside>
|
|||
|
<aside class="footnote brackets" id="numericprelude" role="doc-footnote">
|
|||
|
<dt class="label" id="numericprelude">[<a href="#id2">2</a>]</dt>
|
|||
|
<dd>NumericPrelude: An experimental alternative hierarchy
|
|||
|
of numeric type classes
|
|||
|
(<a class="reference external" href="https://archives.haskell.org/code.haskell.org/numeric-prelude/docs/html/index.html">https://archives.haskell.org/code.haskell.org/numeric-prelude/docs/html/index.html</a>)</aside>
|
|||
|
<aside class="footnote brackets" id="schemetower" role="doc-footnote">
|
|||
|
<dt class="label" id="schemetower">[<a href="#id1">3</a>]</dt>
|
|||
|
<dd>The Scheme numerical tower
|
|||
|
(<a class="reference external" href="https://groups.csail.mit.edu/mac/ftpdir/scheme-reports/r5rs-html/r5rs_8.html#SEC50">https://groups.csail.mit.edu/mac/ftpdir/scheme-reports/r5rs-html/r5rs_8.html#SEC50</a>)</aside>
|
|||
|
</aside>
|
|||
|
</section>
|
|||
|
<section id="acknowledgements">
|
|||
|
<h2><a class="toc-backref" href="#acknowledgements" role="doc-backlink">Acknowledgements</a></h2>
|
|||
|
<p>Thanks to Neal Norwitz for encouraging me to write this PEP in the
|
|||
|
first place, to Travis Oliphant for pointing out that the numpy people
|
|||
|
didn’t really care about the algebraic concepts, to Alan Isaac for
|
|||
|
reminding me that Scheme had already done this, and to Guido van
|
|||
|
Rossum and lots of other people on the mailing list for refining the
|
|||
|
concept.</p>
|
|||
|
</section>
|
|||
|
<section id="copyright">
|
|||
|
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
|
|||
|
<p>This document has been placed in the public domain.</p>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<hr class="docutils" />
|
|||
|
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-3141.rst">https://github.com/python/peps/blob/main/peps/pep-3141.rst</a></p>
|
|||
|
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-3141.rst">2023-09-09 17:39:29 GMT</a></p>
|
|||
|
|
|||
|
</article>
|
|||
|
<nav id="pep-sidebar">
|
|||
|
<h2>Contents</h2>
|
|||
|
<ul>
|
|||
|
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
|||
|
<li><a class="reference internal" href="#rationale">Rationale</a></li>
|
|||
|
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
|||
|
<li><a class="reference internal" href="#numeric-classes">Numeric Classes</a></li>
|
|||
|
<li><a class="reference internal" href="#changes-to-operations-and-magic-methods">Changes to operations and __magic__ methods</a></li>
|
|||
|
<li><a class="reference internal" href="#notes-for-type-implementors">Notes for type implementors</a><ul>
|
|||
|
<li><a class="reference internal" href="#adding-more-numeric-abcs">Adding More Numeric ABCs</a></li>
|
|||
|
<li><a class="reference internal" href="#implementing-the-arithmetic-operations">Implementing the arithmetic operations</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#rejected-alternatives">Rejected Alternatives</a></li>
|
|||
|
<li><a class="reference internal" href="#the-decimal-type">The Decimal Type</a></li>
|
|||
|
<li><a class="reference internal" href="#references">References</a></li>
|
|||
|
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
|
|||
|
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<br>
|
|||
|
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-3141.rst">Page Source (GitHub)</a>
|
|||
|
</nav>
|
|||
|
</section>
|
|||
|
<script src="../_static/colour_scheme.js"></script>
|
|||
|
<script src="../_static/wrap_tables.js"></script>
|
|||
|
<script src="../_static/sticky_banner.js"></script>
|
|||
|
</body>
|
|||
|
</html>
|