python-peps/pep-0245/index.html

619 lines
43 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 245 Python Interface Syntax | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0245/">
<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 245 Python Interface Syntax | peps.python.org'>
<meta property="og:description" content="This PEP describes a proposed syntax for creating interface objects in Python.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0245/">
<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 describes a proposed syntax for creating interface objects in Python.">
<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> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 245</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 245 Python Interface Syntax</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Michel Pelletier &lt;michel&#32;&#97;t&#32;users.sourceforge.net&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Formally declined and will not be accepted">Rejected</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">11-Jan-2001</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">2.2</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even">21-Mar-2001</dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#rejection-notice">Rejection Notice</a></li>
<li><a class="reference internal" href="#introduction">Introduction</a></li>
<li><a class="reference internal" href="#overview">Overview</a></li>
<li><a class="reference internal" href="#the-problem">The Problem</a></li>
<li><a class="reference internal" href="#overview-of-the-interface-syntax">Overview of the Interface Syntax</a></li>
<li><a class="reference internal" href="#interface-assertion">Interface Assertion</a></li>
<li><a class="reference internal" href="#formal-interface-syntax">Formal Interface Syntax</a></li>
<li><a class="reference internal" href="#classes-and-interfaces">Classes and Interfaces</a></li>
<li><a class="reference internal" href="#interface-aware-built-ins">Interface-aware built-ins</a></li>
<li><a class="reference internal" href="#backward-compatibility">Backward Compatibility</a></li>
<li><a class="reference internal" href="#summary-of-proposed-changes-to-python">Summary of Proposed Changes to Python</a></li>
<li><a class="reference internal" href="#risks">Risks</a></li>
<li><a class="reference internal" href="#open-issues">Open Issues</a><ul>
<li><a class="reference internal" href="#goals">Goals</a></li>
<li><a class="reference internal" href="#syntax">Syntax</a></li>
<li><a class="reference internal" href="#architecture">Architecture</a></li>
</ul>
</li>
<li><a class="reference internal" href="#dissenting-opinion">Dissenting Opinion</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>The no-longer-available Zope interfaces wiki page
(<code class="docutils literal notranslate"><span class="pre">https://www.zope.org/Wikis/Interfaces</span></code>) originally linked here,
containing links to further resources for this PEP,
can be <a class="reference external" href="https://web.archive.org/web/20050327013919/http://www.zope.org/Wikis/Interfaces/FrontPage">found on the Wayback Machine archive</a>.
Also, the Interface-Dev Zope mailing list on which this PEP was discussed
was shut down, but <a class="reference external" href="https://mail.zope.dev/pipermail/interface-dev/">its archives remain available</a>.</p>
</div>
<section id="rejection-notice">
<h2><a class="toc-backref" href="#rejection-notice" role="doc-backlink">Rejection Notice</a></h2>
<p>Im rejecting this PEP. Its been five years now. While at some
point I expect that Python will have interfaces, it would be naive
to expect it to resemble the syntax in this PEP. Also, <a class="pep reference internal" href="../pep-0246/" title="PEP 246 Object Adaptation">PEP 246</a> is
being rejected in favor of something completely different; interfaces
wont play a role in adaptation or whatever will replace it. GvR.</p>
</section>
<section id="introduction">
<h2><a class="toc-backref" href="#introduction" role="doc-backlink">Introduction</a></h2>
<p>This PEP describes a proposed syntax for creating interface
objects in Python.</p>
</section>
<section id="overview">
<h2><a class="toc-backref" href="#overview" role="doc-backlink">Overview</a></h2>
<p>In addition to thinking about adding a static type system to
Python, the Types-SIG was also charged to devise an interface
system for Python. In December of 1998, Jim Fulton released a
prototype interfaces system based on discussions from the SIG.
Many of the issues and background information on this discussion
and prototype can be found in the SIG archives <a class="footnote-reference brackets" href="#id5" id="id1">[1]</a>.</p>
<p>Around the end of 2000, Digital Creations began thinking about
better component model designs for Zope <a class="footnote-reference brackets" href="#id6" id="id2">[2]</a>. Zopes future
component model relies heavily on interface objects. This led to
further development of Jims “Scarecrow” interfaces prototype.
Starting with version 2.3, Zope comes with an Interface package as
standard software. Zopes Interface package is used as the
reference implementation for this PEP.</p>
<p>The syntax proposed by this PEP relies on syntax enhancements
describe in <a class="pep reference internal" href="../pep-0232/" title="PEP 232 Function Attributes">PEP 232</a> and describes an underlying framework
which <a class="pep reference internal" href="../pep-0233/" title="PEP 233 Python Online Help">PEP 233</a> could be based upon. There is some work being
done with regard to interface objects and Proxy objects, so for
those optional parts of this PEP you may want to see <a class="footnote-reference brackets" href="#id7" id="id3">[3]</a>.</p>
</section>
<section id="the-problem">
<h2><a class="toc-backref" href="#the-problem" role="doc-backlink">The Problem</a></h2>
<p>Interfaces are important because they solve a number of problems
that arise while developing software:</p>
<ul class="simple">
<li>There are many implied interfaces in Python, commonly referred
to as “protocols”. Currently determining those protocols is
based on implementation introspection, but often that also
fails. For example, defining <code class="docutils literal notranslate"><span class="pre">__getitem__</span></code> implies both a
sequence and a mapping (the former with sequential, integer
keys). There is no way for the developer to be explicit about
which protocols the object intends to implement.</li>
<li>Python is limited, from the developers point of view, by the
split between types and classes. When types are expected, the
consumer uses code like type(foo) == type(“”) to determine if
foo is a string. When instances of classes are expected, the
consumer uses isinstance(foo, MyString) to determine if foo
is an instance of the MyString class. There is no unified
model for determining if an object can be used in a certain,
valid way.</li>
<li>Pythons dynamic typing is very flexible and powerful, but it
does not have the advantage of static typed languages that
provide type checking. Static typed languages provide you with
much more type safety, but are often overly verbose because
objects can only be generalized by common subclassing and used
specifically with casting (for example, in Java).</li>
</ul>
<p>There are also a number of documentation problems that interfaces
try to solve.</p>
<ul class="simple">
<li>Developers waste a lot of time looking at the source code of
your system to figure out how objects work.</li>
<li>Developers who are new to your system may misunderstand how your
objects work, causing, and possibly propagating, usage errors.</li>
<li>Because a lack of interfaces means usage is inferred from the
source, developers may end up using methods and attributes that
are meant for “internal use only”.</li>
<li>Code inspection can be hard, and very discouraging to novice
programmers trying to properly understand code written by gurus.</li>
<li>A lot of time is wasted when many people try very hard to
understand obscurity (like undocumented software). Effort spend
up front documenting interfaces will save much of this time in
the end.</li>
</ul>
<p>Interfaces try to solve these problems by providing a way for you
to specify a contractual obligation for your object, documentation
on how to use an object, and a built-in mechanism for discovering
the contract and the documentation.</p>
<p>Python has very useful introspection features. It is well known
that this makes exploring concepts in the interactive interpreter
easier, because Python gives you the ability to look at all kinds
of information about the objects: the type, doc strings, instance
dictionaries, base classes, unbound methods and more.</p>
<p>Many of these features are oriented toward introspecting, using
and changing the implementation of software, and one of them (“doc
strings”) is oriented toward providing documentation. This
proposal describes an extension to this natural introspection
framework that describes an objects interface.</p>
</section>
<section id="overview-of-the-interface-syntax">
<h2><a class="toc-backref" href="#overview-of-the-interface-syntax" role="doc-backlink">Overview of the Interface Syntax</a></h2>
<p>For the most part, the syntax of interfaces is very much like the
syntax of classes, but future needs, or needs brought up in
discussion, may define new possibilities for interface syntax.</p>
<p>A formal BNF description of the syntax is givena later in the PEP,
for the purposes of illustration, here is an example of two
different interfaces created with the proposed syntax:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">interface</span> <span class="n">CountFishInterface</span><span class="p">:</span>
<span class="s2">&quot;Fish counting interface&quot;</span>
<span class="k">def</span> <span class="nf">oneFish</span><span class="p">():</span>
<span class="s2">&quot;Increments the fish count by one&quot;</span>
<span class="k">def</span> <span class="nf">twoFish</span><span class="p">():</span>
<span class="s2">&quot;Increments the fish count by two&quot;</span>
<span class="k">def</span> <span class="nf">getFishCount</span><span class="p">():</span>
<span class="s2">&quot;Returns the fish count&quot;</span>
<span class="n">interface</span> <span class="n">ColorFishInterface</span><span class="p">:</span>
<span class="s2">&quot;Fish coloring interface&quot;</span>
<span class="k">def</span> <span class="nf">redFish</span><span class="p">():</span>
<span class="s2">&quot;Sets the current fish color to red&quot;</span>
<span class="k">def</span> <span class="nf">blueFish</span><span class="p">():</span>
<span class="s2">&quot;Sets the current fish color to blue&quot;</span>
<span class="k">def</span> <span class="nf">getFishColor</span><span class="p">():</span>
<span class="s2">&quot;This returns the current fish color&quot;</span>
</pre></div>
</div>
<p>This code, when evaluated, will create two interfaces called
<code class="docutils literal notranslate"><span class="pre">CountFishInterface</span></code> and <code class="docutils literal notranslate"><span class="pre">ColorFishInterface</span></code>. These interfaces
are defined by the <code class="docutils literal notranslate"><span class="pre">interface</span></code> statement.</p>
<p>The prose documentation for the interfaces and their methods come
from doc strings. The method signature information comes from the
signatures of the <code class="docutils literal notranslate"><span class="pre">def</span></code> statements. Notice how there is no body
for the def statements. The interface does not implement a
service to anything; it merely describes one. Documentation
strings on interfaces and interface methods are mandatory, a
pass statement cannot be provided. The interface equivalent of
a pass statement is an empty doc string.</p>
<p>You can also create interfaces that “extend” other interfaces.
Here, you can see a new type of Interface that extends the
CountFishInterface and ColorFishInterface:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">interface</span> <span class="n">FishMarketInterface</span><span class="p">(</span><span class="n">CountFishInterface</span><span class="p">,</span> <span class="n">ColorFishInterface</span><span class="p">):</span>
<span class="s2">&quot;This is the documentation for the FishMarketInterface&quot;</span>
<span class="k">def</span> <span class="nf">getFishMonger</span><span class="p">():</span>
<span class="s2">&quot;Returns the fish monger you can interact with&quot;</span>
<span class="k">def</span> <span class="nf">hireNewFishMonger</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
<span class="s2">&quot;Hire a new fish monger&quot;</span>
<span class="k">def</span> <span class="nf">buySomeFish</span><span class="p">(</span><span class="n">quantity</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
<span class="s2">&quot;Buy some fish at the market&quot;</span>
</pre></div>
</div>
<p>The FishMarketInterface extends upon the CountFishInterface and
ColorfishInterface.</p>
</section>
<section id="interface-assertion">
<h2><a class="toc-backref" href="#interface-assertion" role="doc-backlink">Interface Assertion</a></h2>
<p>The next step is to put classes and interfaces together by
creating a concrete Python class that asserts that it implements
an interface. Here is an example FishMarket component that might
do this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">FishError</span><span class="p">(</span><span class="n">Error</span><span class="p">):</span>
<span class="k">pass</span>
<span class="k">class</span> <span class="nc">FishMarket</span> <span class="n">implements</span> <span class="n">FishMarketInterface</span><span class="p">:</span>
<span class="n">number</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">color</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">monger_name</span> <span class="o">=</span> <span class="s1">&#39;Crusty Barnacles&#39;</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">number</span><span class="p">,</span> <span class="n">color</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">number</span> <span class="o">=</span> <span class="n">number</span>
<span class="bp">self</span><span class="o">.</span><span class="n">color</span> <span class="o">=</span> <span class="n">color</span>
<span class="k">def</span> <span class="nf">oneFish</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">number</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">def</span> <span class="nf">twoFish</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">number</span> <span class="o">+=</span> <span class="mi">2</span>
<span class="k">def</span> <span class="nf">redFish</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">color</span> <span class="o">=</span> <span class="s1">&#39;red&#39;</span>
<span class="k">def</span> <span class="nf">blueFish</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">color</span> <span class="o">=</span> <span class="s1">&#39;blue&#39;</span>
<span class="k">def</span> <span class="nf">getFishCount</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">number</span>
<span class="k">def</span> <span class="nf">getFishColor</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">color</span>
<span class="k">def</span> <span class="nf">getFishMonger</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">monger_name</span>
<span class="k">def</span> <span class="nf">hireNewFishMonger</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">monger_name</span> <span class="o">=</span> <span class="n">name</span>
<span class="k">def</span> <span class="nf">buySomeFish</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">quantity</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
<span class="k">if</span> <span class="n">quantity</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">count</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">FishError</span><span class="p">(</span><span class="s2">&quot;There&#39;s not enough fish&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">count</span> <span class="o">-=</span> <span class="n">quantity</span>
<span class="k">return</span> <span class="n">quantity</span>
</pre></div>
</div>
<p>This new class, FishMarket defines a concrete class which
implements the FishMarketInterface. The object following the
<code class="docutils literal notranslate"><span class="pre">implements</span></code> statement is called an “interface assertion”. An
interface assertion can be either an interface object, or tuple of
interface assertions.</p>
<p>The interface assertion provided in a <code class="docutils literal notranslate"><span class="pre">class</span></code> statement like this
is stored in the classs <code class="docutils literal notranslate"><span class="pre">__implements__</span></code> class attribute. After
interpreting the above example, you would have a class statement
that can be examined like this with an implements built-in
function:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">FishMarket</span>
<span class="go">&lt;class FishMarket at 8140f50&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">FishMarket</span><span class="o">.</span><span class="n">__implements__</span>
<span class="go">(&lt;Interface FishMarketInterface at 81006f0&gt;,)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span> <span class="o">=</span> <span class="n">FishMarket</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="s1">&#39;red&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">implements</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">FishMarketInterface</span><span class="p">)</span>
<span class="go">1</span>
<span class="gp">&gt;&gt;&gt;</span>
</pre></div>
</div>
<p>A class can realize more than one interface. For example, say you
had an interface called <code class="docutils literal notranslate"><span class="pre">ItemInterface</span></code> that described how an
object worked as an item in a container object. If you wanted to
assert that FishMarket instances realized the ItemInterface
interface as well as the FishMarketInterface, you can provide an
interface assertion that contained a tuple of interface objects to
the FishMarket class:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">FishMarket</span> <span class="n">implements</span> <span class="n">FishMarketInterface</span><span class="p">,</span> <span class="n">ItemInterface</span><span class="p">:</span>
<span class="c1"># ...</span>
</pre></div>
</div>
<p>Interface assertions can also be used if you want to assert that
one class implements an interface, and all of the interfaces that
another class implements:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyFishMarket</span> <span class="n">implements</span> <span class="n">FishMarketInterface</span><span class="p">,</span> <span class="n">ItemInterface</span><span class="p">:</span>
<span class="c1"># ...</span>
<span class="k">class</span> <span class="nc">YourFishMarket</span> <span class="n">implements</span> <span class="n">FooInterface</span><span class="p">,</span> <span class="n">MyFishMarket</span><span class="o">.</span><span class="n">__implements__</span><span class="p">:</span>
<span class="c1"># ...</span>
</pre></div>
</div>
<p>This new class YourFishMarket, asserts that it implements the
FooInterface, as well as the interfaces implemented by the
MyFishMarket class.</p>
<p>Its worth going into a little bit more detail about interface
assertions. An interface assertion is either an interface object,
or a tuple of interface assertions. For example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">FooInterface</span>
<span class="n">FooInterface</span><span class="p">,</span> <span class="p">(</span><span class="n">BarInterface</span><span class="p">,</span> <span class="n">BobInterface</span><span class="p">)</span>
<span class="n">FooInterface</span><span class="p">,</span> <span class="p">(</span><span class="n">BarInterface</span><span class="p">,</span> <span class="p">(</span><span class="n">BobInterface</span><span class="p">,</span> <span class="n">MyClass</span><span class="o">.</span><span class="n">__implements__</span><span class="p">))</span>
</pre></div>
</div>
<p>Are all valid interface assertions. When two interfaces define
the same attributes, the order in which information is preferred
in the assertion is from top-to-bottom, left-to-right.</p>
<p>There are other interface proposals that, in the need for
simplicity, have combined the notion of class and interface to
provide simple interface enforcement. Interface objects have a
<code class="docutils literal notranslate"><span class="pre">deferred</span></code> method that returns a deferred class that implements
this behavior:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">FM</span> <span class="o">=</span> <span class="n">FishMarketInterface</span><span class="o">.</span><span class="n">deferred</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">MyFM</span><span class="p">(</span><span class="n">FM</span><span class="p">):</span> <span class="k">pass</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span> <span class="o">=</span> <span class="n">MyFM</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">getFishMonger</span><span class="p">()</span>
<span class="go">Traceback (innermost last):</span>
File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">?</span>
<span class="gr">Interface.Exceptions.BrokenImplementation</span><span class="w">:</span>
<span class="x">An object has failed to implement interface FishMarketInterface</span>
<span class="x"> The getFishMonger attribute was not provided.</span>
<span class="gp">&gt;&gt;&gt;</span>
</pre></div>
</div>
<p>This provides for a bit of passive interface enforcement by
telling you what you forgot to do to implement that interface.</p>
</section>
<section id="formal-interface-syntax">
<h2><a class="toc-backref" href="#formal-interface-syntax" role="doc-backlink">Formal Interface Syntax</a></h2>
<p>Python syntax is defined in a modified BNF grammar notation
described in the Python Reference Manual <a class="footnote-reference brackets" href="#id8" id="id4">[4]</a>. This section
describes the proposed interface syntax using this grammar:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">interfacedef</span><span class="p">:</span> <span class="s2">&quot;interface&quot;</span> <span class="n">interfacename</span> <span class="p">[</span><span class="n">extends</span><span class="p">]</span> <span class="s2">&quot;:&quot;</span> <span class="n">suite</span>
<span class="n">extends</span><span class="p">:</span> <span class="s2">&quot;(&quot;</span> <span class="p">[</span><span class="n">expression_list</span><span class="p">]</span> <span class="s2">&quot;)&quot;</span>
<span class="n">interfacename</span><span class="p">:</span> <span class="n">identifier</span>
</pre></div>
</div>
<p>An interface definition is an executable statement. It first
evaluates the extends list, if present. Each item in the extends
list should evaluate to an interface object.</p>
<p>The interfaces suite is then executed in a new execution frame
(see the Python Reference Manual, section 4.1), using a newly
created local namespace and the original global namespace. When
the interfaces suite finishes execution, its execution frame is
discarded but its local namespace is saved as interface elements.
An interface object is then created using the extends list for the
base interfaces and the saved interface elements. The interface
name is bound to this interface object in the original local
namespace.</p>
<p>This PEP also proposes an extension to Pythons class statement:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">classdef</span><span class="p">:</span> <span class="s2">&quot;class&quot;</span> <span class="n">classname</span> <span class="p">[</span><span class="n">inheritance</span><span class="p">]</span> <span class="p">[</span><span class="n">implements</span><span class="p">]</span> <span class="s2">&quot;:&quot;</span> <span class="n">suite</span>
<span class="n">implements</span><span class="p">:</span> <span class="s2">&quot;implements&quot;</span> <span class="n">implist</span>
<span class="n">implist</span><span class="p">:</span> <span class="n">expression</span><span class="o">-</span><span class="nb">list</span>
<span class="n">classname</span><span class="p">,</span>
<span class="n">inheritance</span><span class="p">,</span>
<span class="n">suite</span><span class="p">,</span>
<span class="n">expression</span><span class="o">-</span><span class="nb">list</span><span class="p">:</span> <span class="n">see</span> <span class="n">the</span> <span class="n">Python</span> <span class="n">Reference</span> <span class="n">Manual</span>
</pre></div>
</div>
<p>Before a class suite is executed, the inheritance and
implements statements are evaluated, if present. The
inheritance behavior is unchanged as defined in Section 7.6 of
the Language Reference.</p>
<p>The implements, if present, is evaluated after inheritance.
This must evaluate to an interface specification, which is either
an interface, or a tuple of interface specifications. If a valid
interface specification is present, the assertion is assigned to
the class objects __implements__ attribute, as a tuple.</p>
<p>This PEP does not propose any changes to the syntax of function
definitions or assignments.</p>
</section>
<section id="classes-and-interfaces">
<h2><a class="toc-backref" href="#classes-and-interfaces" role="doc-backlink">Classes and Interfaces</a></h2>
<p>The example interfaces above do not describe any kind of behavior
for their methods, they just describe an interface that a typical
FishMarket object would realize.</p>
<p>You may notice a similarity between interfaces extending from
other interfaces and classes sub-classing from other classes.
This is a similar concept. However it is important to note that
interfaces extend interfaces and classes subclass classes. You
cannot extend a class or subclass an interface. Classes and
interfaces are separate.</p>
<p>The purpose of a class is to share the implementation of how an
object works. The purpose of an interface is to document how to
work with an object, not how the object is implemented. It is
possible to have several different classes with very different
implementations realize the same interface.</p>
<p>Its also possible to implement one interface with many classes
that mix in pieces the functionality of the interface or,
conversely, its possible to have one class implement many
interfaces. Because of this, interfaces and classes should not be
confused or intermingled.</p>
</section>
<section id="interface-aware-built-ins">
<h2><a class="toc-backref" href="#interface-aware-built-ins" role="doc-backlink">Interface-aware built-ins</a></h2>
<p>A useful extension to Pythons list of built-in functions in the
light of interface objects would be <code class="docutils literal notranslate"><span class="pre">implements()</span></code>. This builtin
would expect two arguments, an object and an interface, and return
a true value if the object implements the interface, false
otherwise. For example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">interface</span> <span class="n">FooInterface</span><span class="p">:</span> <span class="k">pass</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">Foo</span> <span class="n">implements</span> <span class="n">FooInterface</span><span class="p">:</span> <span class="k">pass</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span> <span class="o">=</span> <span class="n">Foo</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">implements</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">FooInterface</span><span class="p">)</span>
<span class="go">1</span>
</pre></div>
</div>
<p>Currently, this functionality exists in the reference
implementation as functions in the <code class="docutils literal notranslate"><span class="pre">Interface</span></code> package, requiring
an “import Interface” to use it. Its existence as a built-in
would be purely for a convenience, and not necessary for using
interfaces, and analogous to <code class="docutils literal notranslate"><span class="pre">isinstance()</span></code> for classes.</p>
</section>
<section id="backward-compatibility">
<h2><a class="toc-backref" href="#backward-compatibility" role="doc-backlink">Backward Compatibility</a></h2>
<p>The proposed interface model does not introduce any backward
compatibility issues in Python. The proposed syntax, however,
does.</p>
<p>Any existing code that uses <code class="docutils literal notranslate"><span class="pre">interface</span></code> as an identifier will
break. There may be other kinds of backwards incompatibility that
defining <code class="docutils literal notranslate"><span class="pre">interface</span></code> as a new keyword will introduce. This
extension to Pythons syntax does not change any existing syntax
in any backward incompatible way.</p>
<p>The new <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span></code> Python syntax (<a class="pep reference internal" href="../pep-0236/" title="PEP 236 Back to the __future__">PEP 236</a>), and the new warning
framework (<a class="pep reference internal" href="../pep-0230/" title="PEP 230 Warning Framework">PEP 230</a>) is ideal for resolving this backward
incompatibility. To use interface syntax now, a developer could
use the statement:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">interfaces</span>
</pre></div>
</div>
<p>In addition, any code that uses the keyword <code class="docutils literal notranslate"><span class="pre">interface</span></code> as an
identifier will be issued a warning from Python. After the
appropriate period of time, the interface syntax would become
standard, the above import statement would do nothing, and any
identifiers named <code class="docutils literal notranslate"><span class="pre">interface</span></code> would raise an exception. This
period of time is proposed to be 24 months.</p>
</section>
<section id="summary-of-proposed-changes-to-python">
<h2><a class="toc-backref" href="#summary-of-proposed-changes-to-python" role="doc-backlink">Summary of Proposed Changes to Python</a></h2>
<p>Adding new <code class="docutils literal notranslate"><span class="pre">interface</span></code> keyword and extending class syntax with
<code class="docutils literal notranslate"><span class="pre">implements</span></code>.</p>
<p>Extending class interface to include <code class="docutils literal notranslate"><span class="pre">__implements__</span></code>.</p>
<p>Add implements(obj, interface) built-in.</p>
</section>
<section id="risks">
<h2><a class="toc-backref" href="#risks" role="doc-backlink">Risks</a></h2>
<p>This PEP proposes adding one new keyword to the Python language,
<code class="docutils literal notranslate"><span class="pre">interface</span></code>. This will break code.</p>
</section>
<section id="open-issues">
<h2><a class="toc-backref" href="#open-issues" role="doc-backlink">Open Issues</a></h2>
<section id="goals">
<h3><a class="toc-backref" href="#goals" role="doc-backlink">Goals</a></h3>
</section>
<section id="syntax">
<h3><a class="toc-backref" href="#syntax" role="doc-backlink">Syntax</a></h3>
</section>
<section id="architecture">
<h3><a class="toc-backref" href="#architecture" role="doc-backlink">Architecture</a></h3>
</section>
</section>
<section id="dissenting-opinion">
<h2><a class="toc-backref" href="#dissenting-opinion" role="doc-backlink">Dissenting Opinion</a></h2>
<p>This PEP has not yet been discussed on python-dev.</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="id5" role="doc-footnote">
<dt class="label" id="id5">[<a href="#id1">1</a>]</dt>
<dd><a class="reference external" href="https://mail.python.org/pipermail/types-sig/1998-December/date.html">https://mail.python.org/pipermail/types-sig/1998-December/date.html</a></aside>
<aside class="footnote brackets" id="id6" role="doc-footnote">
<dt class="label" id="id6">[<a href="#id2">2</a>]</dt>
<dd><a class="reference external" href="http://www.zope.org">http://www.zope.org</a></aside>
<aside class="footnote brackets" id="id7" role="doc-footnote">
<dt class="label" id="id7">[<a href="#id3">3</a>]</dt>
<dd><a class="reference external" href="http://www.lemburg.com/files/python/mxProxy.html">http://www.lemburg.com/files/python/mxProxy.html</a></aside>
<aside class="footnote brackets" id="id8" role="doc-footnote">
<dt class="label" id="id8">[<a href="#id4">4</a>]</dt>
<dd>Python Reference Manual
<a class="reference external" href="http://docs.python.org/reference/">http://docs.python.org/reference/</a></aside>
</aside>
</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-0245.rst">https://github.com/python/peps/blob/main/peps/pep-0245.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0245.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="#rejection-notice">Rejection Notice</a></li>
<li><a class="reference internal" href="#introduction">Introduction</a></li>
<li><a class="reference internal" href="#overview">Overview</a></li>
<li><a class="reference internal" href="#the-problem">The Problem</a></li>
<li><a class="reference internal" href="#overview-of-the-interface-syntax">Overview of the Interface Syntax</a></li>
<li><a class="reference internal" href="#interface-assertion">Interface Assertion</a></li>
<li><a class="reference internal" href="#formal-interface-syntax">Formal Interface Syntax</a></li>
<li><a class="reference internal" href="#classes-and-interfaces">Classes and Interfaces</a></li>
<li><a class="reference internal" href="#interface-aware-built-ins">Interface-aware built-ins</a></li>
<li><a class="reference internal" href="#backward-compatibility">Backward Compatibility</a></li>
<li><a class="reference internal" href="#summary-of-proposed-changes-to-python">Summary of Proposed Changes to Python</a></li>
<li><a class="reference internal" href="#risks">Risks</a></li>
<li><a class="reference internal" href="#open-issues">Open Issues</a><ul>
<li><a class="reference internal" href="#goals">Goals</a></li>
<li><a class="reference internal" href="#syntax">Syntax</a></li>
<li><a class="reference internal" href="#architecture">Architecture</a></li>
</ul>
</li>
<li><a class="reference internal" href="#dissenting-opinion">Dissenting Opinion</a></li>
<li><a class="reference internal" href="#references">References</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-0245.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>