CINXE.COM
PEP 3124 – Overloading, Generic Functions, Interfaces, and Adaptation | peps.python.org
<!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 3124 – Overloading, Generic Functions, Interfaces, and Adaptation | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-3124/"> <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 3124 – Overloading, Generic Functions, Interfaces, and Adaptation | peps.python.org'> <meta property="og:description" content="This PEP proposes a new standard library module, overloading, to provide generic programming features including dynamic overloading (aka generic functions), interfaces, adaptation, method combining (ala CLOS and AspectJ), and simple forms of aspect-orie..."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-3124/"> <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 PEP proposes a new standard library module, overloading, to provide generic programming features including dynamic overloading (aka generic functions), interfaces, adaptation, method combining (ala CLOS and AspectJ), and simple forms of aspect-orie..."> <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 3124</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 3124 – Overloading, Generic Functions, Interfaces, and Adaptation</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Phillip J. Eby <pje at telecommunity.com></dd> <dt class="field-even">Discussions-To<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://mail.python.org/pipermail/python-3000/">Python-3000 list</a></dd> <dt class="field-odd">Status<span class="colon">:</span></dt> <dd class="field-odd"><abbr title="Inactive draft that may be taken up again at a later time">Deferred</abbr></dd> <dt class="field-even">Type<span class="colon">:</span></dt> <dd class="field-even"><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-odd">Requires<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="../pep-3107/">3107</a>, <a class="reference external" href="../pep-3115/">3115</a>, <a class="reference external" href="../pep-3119/">3119</a></dd> <dt class="field-even">Created<span class="colon">:</span></dt> <dd class="field-even">28-Apr-2007</dd> <dt class="field-odd">Post-History<span class="colon">:</span></dt> <dd class="field-odd">30-Apr-2007</dd> <dt class="field-even">Replaces<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="../pep-0245/">245</a>, <a class="reference external" href="../pep-0246/">246</a></dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#deferred">Deferred</a></li> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#rationale-and-goals">Rationale and Goals</a></li> <li><a class="reference internal" href="#user-api">User API</a><ul> <li><a class="reference internal" href="#overloading-generic-functions">Overloading/Generic Functions</a><ul> <li><a class="reference internal" href="#overload-vs-when"><code class="docutils literal notranslate"><span class="pre">@overload</span></code> vs. <code class="docutils literal notranslate"><span class="pre">@when</span></code></a></li> </ul> </li> <li><a class="reference internal" href="#method-combination-and-overriding">Method Combination and Overriding</a><ul> <li><a class="reference internal" href="#proceeding-to-the-next-method">Proceeding to the “Next” Method</a></li> <li><a class="reference internal" href="#before-and-after-methods">“Before” and “After” Methods</a></li> <li><a class="reference internal" href="#around-methods">“Around” Methods</a></li> <li><a class="reference internal" href="#custom-combinations">Custom Combinations</a></li> </ul> </li> <li><a class="reference internal" href="#overloading-inside-classes">Overloading Inside Classes</a></li> <li><a class="reference internal" href="#interfaces-and-adaptation">Interfaces and Adaptation</a><ul> <li><a class="reference internal" href="#abstract-and-concrete-methods">Abstract and Concrete Methods</a></li> <li><a class="reference internal" href="#subclassing-and-re-assembly">Subclassing and Re-assembly</a></li> <li><a class="reference internal" href="#implementing-an-interface-in-a-class">Implementing an Interface in a Class</a></li> <li><a class="reference internal" href="#interfaces-as-type-specifiers">Interfaces as Type Specifiers</a></li> <li><a class="reference internal" href="#non-method-attributes-in-interfaces">Non-Method Attributes in Interfaces</a></li> </ul> </li> <li><a class="reference internal" href="#aspects">Aspects</a></li> </ul> </li> <li><a class="reference internal" href="#extension-api">Extension API</a></li> <li><a class="reference internal" href="#overloading-usage-patterns">Overloading Usage Patterns</a></li> <li><a class="reference internal" href="#implementation-notes">Implementation Notes</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <section id="deferred"> <h2><a class="toc-backref" href="#deferred" role="doc-backlink">Deferred</a></h2> <p>See <a class="reference external" href="https://mail.python.org/pipermail/python-3000/2007-July/008784.html">https://mail.python.org/pipermail/python-3000/2007-July/008784.html</a>.</p> </section> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>This PEP proposes a new standard library module, <code class="docutils literal notranslate"><span class="pre">overloading</span></code>, to provide generic programming features including dynamic overloading (aka generic functions), interfaces, adaptation, method combining (ala CLOS and AspectJ), and simple forms of aspect-oriented programming (AOP).</p> <p>The proposed API is also open to extension; that is, it will be possible for library developers to implement their own specialized interface types, generic function dispatchers, method combination algorithms, etc., and those extensions will be treated as first-class citizens by the proposed API.</p> <p>The API will be implemented in pure Python with no C, but may have some dependency on CPython-specific features such as <code class="docutils literal notranslate"><span class="pre">sys._getframe</span></code> and the <code class="docutils literal notranslate"><span class="pre">func_code</span></code> attribute of functions. It is expected that e.g. Jython and IronPython will have other ways of implementing similar functionality (perhaps using Java or C#).</p> </section> <section id="rationale-and-goals"> <h2><a class="toc-backref" href="#rationale-and-goals" role="doc-backlink">Rationale and Goals</a></h2> <p>Python has always provided a variety of built-in and standard-library generic functions, such as <code class="docutils literal notranslate"><span class="pre">len()</span></code>, <code class="docutils literal notranslate"><span class="pre">iter()</span></code>, <code class="docutils literal notranslate"><span class="pre">pprint.pprint()</span></code>, and most of the functions in the <code class="docutils literal notranslate"><span class="pre">operator</span></code> module. However, it currently:</p> <ol class="arabic simple"> <li>does not have a simple or straightforward way for developers to create new generic functions,</li> <li>does not have a standard way for methods to be added to existing generic functions (i.e., some are added using registration functions, others require defining <code class="docutils literal notranslate"><span class="pre">__special__</span></code> methods, possibly by monkeypatching), and</li> <li>does not allow dispatching on multiple argument types (except in a limited form for arithmetic operators, where “right-hand” (<code class="docutils literal notranslate"><span class="pre">__r*__</span></code>) methods can be used to do two-argument dispatch.</li> </ol> <p>In addition, it is currently a common anti-pattern for Python code to inspect the types of received arguments, in order to decide what to do with the objects. For example, code may wish to accept either an object of some type, or a sequence of objects of that type.</p> <p>Currently, the “obvious way” to do this is by type inspection, but this is brittle and closed to extension. A developer using an already-written library may be unable to change how their objects are treated by such code, especially if the objects they are using were created by a third party.</p> <p>Therefore, this PEP proposes a standard library module to address these, and related issues, using decorators and argument annotations (<a class="pep reference internal" href="../pep-3107/" title="PEP 3107 – Function Annotations">PEP 3107</a>). The primary features to be provided are:</p> <ul class="simple"> <li>a dynamic overloading facility, similar to the static overloading found in languages such as Java and C++, but including optional method combination features as found in CLOS and AspectJ.</li> <li>a simple “interfaces and adaptation” library inspired by Haskell’s typeclasses (but more dynamic, and without any static type-checking), with an extension API to allow registering user-defined interface types such as those found in PyProtocols and Zope.</li> <li>a simple “aspect” implementation to make it easy to create stateful adapters and to do other stateful AOP.</li> </ul> <p>These features are to be provided in such a way that extended implementations can be created and used. For example, it should be possible for libraries to define new dispatching criteria for generic functions, and new kinds of interfaces, and use them in place of the predefined features. For example, it should be possible to use a <code class="docutils literal notranslate"><span class="pre">zope.interface</span></code> interface object to specify the desired type of a function argument, as long as the <code class="docutils literal notranslate"><span class="pre">zope.interface</span></code> package registered itself correctly (or a third party did the registration).</p> <p>In this way, the proposed API simply offers a uniform way of accessing the functionality within its scope, rather than prescribing a single implementation to be used for all libraries, frameworks, and applications.</p> </section> <section id="user-api"> <h2><a class="toc-backref" href="#user-api" role="doc-backlink">User API</a></h2> <p>The overloading API will be implemented as a single module, named <code class="docutils literal notranslate"><span class="pre">overloading</span></code>, providing the following features:</p> <section id="overloading-generic-functions"> <h3><a class="toc-backref" href="#overloading-generic-functions" role="doc-backlink">Overloading/Generic Functions</a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">@overload</span></code> decorator allows you to define alternate implementations of a function, specialized by argument type(s). A function with the same name must already exist in the local namespace. The existing function is modified in-place by the decorator to add the new implementation, and the modified function is returned by the decorator. Thus, the following code:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">overloading</span><span class="w"> </span><span class="kn">import</span> <span class="n">overload</span> <span class="kn">from</span><span class="w"> </span><span class="nn">collections</span><span class="w"> </span><span class="kn">import</span> <span class="n">Iterable</span> <span class="k">def</span><span class="w"> </span><span class="nf">flatten</span><span class="p">(</span><span class="n">ob</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Flatten an object to its component iterables"""</span> <span class="k">yield</span> <span class="n">ob</span> <span class="nd">@overload</span> <span class="k">def</span><span class="w"> </span><span class="nf">flatten</span><span class="p">(</span><span class="n">ob</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">):</span> <span class="k">for</span> <span class="n">o</span> <span class="ow">in</span> <span class="n">ob</span><span class="p">:</span> <span class="k">for</span> <span class="n">ob</span> <span class="ow">in</span> <span class="n">flatten</span><span class="p">(</span><span class="n">o</span><span class="p">):</span> <span class="k">yield</span> <span class="n">ob</span> <span class="nd">@overload</span> <span class="k">def</span><span class="w"> </span><span class="nf">flatten</span><span class="p">(</span><span class="n">ob</span><span class="p">:</span> <span class="n">basestring</span><span class="p">):</span> <span class="k">yield</span> <span class="n">ob</span> </pre></div> </div> <p>creates a single <code class="docutils literal notranslate"><span class="pre">flatten()</span></code> function whose implementation roughly equates to:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">flatten</span><span class="p">(</span><span class="n">ob</span><span class="p">):</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ob</span><span class="p">,</span> <span class="n">basestring</span><span class="p">)</span> <span class="ow">or</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ob</span><span class="p">,</span> <span class="n">Iterable</span><span class="p">):</span> <span class="k">yield</span> <span class="n">ob</span> <span class="k">else</span><span class="p">:</span> <span class="k">for</span> <span class="n">o</span> <span class="ow">in</span> <span class="n">ob</span><span class="p">:</span> <span class="k">for</span> <span class="n">ob</span> <span class="ow">in</span> <span class="n">flatten</span><span class="p">(</span><span class="n">o</span><span class="p">):</span> <span class="k">yield</span> <span class="n">ob</span> </pre></div> </div> <p><strong>except</strong> that the <code class="docutils literal notranslate"><span class="pre">flatten()</span></code> function defined by overloading remains open to extension by adding more overloads, while the hardcoded version cannot be extended.</p> <p>For example, if someone wants to use <code class="docutils literal notranslate"><span class="pre">flatten()</span></code> with a string-like type that doesn’t subclass <code class="docutils literal notranslate"><span class="pre">basestring</span></code>, they would be out of luck with the second implementation. With the overloaded implementation, however, they can either write this:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@overload</span> <span class="k">def</span><span class="w"> </span><span class="nf">flatten</span><span class="p">(</span><span class="n">ob</span><span class="p">:</span> <span class="n">MyString</span><span class="p">):</span> <span class="k">yield</span> <span class="n">ob</span> </pre></div> </div> <p>or this (to avoid copying the implementation):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">overloading</span><span class="w"> </span><span class="kn">import</span> <span class="n">RuleSet</span> <span class="n">RuleSet</span><span class="p">(</span><span class="n">flatten</span><span class="p">)</span><span class="o">.</span><span class="n">copy_rules</span><span class="p">((</span><span class="n">basestring</span><span class="p">,),</span> <span class="p">(</span><span class="n">MyString</span><span class="p">,))</span> </pre></div> </div> <p>(Note also that, although <a class="pep reference internal" href="../pep-3119/" title="PEP 3119 – Introducing Abstract Base Classes">PEP 3119</a> proposes that it should be possible for abstract base classes like <code class="docutils literal notranslate"><span class="pre">Iterable</span></code> to allow classes like <code class="docutils literal notranslate"><span class="pre">MyString</span></code> to claim subclass-hood, such a claim is <em>global</em>, throughout the application. In contrast, adding a specific overload or copying a rule is specific to an individual function, and therefore less likely to have undesired side effects.)</p> <section id="overload-vs-when"> <h4><a class="toc-backref" href="#overload-vs-when" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">@overload</span></code> vs. <code class="docutils literal notranslate"><span class="pre">@when</span></code></a></h4> <p>The <code class="docutils literal notranslate"><span class="pre">@overload</span></code> decorator is a common-case shorthand for the more general <code class="docutils literal notranslate"><span class="pre">@when</span></code> decorator. It allows you to leave out the name of the function you are overloading, at the expense of requiring the target function to be in the local namespace. It also doesn’t support adding additional criteria besides the ones specified via argument annotations. The following function definitions have identical effects, except for name binding side-effects (which will be described below):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">overloading</span><span class="w"> </span><span class="kn">import</span> <span class="n">when</span> <span class="nd">@overload</span> <span class="k">def</span><span class="w"> </span><span class="nf">flatten</span><span class="p">(</span><span class="n">ob</span><span class="p">:</span> <span class="n">basestring</span><span class="p">):</span> <span class="k">yield</span> <span class="n">ob</span> <span class="nd">@when</span><span class="p">(</span><span class="n">flatten</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">flatten</span><span class="p">(</span><span class="n">ob</span><span class="p">:</span> <span class="n">basestring</span><span class="p">):</span> <span class="k">yield</span> <span class="n">ob</span> <span class="nd">@when</span><span class="p">(</span><span class="n">flatten</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">flatten_basestring</span><span class="p">(</span><span class="n">ob</span><span class="p">:</span> <span class="n">basestring</span><span class="p">):</span> <span class="k">yield</span> <span class="n">ob</span> <span class="nd">@when</span><span class="p">(</span><span class="n">flatten</span><span class="p">,</span> <span class="p">(</span><span class="n">basestring</span><span class="p">,))</span> <span class="k">def</span><span class="w"> </span><span class="nf">flatten_basestring</span><span class="p">(</span><span class="n">ob</span><span class="p">):</span> <span class="k">yield</span> <span class="n">ob</span> </pre></div> </div> <p>The first definition above will bind <code class="docutils literal notranslate"><span class="pre">flatten</span></code> to whatever it was previously bound to. The second will do the same, if it was already bound to the <code class="docutils literal notranslate"><span class="pre">when</span></code> decorator’s first argument. If <code class="docutils literal notranslate"><span class="pre">flatten</span></code> is unbound or bound to something else, it will be rebound to the function definition as given. The last two definitions above will always bind <code class="docutils literal notranslate"><span class="pre">flatten_basestring</span></code> to the function definition as given.</p> <p>Using this approach allows you to both give a method a descriptive name (often useful in tracebacks!) and to reuse the method later.</p> <p>Except as otherwise specified, all <code class="docutils literal notranslate"><span class="pre">overloading</span></code> decorators have the same signature and binding rules as <code class="docutils literal notranslate"><span class="pre">@when</span></code>. They accept a function and an optional “predicate” object.</p> <p>The default predicate implementation is a tuple of types with positional matching to the overloaded function’s arguments. However, an arbitrary number of other kinds of predicates can be created and registered using the <a class="reference internal" href="#extension-api">Extension API</a>, and will then be usable with <code class="docutils literal notranslate"><span class="pre">@when</span></code> and other decorators created by this module (like <code class="docutils literal notranslate"><span class="pre">@before</span></code>, <code class="docutils literal notranslate"><span class="pre">@after</span></code>, and <code class="docutils literal notranslate"><span class="pre">@around</span></code>).</p> </section> </section> <section id="method-combination-and-overriding"> <h3><a class="toc-backref" href="#method-combination-and-overriding" role="doc-backlink">Method Combination and Overriding</a></h3> <p>When an overloaded function is invoked, the implementation with the signature that <em>most specifically matches</em> the calling arguments is the one used. If no implementation matches, a <code class="docutils literal notranslate"><span class="pre">NoApplicableMethods</span></code> error is raised. If more than one implementation matches, but none of the signatures are more specific than the others, an <code class="docutils literal notranslate"><span class="pre">AmbiguousMethods</span></code> error is raised.</p> <p>For example, the following pair of implementations are ambiguous, if the <code class="docutils literal notranslate"><span class="pre">foo()</span></code> function is ever called with two integer arguments, because both signatures would apply, but neither signature is more <em>specific</em> than the other (i.e., neither implies the other):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">foo</span><span class="p">(</span><span class="n">bar</span><span class="p">:</span><span class="nb">int</span><span class="p">,</span> <span class="n">baz</span><span class="p">:</span><span class="nb">object</span><span class="p">):</span> <span class="k">pass</span> <span class="nd">@overload</span> <span class="k">def</span><span class="w"> </span><span class="nf">foo</span><span class="p">(</span><span class="n">bar</span><span class="p">:</span><span class="nb">object</span><span class="p">,</span> <span class="n">baz</span><span class="p">:</span><span class="nb">int</span><span class="p">):</span> <span class="k">pass</span> </pre></div> </div> <p>In contrast, the following pair of implementations can never be ambiguous, because one signature always implies the other; the <code class="docutils literal notranslate"><span class="pre">int/int</span></code> signature is more specific than the <code class="docutils literal notranslate"><span class="pre">object/object</span></code> signature:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">foo</span><span class="p">(</span><span class="n">bar</span><span class="p">:</span><span class="nb">object</span><span class="p">,</span> <span class="n">baz</span><span class="p">:</span><span class="nb">object</span><span class="p">):</span> <span class="k">pass</span> <span class="nd">@overload</span> <span class="k">def</span><span class="w"> </span><span class="nf">foo</span><span class="p">(</span><span class="n">bar</span><span class="p">:</span><span class="nb">int</span><span class="p">,</span> <span class="n">baz</span><span class="p">:</span><span class="nb">int</span><span class="p">):</span> <span class="k">pass</span> </pre></div> </div> <p>A signature S1 implies another signature S2, if whenever S1 would apply, S2 would also. A signature S1 is “more specific” than another signature S2, if S1 implies S2, but S2 does not imply S1.</p> <p>Although the examples above have all used concrete or abstract types as argument annotations, there is no requirement that the annotations be such. They can also be “interface” objects (discussed in the <a class="reference internal" href="#interfaces-and-adaptation">Interfaces and Adaptation</a> section), including user-defined interface types. (They can also be other objects whose types are appropriately registered via the <a class="reference internal" href="#extension-api">Extension API</a>.)</p> <section id="proceeding-to-the-next-method"> <h4><a class="toc-backref" href="#proceeding-to-the-next-method" role="doc-backlink">Proceeding to the “Next” Method</a></h4> <p>If the first parameter of an overloaded function is named <code class="docutils literal notranslate"><span class="pre">__proceed__</span></code>, it will be passed a callable representing the next most-specific method. For example, this code:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">foo</span><span class="p">(</span><span class="n">bar</span><span class="p">:</span><span class="nb">object</span><span class="p">,</span> <span class="n">baz</span><span class="p">:</span><span class="nb">object</span><span class="p">):</span> <span class="nb">print</span> <span class="s2">"got objects!"</span> <span class="nd">@overload</span> <span class="k">def</span><span class="w"> </span><span class="nf">foo</span><span class="p">(</span><span class="n">__proceed__</span><span class="p">,</span> <span class="n">bar</span><span class="p">:</span><span class="nb">int</span><span class="p">,</span> <span class="n">baz</span><span class="p">:</span><span class="nb">int</span><span class="p">):</span> <span class="nb">print</span> <span class="s2">"got integers!"</span> <span class="k">return</span> <span class="n">__proceed__</span><span class="p">(</span><span class="n">bar</span><span class="p">,</span> <span class="n">baz</span><span class="p">)</span> </pre></div> </div> <p>Will print “got integers!” followed by “got objects!”.</p> <p>If there is no next most-specific method, <code class="docutils literal notranslate"><span class="pre">__proceed__</span></code> will be bound to a <code class="docutils literal notranslate"><span class="pre">NoApplicableMethods</span></code> instance. When called, a new <code class="docutils literal notranslate"><span class="pre">NoApplicableMethods</span></code> instance will be raised, with the arguments passed to the first instance.</p> <p>Similarly, if the next most-specific methods have ambiguous precedence with respect to each other, <code class="docutils literal notranslate"><span class="pre">__proceed__</span></code> will be bound to an <code class="docutils literal notranslate"><span class="pre">AmbiguousMethods</span></code> instance, and if called, it will raise a new instance.</p> <p>Thus, a method can either check if <code class="docutils literal notranslate"><span class="pre">__proceed__</span></code> is an error instance, or simply invoke it. The <code class="docutils literal notranslate"><span class="pre">NoApplicableMethods</span></code> and <code class="docutils literal notranslate"><span class="pre">AmbiguousMethods</span></code> error classes have a common <code class="docutils literal notranslate"><span class="pre">DispatchError</span></code> base class, so <code class="docutils literal notranslate"><span class="pre">isinstance(__proceed__,</span> <span class="pre">overloading.DispatchError)</span></code> is sufficient to identify whether <code class="docutils literal notranslate"><span class="pre">__proceed__</span></code> can be safely called.</p> <p>(Implementation note: using a magic argument name like <code class="docutils literal notranslate"><span class="pre">__proceed__</span></code> could potentially be replaced by a magic function that would be called to obtain the next method. A magic function, however, would degrade performance and might be more difficult to implement on non-CPython platforms. Method chaining via magic argument names, however, can be efficiently implemented on any Python platform that supports creating bound methods from functions – one simply recursively binds each function to be chained, using the following function or error as the <code class="docutils literal notranslate"><span class="pre">im_self</span></code> of the bound method.)</p> </section> <section id="before-and-after-methods"> <h4><a class="toc-backref" href="#before-and-after-methods" role="doc-backlink">“Before” and “After” Methods</a></h4> <p>In addition to the simple next-method chaining shown above, it is sometimes useful to have other ways of combining methods. For example, the “observer pattern” can sometimes be implemented by adding extra methods to a function, that execute before or after the normal implementation.</p> <p>To support these use cases, the <code class="docutils literal notranslate"><span class="pre">overloading</span></code> module will supply <code class="docutils literal notranslate"><span class="pre">@before</span></code>, <code class="docutils literal notranslate"><span class="pre">@after</span></code>, and <code class="docutils literal notranslate"><span class="pre">@around</span></code> decorators, that roughly correspond to the same types of methods in the Common Lisp Object System (CLOS), or the corresponding “advice” types in AspectJ.</p> <p>Like <code class="docutils literal notranslate"><span class="pre">@when</span></code>, all of these decorators must be passed the function to be overloaded, and can optionally accept a predicate as well:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">overloading</span><span class="w"> </span><span class="kn">import</span> <span class="n">before</span><span class="p">,</span> <span class="n">after</span> <span class="k">def</span><span class="w"> </span><span class="nf">begin_transaction</span><span class="p">(</span><span class="n">db</span><span class="p">):</span> <span class="nb">print</span> <span class="s2">"Beginning the actual transaction"</span> <span class="nd">@before</span><span class="p">(</span><span class="n">begin_transaction</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">check_single_access</span><span class="p">(</span><span class="n">db</span><span class="p">:</span> <span class="n">SingletonDB</span><span class="p">):</span> <span class="k">if</span> <span class="n">db</span><span class="o">.</span><span class="n">inuse</span><span class="p">:</span> <span class="k">raise</span> <span class="n">TransactionError</span><span class="p">(</span><span class="s2">"Database already in use"</span><span class="p">)</span> <span class="nd">@after</span><span class="p">(</span><span class="n">begin_transaction</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">start_logging</span><span class="p">(</span><span class="n">db</span><span class="p">:</span> <span class="n">LoggableDB</span><span class="p">):</span> <span class="n">db</span><span class="o">.</span><span class="n">set_log_level</span><span class="p">(</span><span class="n">VERBOSE</span><span class="p">)</span> </pre></div> </div> <p><code class="docutils literal notranslate"><span class="pre">@before</span></code> and <code class="docutils literal notranslate"><span class="pre">@after</span></code> methods are invoked either before or after the main function body, and are <em>never considered ambiguous</em>. That is, it will not cause any errors to have multiple “before” or “after” methods with identical or overlapping signatures. Ambiguities are resolved using the order in which the methods were added to the target function.</p> <p>“Before” methods are invoked most-specific method first, with ambiguous methods being executed in the order they were added. All “before” methods are called before any of the function’s “primary” methods (i.e. normal <code class="docutils literal notranslate"><span class="pre">@overload</span></code> methods) are executed.</p> <p>“After” methods are invoked in the <em>reverse</em> order, after all of the function’s “primary” methods are executed. That is, they are executed least-specific methods first, with ambiguous methods being executed in the reverse of the order in which they were added.</p> <p>The return values of both “before” and “after” methods are ignored, and any uncaught exceptions raised by <em>any</em> methods (primary or other) immediately end the dispatching process. “Before” and “after” methods cannot have <code class="docutils literal notranslate"><span class="pre">__proceed__</span></code> arguments, as they are not responsible for calling any other methods. They are simply called as a notification before or after the primary methods.</p> <p>Thus, “before” and “after” methods can be used to check or establish preconditions (e.g. by raising an error if the conditions aren’t met) or to ensure postconditions, without needing to duplicate any existing functionality.</p> </section> <section id="around-methods"> <h4><a class="toc-backref" href="#around-methods" role="doc-backlink">“Around” Methods</a></h4> <p>The <code class="docutils literal notranslate"><span class="pre">@around</span></code> decorator declares a method as an “around” method. “Around” methods are much like primary methods, except that the least-specific “around” method has higher precedence than the most-specific “before” method.</p> <p>Unlike “before” and “after” methods, however, “Around” methods <em>are</em> responsible for calling their <code class="docutils literal notranslate"><span class="pre">__proceed__</span></code> argument, in order to continue the invocation process. “Around” methods are usually used to transform input arguments or return values, or to wrap specific cases with special error handling or try/finally conditions, e.g.:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">overloading</span><span class="w"> </span><span class="kn">import</span> <span class="n">around</span> <span class="nd">@around</span><span class="p">(</span><span class="n">commit_transaction</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">lock_while_committing</span><span class="p">(</span><span class="n">__proceed__</span><span class="p">,</span> <span class="n">db</span><span class="p">:</span> <span class="n">SingletonDB</span><span class="p">):</span> <span class="k">with</span> <span class="n">db</span><span class="o">.</span><span class="n">global_lock</span><span class="p">:</span> <span class="k">return</span> <span class="n">__proceed__</span><span class="p">(</span><span class="n">db</span><span class="p">)</span> </pre></div> </div> <p>They can also be used to replace the normal handling for a specific case, by <em>not</em> invoking the <code class="docutils literal notranslate"><span class="pre">__proceed__</span></code> function.</p> <p>The <code class="docutils literal notranslate"><span class="pre">__proceed__</span></code> given to an “around” method will either be the next applicable “around” method, a <code class="docutils literal notranslate"><span class="pre">DispatchError</span></code> instance, or a synthetic method object that will call all the “before” methods, followed by the primary method chain, followed by all the “after” methods, and return the result from the primary method chain.</p> <p>Thus, just as with normal methods, <code class="docutils literal notranslate"><span class="pre">__proceed__</span></code> can be checked for <code class="docutils literal notranslate"><span class="pre">DispatchError</span></code>-ness, or simply invoked. The “around” method should return the value returned by <code class="docutils literal notranslate"><span class="pre">__proceed__</span></code>, unless of course it wishes to modify or replace it with a different return value for the function as a whole.</p> </section> <section id="custom-combinations"> <h4><a class="toc-backref" href="#custom-combinations" role="doc-backlink">Custom Combinations</a></h4> <p>The decorators described above (<code class="docutils literal notranslate"><span class="pre">@overload</span></code>, <code class="docutils literal notranslate"><span class="pre">@when</span></code>, <code class="docutils literal notranslate"><span class="pre">@before</span></code>, <code class="docutils literal notranslate"><span class="pre">@after</span></code>, and <code class="docutils literal notranslate"><span class="pre">@around</span></code>) collectively implement what in CLOS is called the “standard method combination” – the most common patterns used in combining methods.</p> <p>Sometimes, however, an application or library may have use for a more sophisticated type of method combination. For example, if you would like to have “discount” methods that return a percentage off, to be subtracted from the value returned by the primary method(s), you might write something like this:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">overloading</span><span class="w"> </span><span class="kn">import</span> <span class="n">always_overrides</span><span class="p">,</span> <span class="n">merge_by_default</span> <span class="kn">from</span><span class="w"> </span><span class="nn">overloading</span><span class="w"> </span><span class="kn">import</span> <span class="n">Around</span><span class="p">,</span> <span class="n">Before</span><span class="p">,</span> <span class="n">After</span><span class="p">,</span> <span class="n">Method</span><span class="p">,</span> <span class="n">MethodList</span> <span class="k">class</span><span class="w"> </span><span class="nc">Discount</span><span class="p">(</span><span class="n">MethodList</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Apply return values as discounts"""</span> <span class="k">def</span><span class="w"> </span><span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span> <span class="n">retval</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tail</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span> <span class="k">for</span> <span class="n">sig</span><span class="p">,</span> <span class="n">body</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">sorted</span><span class="p">():</span> <span class="n">retval</span> <span class="o">-=</span> <span class="n">retval</span> <span class="o">*</span> <span class="n">body</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span> <span class="k">return</span> <span class="n">retval</span> <span class="c1"># merge discounts by priority</span> <span class="n">merge_by_default</span><span class="p">(</span><span class="n">Discount</span><span class="p">)</span> <span class="c1"># discounts have precedence over before/after/primary methods</span> <span class="n">always_overrides</span><span class="p">(</span><span class="n">Discount</span><span class="p">,</span> <span class="n">Before</span><span class="p">)</span> <span class="n">always_overrides</span><span class="p">(</span><span class="n">Discount</span><span class="p">,</span> <span class="n">After</span><span class="p">)</span> <span class="n">always_overrides</span><span class="p">(</span><span class="n">Discount</span><span class="p">,</span> <span class="n">Method</span><span class="p">)</span> <span class="c1"># but not over "around" methods</span> <span class="n">always_overrides</span><span class="p">(</span><span class="n">Around</span><span class="p">,</span> <span class="n">Discount</span><span class="p">)</span> <span class="c1"># Make a decorator called "discount" that works just like the</span> <span class="c1"># standard decorators...</span> <span class="n">discount</span> <span class="o">=</span> <span class="n">Discount</span><span class="o">.</span><span class="n">make_decorator</span><span class="p">(</span><span class="s1">'discount'</span><span class="p">)</span> <span class="c1"># and now let's use it...</span> <span class="k">def</span><span class="w"> </span><span class="nf">price</span><span class="p">(</span><span class="n">product</span><span class="p">):</span> <span class="k">return</span> <span class="n">product</span><span class="o">.</span><span class="n">list_price</span> <span class="nd">@discount</span><span class="p">(</span><span class="n">price</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">ten_percent_off_shoes</span><span class="p">(</span><span class="n">product</span><span class="p">:</span> <span class="n">Shoe</span><span class="p">)</span> <span class="k">return</span> <span class="n">Decimal</span><span class="p">(</span><span class="s1">'0.1'</span><span class="p">)</span> </pre></div> </div> <p>Similar techniques can be used to implement a wide variety of CLOS-style method qualifiers and combination rules. The process of creating custom method combination objects and their corresponding decorators is described in more detail under the <a class="reference internal" href="#extension-api">Extension API</a> section.</p> <p>Note, by the way, that the <code class="docutils literal notranslate"><span class="pre">@discount</span></code> decorator shown will work correctly with any new predicates defined by other code. For example, if <code class="docutils literal notranslate"><span class="pre">zope.interface</span></code> were to register its interface types to work correctly as argument annotations, you would be able to specify discounts on the basis of its interface types, not just classes or <code class="docutils literal notranslate"><span class="pre">overloading</span></code>-defined interface types.</p> <p>Similarly, if a library like RuleDispatch or PEAK-Rules were to register an appropriate predicate implementation and dispatch engine, one would then be able to use those predicates for discounts as well, e.g.:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">somewhere</span><span class="w"> </span><span class="kn">import</span> <span class="n">Pred</span> <span class="c1"># some predicate implementation</span> <span class="nd">@discount</span><span class="p">(</span> <span class="n">price</span><span class="p">,</span> <span class="n">Pred</span><span class="p">(</span><span class="s2">"isinstance(product,Shoe) and"</span> <span class="s2">" product.material.name=='Blue Suede'"</span><span class="p">)</span> <span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">forty_off_blue_suede_shoes</span><span class="p">(</span><span class="n">product</span><span class="p">):</span> <span class="k">return</span> <span class="n">Decimal</span><span class="p">(</span><span class="s1">'0.4'</span><span class="p">)</span> </pre></div> </div> <p>The process of defining custom predicate types and dispatching engines is also described in more detail under the <a class="reference internal" href="#extension-api">Extension API</a> section.</p> </section> </section> <section id="overloading-inside-classes"> <h3><a class="toc-backref" href="#overloading-inside-classes" role="doc-backlink">Overloading Inside Classes</a></h3> <p>All of the decorators above have a special additional behavior when they are directly invoked within a class body: the first parameter (other than <code class="docutils literal notranslate"><span class="pre">__proceed__</span></code>, if present) of the decorated function will be treated as though it had an annotation equal to the class in which it was defined.</p> <p>That is, this code:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">And</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="c1"># ...</span> <span class="nd">@when</span><span class="p">(</span><span class="n">get_conjuncts</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">__conjuncts</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">conjuncts</span> </pre></div> </div> <p>produces the same effect as this (apart from the existence of a private method):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">And</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="c1"># ...</span> <span class="nd">@when</span><span class="p">(</span><span class="n">get_conjuncts</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_conjuncts_of_and</span><span class="p">(</span><span class="n">ob</span><span class="p">:</span> <span class="n">And</span><span class="p">):</span> <span class="k">return</span> <span class="n">ob</span><span class="o">.</span><span class="n">conjuncts</span> </pre></div> </div> <p>This behavior is both a convenience enhancement when defining lots of methods, and a requirement for safely distinguishing multi-argument overloads in subclasses. Consider, for example, the following code:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">A</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="nf">foo</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ob</span><span class="p">):</span> <span class="nb">print</span> <span class="s2">"got an object"</span> <span class="nd">@overload</span> <span class="k">def</span><span class="w"> </span><span class="nf">foo</span><span class="p">(</span><span class="n">__proceed__</span><span class="p">,</span> <span class="bp">self</span><span class="p">,</span> <span class="n">ob</span><span class="p">:</span><span class="n">Iterable</span><span class="p">):</span> <span class="nb">print</span> <span class="s2">"it's iterable!"</span> <span class="k">return</span> <span class="n">__proceed__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ob</span><span class="p">)</span> <span class="k">class</span><span class="w"> </span><span class="nc">B</span><span class="p">(</span><span class="n">A</span><span class="p">):</span> <span class="n">foo</span> <span class="o">=</span> <span class="n">A</span><span class="o">.</span><span class="n">foo</span> <span class="c1"># foo must be defined in local namespace</span> <span class="nd">@overload</span> <span class="k">def</span><span class="w"> </span><span class="nf">foo</span><span class="p">(</span><span class="n">__proceed__</span><span class="p">,</span> <span class="bp">self</span><span class="p">,</span> <span class="n">ob</span><span class="p">:</span><span class="n">Iterable</span><span class="p">):</span> <span class="nb">print</span> <span class="s2">"B got an iterable!"</span> <span class="k">return</span> <span class="n">__proceed__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ob</span><span class="p">)</span> </pre></div> </div> <p>Due to the implicit class rule, calling <code class="docutils literal notranslate"><span class="pre">B().foo([])</span></code> will print “B got an iterable!” followed by “it’s iterable!”, and finally, “got an object”, while <code class="docutils literal notranslate"><span class="pre">A().foo([])</span></code> would print only the messages defined in <code class="docutils literal notranslate"><span class="pre">A</span></code>.</p> <p>Conversely, without the implicit class rule, the two “Iterable” methods would have the exact same applicability conditions, so calling either <code class="docutils literal notranslate"><span class="pre">A().foo([])</span></code> or <code class="docutils literal notranslate"><span class="pre">B().foo([])</span></code> would result in an <code class="docutils literal notranslate"><span class="pre">AmbiguousMethods</span></code> error.</p> <p>It is currently an open issue to determine the best way to implement this rule in Python 3.0. Under Python 2.x, a class’ metaclass was not chosen until the end of the class body, which means that decorators could insert a custom metaclass to do processing of this sort. (This is how RuleDispatch, for example, implements the implicit class rule.)</p> <p><a class="pep reference internal" href="../pep-3115/" title="PEP 3115 – Metaclasses in Python 3000">PEP 3115</a>, however, requires that a class’ metaclass be determined <em>before</em> the class body has executed, making it impossible to use this technique for class decoration any more.</p> <p>At this writing, discussion on this issue is ongoing.</p> </section> <section id="interfaces-and-adaptation"> <h3><a class="toc-backref" href="#interfaces-and-adaptation" role="doc-backlink">Interfaces and Adaptation</a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">overloading</span></code> module provides a simple implementation of interfaces and adaptation. The following example defines an <code class="docutils literal notranslate"><span class="pre">IStack</span></code> interface, and declares that <code class="docutils literal notranslate"><span class="pre">list</span></code> objects support it:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">overloading</span><span class="w"> </span><span class="kn">import</span> <span class="n">abstract</span><span class="p">,</span> <span class="n">Interface</span> <span class="k">class</span><span class="w"> </span><span class="nc">IStack</span><span class="p">(</span><span class="n">Interface</span><span class="p">):</span> <span class="nd">@abstract</span> <span class="k">def</span><span class="w"> </span><span class="nf">push</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ob</span><span class="p">)</span> <span class="w"> </span><span class="sd">"""Push 'ob' onto the stack"""</span> <span class="nd">@abstract</span> <span class="k">def</span><span class="w"> </span><span class="nf">pop</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Pop a value and return it"""</span> <span class="n">when</span><span class="p">(</span><span class="n">IStack</span><span class="o">.</span><span class="n">push</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,</span> <span class="nb">object</span><span class="p">))(</span><span class="nb">list</span><span class="o">.</span><span class="n">append</span><span class="p">)</span> <span class="n">when</span><span class="p">(</span><span class="n">IStack</span><span class="o">.</span><span class="n">pop</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,))(</span><span class="nb">list</span><span class="o">.</span><span class="n">pop</span><span class="p">)</span> <span class="n">mylist</span> <span class="o">=</span> <span class="p">[]</span> <span class="n">mystack</span> <span class="o">=</span> <span class="n">IStack</span><span class="p">(</span><span class="n">mylist</span><span class="p">)</span> <span class="n">mystack</span><span class="o">.</span><span class="n">push</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span> <span class="k">assert</span> <span class="n">mystack</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span><span class="o">==</span><span class="mi">42</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">Interface</span></code> class is a kind of “universal adapter”. It accepts a single argument: an object to adapt. It then binds all its methods to the target object, in place of itself. Thus, calling <code class="docutils literal notranslate"><span class="pre">mystack.push(42</span></code>) is the same as calling <code class="docutils literal notranslate"><span class="pre">IStack.push(mylist,</span> <span class="pre">42)</span></code>.</p> <p>The <code class="docutils literal notranslate"><span class="pre">@abstract</span></code> decorator marks a function as being abstract: i.e., having no implementation. If an <code class="docutils literal notranslate"><span class="pre">@abstract</span></code> function is called, it raises <code class="docutils literal notranslate"><span class="pre">NoApplicableMethods</span></code>. To become executable, overloaded methods must be added using the techniques previously described. (That is, methods can be added using <code class="docutils literal notranslate"><span class="pre">@when</span></code>, <code class="docutils literal notranslate"><span class="pre">@before</span></code>, <code class="docutils literal notranslate"><span class="pre">@after</span></code>, <code class="docutils literal notranslate"><span class="pre">@around</span></code>, or any custom method combination decorators.)</p> <p>In the example above, the <code class="docutils literal notranslate"><span class="pre">list.append</span></code> method is added as a method for <code class="docutils literal notranslate"><span class="pre">IStack.push()</span></code> when its arguments are a list and an arbitrary object. Thus, <code class="docutils literal notranslate"><span class="pre">IStack.push(mylist,</span> <span class="pre">42)</span></code> is translated to <code class="docutils literal notranslate"><span class="pre">list.append(mylist,</span> <span class="pre">42)</span></code>, thereby implementing the desired operation.</p> <section id="abstract-and-concrete-methods"> <h4><a class="toc-backref" href="#abstract-and-concrete-methods" role="doc-backlink">Abstract and Concrete Methods</a></h4> <p>Note, by the way, that the <code class="docutils literal notranslate"><span class="pre">@abstract</span></code> decorator is not limited to use in interface definitions; it can be used anywhere that you wish to create an “empty” generic function that initially has no methods. In particular, it need not be used inside a class.</p> <p>Also note that interface methods need not be abstract; one could, for example, write an interface like this:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">IWriteMapping</span><span class="p">(</span><span class="n">Interface</span><span class="p">):</span> <span class="nd">@abstract</span> <span class="k">def</span><span class="w"> </span><span class="fm">__setitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""This has to be implemented"""</span> <span class="k">def</span><span class="w"> </span><span class="nf">update</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="n">IReadMapping</span><span class="p">):</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">IReadMapping</span><span class="p">(</span><span class="n">other</span><span class="p">)</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> <span class="bp">self</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span> </pre></div> </div> <p>As long as <code class="docutils literal notranslate"><span class="pre">__setitem__</span></code> is defined for some type, the above interface will provide a usable <code class="docutils literal notranslate"><span class="pre">update()</span></code> implementation. However, if some specific type (or pair of types) has a more efficient way of handling <code class="docutils literal notranslate"><span class="pre">update()</span></code> operations, an appropriate overload can still be registered for use in that case.</p> </section> <section id="subclassing-and-re-assembly"> <h4><a class="toc-backref" href="#subclassing-and-re-assembly" role="doc-backlink">Subclassing and Re-assembly</a></h4> <p>Interfaces can be subclassed:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">ISizedStack</span><span class="p">(</span><span class="n">IStack</span><span class="p">):</span> <span class="nd">@abstract</span> <span class="k">def</span><span class="w"> </span><span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Return the number of items on the stack"""</span> <span class="c1"># define __len__ support for ISizedStack</span> <span class="n">when</span><span class="p">(</span><span class="n">ISizedStack</span><span class="o">.</span><span class="fm">__len__</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,))(</span><span class="nb">list</span><span class="o">.</span><span class="fm">__len__</span><span class="p">)</span> </pre></div> </div> <p>Or assembled by combining functions from existing interfaces:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Sizable</span><span class="p">(</span><span class="n">Interface</span><span class="p">):</span> <span class="fm">__len__</span> <span class="o">=</span> <span class="n">ISizedStack</span><span class="o">.</span><span class="fm">__len__</span> <span class="c1"># list now implements Sizable as well as ISizedStack, without</span> <span class="c1"># making any new declarations!</span> </pre></div> </div> <p>A class can be considered to “adapt to” an interface at a given point in time, if no method defined in the interface is guaranteed to raise a <code class="docutils literal notranslate"><span class="pre">NoApplicableMethods</span></code> error if invoked on an instance of that class at that point in time.</p> <p>In normal usage, however, it is “easier to ask forgiveness than permission”. That is, it is easier to simply use an interface on an object by adapting it to the interface (e.g. <code class="docutils literal notranslate"><span class="pre">IStack(mylist)</span></code>) or invoking interface methods directly (e.g. <code class="docutils literal notranslate"><span class="pre">IStack.push(mylist,</span> <span class="pre">42)</span></code>), than to try to figure out whether the object is adaptable to (or directly implements) the interface.</p> </section> <section id="implementing-an-interface-in-a-class"> <h4><a class="toc-backref" href="#implementing-an-interface-in-a-class" role="doc-backlink">Implementing an Interface in a Class</a></h4> <p>It is possible to declare that a class directly implements an interface, using the <code class="docutils literal notranslate"><span class="pre">declare_implementation()</span></code> function:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">overloading</span><span class="w"> </span><span class="kn">import</span> <span class="n">declare_implementation</span> <span class="k">class</span><span class="w"> </span><span class="nc">Stack</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">def</span><span class="w"> </span><span class="nf">push</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ob</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ob</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">pop</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">data</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span> <span class="n">declare_implementation</span><span class="p">(</span><span class="n">IStack</span><span class="p">,</span> <span class="n">Stack</span><span class="p">)</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">declare_implementation()</span></code> call above is roughly equivalent to the following steps:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">when</span><span class="p">(</span><span class="n">IStack</span><span class="o">.</span><span class="n">push</span><span class="p">,</span> <span class="p">(</span><span class="n">Stack</span><span class="p">,</span><span class="nb">object</span><span class="p">))(</span><span class="k">lambda</span> <span class="bp">self</span><span class="p">,</span> <span class="n">ob</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">push</span><span class="p">(</span><span class="n">ob</span><span class="p">))</span> <span class="n">when</span><span class="p">(</span><span class="n">IStack</span><span class="o">.</span><span class="n">pop</span><span class="p">,</span> <span class="p">(</span><span class="n">Stack</span><span class="p">,))(</span><span class="k">lambda</span> <span class="bp">self</span><span class="p">,</span> <span class="n">ob</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">pop</span><span class="p">())</span> </pre></div> </div> <p>That is, calling <code class="docutils literal notranslate"><span class="pre">IStack.push()</span></code> or <code class="docutils literal notranslate"><span class="pre">IStack.pop()</span></code> on an instance of any subclass of <code class="docutils literal notranslate"><span class="pre">Stack</span></code>, will simply delegate to the actual <code class="docutils literal notranslate"><span class="pre">push()</span></code> or <code class="docutils literal notranslate"><span class="pre">pop()</span></code> methods thereof.</p> <p>For the sake of efficiency, calling <code class="docutils literal notranslate"><span class="pre">IStack(s)</span></code> where <code class="docutils literal notranslate"><span class="pre">s</span></code> is an instance of <code class="docutils literal notranslate"><span class="pre">Stack</span></code>, <strong>may</strong> return <code class="docutils literal notranslate"><span class="pre">s</span></code> rather than an <code class="docutils literal notranslate"><span class="pre">IStack</span></code> adapter. (Note that calling <code class="docutils literal notranslate"><span class="pre">IStack(x)</span></code> where <code class="docutils literal notranslate"><span class="pre">x</span></code> is already an <code class="docutils literal notranslate"><span class="pre">IStack</span></code> adapter will always return <code class="docutils literal notranslate"><span class="pre">x</span></code> unchanged; this is an additional optimization allowed in cases where the adaptee is known to <em>directly</em> implement the interface, without adaptation.)</p> <p>For convenience, it may be useful to declare implementations in the class header, e.g.:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Stack</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">Implementer</span><span class="p">,</span> <span class="n">implements</span><span class="o">=</span><span class="n">IStack</span><span class="p">):</span> <span class="o">...</span> </pre></div> </div> <p>Instead of calling <code class="docutils literal notranslate"><span class="pre">declare_implementation()</span></code> after the end of the suite.</p> </section> <section id="interfaces-as-type-specifiers"> <h4><a class="toc-backref" href="#interfaces-as-type-specifiers" role="doc-backlink">Interfaces as Type Specifiers</a></h4> <p><code class="docutils literal notranslate"><span class="pre">Interface</span></code> subclasses can be used as argument annotations to indicate what type of objects are acceptable to an overload, e.g.:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@overload</span> <span class="k">def</span><span class="w"> </span><span class="nf">traverse</span><span class="p">(</span><span class="n">g</span><span class="p">:</span> <span class="n">IGraph</span><span class="p">,</span> <span class="n">s</span><span class="p">:</span> <span class="n">IStack</span><span class="p">):</span> <span class="n">g</span> <span class="o">=</span> <span class="n">IGraph</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> <span class="n">s</span> <span class="o">=</span> <span class="n">IStack</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="c1"># etc....</span> </pre></div> </div> <p>Note, however, that the actual arguments are <em>not</em> changed or adapted in any way by the mere use of an interface as a type specifier. You must explicitly cast the objects to the appropriate interface, as shown above.</p> <p>Note, however, that other patterns of interface use are possible. For example, other interface implementations might not support adaptation, or might require that function arguments already be adapted to the specified interface. So the exact semantics of using an interface as a type specifier are dependent on the interface objects you actually use.</p> <p>For the interface objects defined by this PEP, however, the semantics are as described above. An interface I1 is considered “more specific” than another interface I2, if the set of descriptors in I1’s inheritance hierarchy are a proper superset of the descriptors in I2’s inheritance hierarchy.</p> <p>So, for example, <code class="docutils literal notranslate"><span class="pre">ISizedStack</span></code> is more specific than both <code class="docutils literal notranslate"><span class="pre">ISizable</span></code> and <code class="docutils literal notranslate"><span class="pre">ISizedStack</span></code>, irrespective of the inheritance relationships between these interfaces. It is purely a question of what operations are included within those interfaces – and the <em>names</em> of the operations are unimportant.</p> <p>Interfaces (at least the ones provided by <code class="docutils literal notranslate"><span class="pre">overloading</span></code>) are always considered less-specific than concrete classes. Other interface implementations can decide on their own specificity rules, both between interfaces and other interfaces, and between interfaces and classes.</p> </section> <section id="non-method-attributes-in-interfaces"> <h4><a class="toc-backref" href="#non-method-attributes-in-interfaces" role="doc-backlink">Non-Method Attributes in Interfaces</a></h4> <p>The <code class="docutils literal notranslate"><span class="pre">Interface</span></code> implementation actually treats all attributes and methods (i.e. descriptors) in the same way: their <code class="docutils literal notranslate"><span class="pre">__get__</span></code> (and <code class="docutils literal notranslate"><span class="pre">__set__</span></code> and <code class="docutils literal notranslate"><span class="pre">__delete__</span></code>, if present) methods are called with the wrapped (adapted) object as “self”. For functions, this has the effect of creating a bound method linking the generic function to the wrapped object.</p> <p>For non-function attributes, it may be easiest to specify them using the <code class="docutils literal notranslate"><span class="pre">property</span></code> built-in, and the corresponding <code class="docutils literal notranslate"><span class="pre">fget</span></code>, <code class="docutils literal notranslate"><span class="pre">fset</span></code>, and <code class="docutils literal notranslate"><span class="pre">fdel</span></code> attributes:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">ILength</span><span class="p">(</span><span class="n">Interface</span><span class="p">):</span> <span class="nd">@property</span> <span class="nd">@abstract</span> <span class="k">def</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Read-only length attribute"""</span> <span class="c1"># ILength(aList).length == list.__len__(aList)</span> <span class="n">when</span><span class="p">(</span><span class="n">ILength</span><span class="o">.</span><span class="n">length</span><span class="o">.</span><span class="n">fget</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,))(</span><span class="nb">list</span><span class="o">.</span><span class="fm">__len__</span><span class="p">)</span> </pre></div> </div> <p>Alternatively, methods such as <code class="docutils literal notranslate"><span class="pre">_get_foo()</span></code> and <code class="docutils literal notranslate"><span class="pre">_set_foo()</span></code> may be defined as part of the interface, and the property defined in terms of those methods, but this is a bit more difficult for users to implement correctly when creating a class that directly implements the interface, as they would then need to match all the individual method names, not just the name of the property or attribute.</p> </section> </section> <section id="aspects"> <h3><a class="toc-backref" href="#aspects" role="doc-backlink">Aspects</a></h3> <p>The adaptation system described above assumes that adapters are “stateless”, which is to say that adapters have no attributes or state apart from that of the adapted object. This follows the “typeclass/instance” model of Haskell, and the concept of “pure” (i.e., transitively composable) adapters.</p> <p>However, there are occasionally cases where, to provide a complete implementation of some interface, some sort of additional state is required.</p> <p>One possibility of course, would be to attach monkeypatched “private” attributes to the adaptee. But this is subject to name collisions, and complicates the process of initialization (since any code using these attributes has to check for their existence and initialize them if necessary). It also doesn’t work on objects that don’t have a <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> attribute.</p> <p>So the <code class="docutils literal notranslate"><span class="pre">Aspect</span></code> class is provided to make it easy to attach extra information to objects that either:</p> <ol class="arabic simple"> <li>have a <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> attribute (so aspect instances can be stored in it, keyed by aspect class),</li> <li>support weak referencing (so aspect instances can be managed using a global but thread-safe weak-reference dictionary), or</li> <li>implement or can be adapt to the <code class="docutils literal notranslate"><span class="pre">overloading.IAspectOwner</span></code> interface (technically, #1 or #2 imply this).</li> </ol> <p>Subclassing <code class="docutils literal notranslate"><span class="pre">Aspect</span></code> creates an adapter class whose state is tied to the life of the adapted object.</p> <p>For example, suppose you would like to count all the times a certain method is called on instances of <code class="docutils literal notranslate"><span class="pre">Target</span></code> (a classic AOP example). You might do something like:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">overloading</span><span class="w"> </span><span class="kn">import</span> <span class="n">Aspect</span> <span class="k">class</span><span class="w"> </span><span class="nc">Count</span><span class="p">(</span><span class="n">Aspect</span><span class="p">):</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span> <span class="nd">@after</span><span class="p">(</span><span class="n">Target</span><span class="o">.</span><span class="n">some_method</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">count_after_call</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span><span class="n">Target</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span> <span class="n">Count</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">count</span> <span class="o">+=</span> <span class="mi">1</span> </pre></div> </div> <p>The above code will keep track of the number of times that <code class="docutils literal notranslate"><span class="pre">Target.some_method()</span></code> is successfully called on an instance of <code class="docutils literal notranslate"><span class="pre">Target</span></code> (i.e., it will not count errors unless they occur in a more-specific “after” method). Other code can then access the count using <code class="docutils literal notranslate"><span class="pre">Count(someTarget).count</span></code>.</p> <p><code class="docutils literal notranslate"><span class="pre">Aspect</span></code> instances can of course have <code class="docutils literal notranslate"><span class="pre">__init__</span></code> methods, to initialize any data structures. They can use either <code class="docutils literal notranslate"><span class="pre">__slots__</span></code> or dictionary-based attributes for storage.</p> <p>While this facility is rather primitive compared to a full-featured AOP tool like AspectJ, persons who wish to build pointcut libraries or other AspectJ-like features can certainly use <code class="docutils literal notranslate"><span class="pre">Aspect</span></code> objects and method-combination decorators as a base for building more expressive AOP tools.</p> <dl class="simple"> <dt>XXX spec out full aspect API, including keys, N-to-1 aspects, manual</dt><dd>attach/detach/delete of aspect instances, and the <code class="docutils literal notranslate"><span class="pre">IAspectOwner</span></code> interface.</dd> </dl> </section> </section> <section id="extension-api"> <h2><a class="toc-backref" href="#extension-api" role="doc-backlink">Extension API</a></h2> <p>TODO: explain how all of these work</p> <p>implies(o1, o2)</p> <p>declare_implementation(iface, class)</p> <p>predicate_signatures(ob)</p> <p>parse_rule(ruleset, body, predicate, actiontype, localdict, globaldict)</p> <p>combine_actions(a1, a2)</p> <p>rules_for(f)</p> <p>Rule objects</p> <p>ActionDef objects</p> <p>RuleSet objects</p> <p>Method objects</p> <p>MethodList objects</p> <p>IAspectOwner</p> </section> <section id="overloading-usage-patterns"> <h2><a class="toc-backref" href="#overloading-usage-patterns" role="doc-backlink">Overloading Usage Patterns</a></h2> <p>In discussion on the Python-3000 list, the proposed feature of allowing arbitrary functions to be overloaded has been somewhat controversial, with some people expressing concern that this would make programs more difficult to understand.</p> <p>The general thrust of this argument is that one cannot rely on what a function does, if it can be changed from anywhere in the program at any time. Even though in principle this can already happen through monkeypatching or code substitution, it is considered poor practice to do so.</p> <p>However, providing support for overloading any function (or so the argument goes), is implicitly blessing such changes as being an acceptable practice.</p> <p>This argument appears to make sense in theory, but it is almost entirely mooted in practice for two reasons.</p> <p>First, people are generally not perverse, defining a function to do one thing in one place, and then summarily defining it to do the opposite somewhere else! The principal reasons to extend the behavior of a function that has <em>not</em> been specifically made generic are to:</p> <ul class="simple"> <li>Add special cases not contemplated by the original function’s author, such as support for additional types.</li> <li>Be notified of an action in order to cause some related operation to be performed, either before the original operation is performed, after it, or both. This can include general-purpose operations like adding logging, timing, or tracing, as well as application-specific behavior.</li> </ul> <p>None of these reasons for adding overloads imply any change to the intended default or overall behavior of the existing function, however. Just as a base class method may be overridden by a subclass for these same two reasons, so too may a function be overloaded to provide for such enhancements.</p> <p>In other words, universal overloading does not equal <em>arbitrary</em> overloading, in the sense that we need not expect people to randomly redefine the behavior of existing functions in illogical or unpredictable ways. If they did so, it would be no less of a bad practice than any other way of writing illogical or unpredictable code!</p> <p>However, to distinguish bad practice from good, it is perhaps necessary to clarify further what good practice for defining overloads <em>is</em>. And that brings us to the second reason why generic functions do not necessarily make programs harder to understand: overloading patterns in actual programs tend to follow very predictable patterns. (Both in Python and in languages that have no <em>non</em>-generic functions.)</p> <p>If a module is defining a new generic operation, it will usually also define any required overloads for existing types in the same place. Likewise, if a module is defining a new type, then it will usually define overloads there for any generic functions that it knows or cares about.</p> <p>As a result, the vast majority of overloads can be found adjacent to either the function being overloaded, or to a newly-defined type for which the overload is adding support. Thus, overloads are highly-discoverable in the common case, as you are either looking at the function or the type, or both.</p> <p>It is only in rather infrequent cases that one will have overloads in a module that contains neither the function nor the type(s) for which the overload is added. This would be the case if, say, a third-party created a bridge of support between one library’s types and another library’s generic function(s). In such a case, however, best practice suggests prominently advertising this, especially by way of the module name.</p> <p>For example, PyProtocols defines such bridge support for working with Zope interfaces and legacy Twisted interfaces, using modules called <code class="docutils literal notranslate"><span class="pre">protocols.twisted_support</span></code> and <code class="docutils literal notranslate"><span class="pre">protocols.zope_support</span></code>. (These bridges are done with interface adapters, rather than generic functions, but the basic principle is the same.)</p> <p>In short, understanding programs in the presence of universal overloading need not be any more difficult, given that the vast majority of overloads will either be adjacent to a function, or the definition of a type that is passed to that function.</p> <p>And, in the absence of incompetence or deliberate intention to be obscure, the few overloads that are not adjacent to the relevant type(s) or function(s), will generally not need to be understood or known about outside the scope where those overloads are defined. (Except in the “support modules” case, where best practice suggests naming them accordingly.)</p> </section> <section id="implementation-notes"> <h2><a class="toc-backref" href="#implementation-notes" role="doc-backlink">Implementation Notes</a></h2> <p>Most of the functionality described in this PEP is already implemented in the in-development version of the PEAK-Rules framework. In particular, the basic overloading and method combination framework (minus the <code class="docutils literal notranslate"><span class="pre">@overload</span></code> decorator) already exists there. The implementation of all of these features in <code class="docutils literal notranslate"><span class="pre">peak.rules.core</span></code> is 656 lines of Python at this writing.</p> <p><code class="docutils literal notranslate"><span class="pre">peak.rules.core</span></code> currently relies on the DecoratorTools and BytecodeAssembler modules, but both of these dependencies can be replaced, as DecoratorTools is used mainly for Python 2.3 compatibility and to implement structure types (which can be done with named tuples in later versions of Python). The use of BytecodeAssembler can be replaced using an “exec” or “compile” workaround, given a reasonable effort. (It would be easier to do this if the <code class="docutils literal notranslate"><span class="pre">func_closure</span></code> attribute of function objects was writable.)</p> <p>The <code class="docutils literal notranslate"><span class="pre">Interface</span></code> class has been previously prototyped, but is not included in PEAK-Rules at the present time.</p> <p>The “implicit class rule” has previously been implemented in the RuleDispatch library. However, it relies on the <code class="docutils literal notranslate"><span class="pre">__metaclass__</span></code> hook that is currently eliminated in <a class="pep reference internal" href="../pep-3115/" title="PEP 3115 – Metaclasses in Python 3000">PEP 3115</a>.</p> <p>I don’t currently know how to make <code class="docutils literal notranslate"><span class="pre">@overload</span></code> play nicely with <code class="docutils literal notranslate"><span class="pre">classmethod</span></code> and <code class="docutils literal notranslate"><span class="pre">staticmethod</span></code> in class bodies. It’s not really clear if it needs to, however.</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-3124.rst">https://github.com/python/peps/blob/main/peps/pep-3124.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-3124.rst">2025-02-01 08:59:27 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#deferred">Deferred</a></li> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#rationale-and-goals">Rationale and Goals</a></li> <li><a class="reference internal" href="#user-api">User API</a><ul> <li><a class="reference internal" href="#overloading-generic-functions">Overloading/Generic Functions</a><ul> <li><a class="reference internal" href="#overload-vs-when"><code class="docutils literal notranslate"><span class="pre">@overload</span></code> vs. <code class="docutils literal notranslate"><span class="pre">@when</span></code></a></li> </ul> </li> <li><a class="reference internal" href="#method-combination-and-overriding">Method Combination and Overriding</a><ul> <li><a class="reference internal" href="#proceeding-to-the-next-method">Proceeding to the “Next” Method</a></li> <li><a class="reference internal" href="#before-and-after-methods">“Before” and “After” Methods</a></li> <li><a class="reference internal" href="#around-methods">“Around” Methods</a></li> <li><a class="reference internal" href="#custom-combinations">Custom Combinations</a></li> </ul> </li> <li><a class="reference internal" href="#overloading-inside-classes">Overloading Inside Classes</a></li> <li><a class="reference internal" href="#interfaces-and-adaptation">Interfaces and Adaptation</a><ul> <li><a class="reference internal" href="#abstract-and-concrete-methods">Abstract and Concrete Methods</a></li> <li><a class="reference internal" href="#subclassing-and-re-assembly">Subclassing and Re-assembly</a></li> <li><a class="reference internal" href="#implementing-an-interface-in-a-class">Implementing an Interface in a Class</a></li> <li><a class="reference internal" href="#interfaces-as-type-specifiers">Interfaces as Type Specifiers</a></li> <li><a class="reference internal" href="#non-method-attributes-in-interfaces">Non-Method Attributes in Interfaces</a></li> </ul> </li> <li><a class="reference internal" href="#aspects">Aspects</a></li> </ul> </li> <li><a class="reference internal" href="#extension-api">Extension API</a></li> <li><a class="reference internal" href="#overloading-usage-patterns">Overloading Usage Patterns</a></li> <li><a class="reference internal" href="#implementation-notes">Implementation Notes</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-3124.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>