352 lines
24 KiB
HTML
352 lines
24 KiB
HTML
|
|
|||
|
<!DOCTYPE html>
|
|||
|
<html lang="en">
|
|||
|
<head>
|
|||
|
<meta charset="utf-8">
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
<meta name="color-scheme" content="light dark">
|
|||
|
<title>PEP 213 – Attribute Access Handlers | peps.python.org</title>
|
|||
|
<link rel="shortcut icon" href="../_static/py.png">
|
|||
|
<link rel="canonical" href="https://peps.python.org/pep-0213/">
|
|||
|
<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 213 – Attribute Access Handlers | peps.python.org'>
|
|||
|
<meta property="og:description" content="It is possible (and even relatively common) in Python code and in extension modules to “trap” when an instance’s client code attempts to set an attribute and execute code instead. In other words, it is possible to allow users to use attribute assignment...">
|
|||
|
<meta property="og:type" content="website">
|
|||
|
<meta property="og:url" content="https://peps.python.org/pep-0213/">
|
|||
|
<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="It is possible (and even relatively common) in Python code and in extension modules to “trap” when an instance’s client code attempts to set an attribute and execute code instead. In other words, it is possible to allow users to use attribute assignment...">
|
|||
|
<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 213</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 213 – Attribute Access Handlers</h1>
|
|||
|
<dl class="rfc2822 field-list simple">
|
|||
|
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
|||
|
<dd class="field-odd">Paul Prescod <paul at prescod.net></dd>
|
|||
|
<dt class="field-even">Status<span class="colon">:</span></dt>
|
|||
|
<dd class="field-even"><abbr title="Inactive draft that may be taken up again at a later time">Deferred</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">21-Jul-2000</dd>
|
|||
|
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
|
|||
|
<dd class="field-odd">2.1</dd>
|
|||
|
<dt class="field-even">Post-History<span class="colon">:</span></dt>
|
|||
|
<dd class="field-even"><p></p></dd>
|
|||
|
</dl>
|
|||
|
<hr class="docutils" />
|
|||
|
<section id="contents">
|
|||
|
<details><summary>Table of Contents</summary><ul class="simple">
|
|||
|
<li><a class="reference internal" href="#introduction">Introduction</a></li>
|
|||
|
<li><a class="reference internal" href="#justification">Justification</a><ul>
|
|||
|
<li><a class="reference internal" href="#scenario-1">Scenario 1</a></li>
|
|||
|
<li><a class="reference internal" href="#scenario-2">Scenario 2</a></li>
|
|||
|
<li><a class="reference internal" href="#scenario-3">Scenario 3</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#current-solution">Current Solution</a></li>
|
|||
|
<li><a class="reference internal" href="#proposed-syntax">Proposed Syntax</a></li>
|
|||
|
<li><a class="reference internal" href="#semantics">Semantics</a></li>
|
|||
|
<li><a class="reference internal" href="#proposed-implementation">Proposed Implementation</a></li>
|
|||
|
<li><a class="reference internal" href="#caveats">Caveats</a></li>
|
|||
|
<li><a class="reference internal" href="#note">Note</a></li>
|
|||
|
</ul>
|
|||
|
</details></section>
|
|||
|
<section id="introduction">
|
|||
|
<h2><a class="toc-backref" href="#introduction" role="doc-backlink">Introduction</a></h2>
|
|||
|
<p>It is possible (and even relatively common) in Python code and
|
|||
|
in extension modules to “trap” when an instance’s client code
|
|||
|
attempts to set an attribute and execute code instead. In other
|
|||
|
words, it is possible to allow users to use attribute assignment/
|
|||
|
retrieval/deletion syntax even though the underlying implementation
|
|||
|
is doing some computation rather than directly modifying a
|
|||
|
binding.</p>
|
|||
|
<p>This PEP describes a feature that makes it easier, more efficient
|
|||
|
and safer to implement these handlers for Python instances.</p>
|
|||
|
</section>
|
|||
|
<section id="justification">
|
|||
|
<h2><a class="toc-backref" href="#justification" role="doc-backlink">Justification</a></h2>
|
|||
|
<section id="scenario-1">
|
|||
|
<h3><a class="toc-backref" href="#scenario-1" role="doc-backlink">Scenario 1</a></h3>
|
|||
|
<p>You have a deployed class that works on an attribute named
|
|||
|
“stdout”. After a while, you think it would be better to
|
|||
|
check that stdout is really an object with a “write” method
|
|||
|
at the moment of assignment. Rather than change to a
|
|||
|
setstdout method (which would be incompatible with deployed
|
|||
|
code) you would rather trap the assignment and check the
|
|||
|
object’s type.</p>
|
|||
|
</section>
|
|||
|
<section id="scenario-2">
|
|||
|
<h3><a class="toc-backref" href="#scenario-2" role="doc-backlink">Scenario 2</a></h3>
|
|||
|
<p>You want to be as compatible as possible with an object
|
|||
|
model that has a concept of attribute assignment. It could
|
|||
|
be the W3C Document Object Model or a particular COM
|
|||
|
interface (e.g. the PowerPoint interface). In that case
|
|||
|
you may well want attributes in the model to show up as
|
|||
|
attributes in the Python interface, even though the
|
|||
|
underlying implementation may not use attributes at all.</p>
|
|||
|
</section>
|
|||
|
<section id="scenario-3">
|
|||
|
<h3><a class="toc-backref" href="#scenario-3" role="doc-backlink">Scenario 3</a></h3>
|
|||
|
<p>A user wants to make an attribute read-only.</p>
|
|||
|
<p>In short, this feature allows programmers to separate the
|
|||
|
interface of their module from the underlying implementation
|
|||
|
for whatever purpose. Again, this is not a new feature but
|
|||
|
merely a new syntax for an existing convention.</p>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<section id="current-solution">
|
|||
|
<h2><a class="toc-backref" href="#current-solution" role="doc-backlink">Current Solution</a></h2>
|
|||
|
<p>To make some attributes read-only:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">foo</span><span class="p">:</span>
|
|||
|
<span class="k">def</span> <span class="fm">__setattr__</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="n">val</span> <span class="p">):</span>
|
|||
|
<span class="k">if</span> <span class="n">name</span><span class="o">==</span><span class="s2">"readonlyattr"</span><span class="p">:</span>
|
|||
|
<span class="k">raise</span> <span class="ne">TypeError</span>
|
|||
|
<span class="k">elif</span> <span class="n">name</span><span class="o">==</span><span class="s2">"readonlyattr2"</span><span class="p">:</span>
|
|||
|
<span class="k">raise</span> <span class="ne">TypeError</span>
|
|||
|
<span class="o">...</span>
|
|||
|
<span class="k">else</span><span class="p">:</span>
|
|||
|
<span class="bp">self</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="s2">"name"</span><span class="p">]</span><span class="o">=</span><span class="n">val</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>This has the following problems:</p>
|
|||
|
<ol class="arabic simple">
|
|||
|
<li>The creator of the method must be intimately aware of whether
|
|||
|
somewhere else in the class hierarchy <code class="docutils literal notranslate"><span class="pre">__setattr__</span></code> has also been
|
|||
|
trapped for any particular purpose. If so, she must specifically
|
|||
|
call that method rather than assigning to the dictionary. There
|
|||
|
are many different reasons to overload <code class="docutils literal notranslate"><span class="pre">__setattr__</span></code> so there is a
|
|||
|
decent potential for clashes. For instance object database
|
|||
|
implementations often overload setattr for an entirely unrelated
|
|||
|
purpose.</li>
|
|||
|
<li>The string-based switch statement forces all attribute handlers
|
|||
|
to be specified in one place in the code. They may then dispatch
|
|||
|
to task-specific methods (for modularity) but this could cause
|
|||
|
performance problems.</li>
|
|||
|
<li>Logic for the setting, getting and deleting must live in
|
|||
|
<code class="docutils literal notranslate"><span class="pre">__getattr__</span></code>, <code class="docutils literal notranslate"><span class="pre">__setattr__</span></code> and <code class="docutils literal notranslate"><span class="pre">__delattr__</span></code>. Once again, this can
|
|||
|
be mitigated through an extra level of method call but this is
|
|||
|
inefficient.</li>
|
|||
|
</ol>
|
|||
|
</section>
|
|||
|
<section id="proposed-syntax">
|
|||
|
<h2><a class="toc-backref" href="#proposed-syntax" role="doc-backlink">Proposed Syntax</a></h2>
|
|||
|
<p>Special methods should declare themselves with declarations of the
|
|||
|
following form:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">x</span><span class="p">:</span>
|
|||
|
<span class="k">def</span> <span class="nf">__attr_XXX__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">op</span><span class="p">,</span> <span class="n">val</span> <span class="p">):</span>
|
|||
|
<span class="k">if</span> <span class="n">op</span><span class="o">==</span><span class="s2">"get"</span><span class="p">:</span>
|
|||
|
<span class="k">return</span> <span class="n">someComputedValue</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">internal</span><span class="p">)</span>
|
|||
|
<span class="k">elif</span> <span class="n">op</span><span class="o">==</span><span class="s2">"set"</span><span class="p">:</span>
|
|||
|
<span class="bp">self</span><span class="o">.</span><span class="n">internal</span><span class="o">=</span><span class="n">someComputedValue</span><span class="p">(</span><span class="n">val</span><span class="p">)</span>
|
|||
|
<span class="k">elif</span> <span class="n">op</span><span class="o">==</span><span class="s2">"del"</span><span class="p">:</span>
|
|||
|
<span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">internal</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>Client code looks like this:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">fooval</span><span class="o">=</span><span class="n">x</span><span class="o">.</span><span class="n">foo</span>
|
|||
|
<span class="n">x</span><span class="o">.</span><span class="n">foo</span><span class="o">=</span><span class="n">fooval</span><span class="o">+</span><span class="mi">5</span>
|
|||
|
<span class="k">del</span> <span class="n">x</span><span class="o">.</span><span class="n">foo</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
<section id="semantics">
|
|||
|
<h2><a class="toc-backref" href="#semantics" role="doc-backlink">Semantics</a></h2>
|
|||
|
<p>Attribute references of all three kinds should call the method.
|
|||
|
The op parameter can be “get”/”set”/”del”. Of course this string
|
|||
|
will be interned so the actual checks for the string will be
|
|||
|
very fast.</p>
|
|||
|
<p>It is disallowed to actually have an attribute named XXX in the
|
|||
|
same instance as a method named __attr_XXX__.</p>
|
|||
|
<p>An implementation of __attr_XXX__ takes precedence over an
|
|||
|
implementation of <code class="docutils literal notranslate"><span class="pre">__getattr__</span></code> based on the principle that
|
|||
|
<code class="docutils literal notranslate"><span class="pre">__getattr__</span></code> is supposed to be invoked only after finding an
|
|||
|
appropriate attribute has failed.</p>
|
|||
|
<p>An implementation of __attr_XXX__ takes precedence over an
|
|||
|
implementation of <code class="docutils literal notranslate"><span class="pre">__setattr__</span></code> in order to be consistent. The
|
|||
|
opposite choice seems fairly feasible also, however. The same
|
|||
|
goes for __del_y__.</p>
|
|||
|
</section>
|
|||
|
<section id="proposed-implementation">
|
|||
|
<h2><a class="toc-backref" href="#proposed-implementation" role="doc-backlink">Proposed Implementation</a></h2>
|
|||
|
<p>There is a new object type called an attribute access handler.
|
|||
|
Objects of this type have the following attributes:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">name</span> <span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">g</span><span class="o">.</span> <span class="n">XXX</span><span class="p">,</span> <span class="ow">not</span> <span class="n">__attr__XXX__</span><span class="p">)</span>
|
|||
|
<span class="n">method</span> <span class="p">(</span><span class="n">pointer</span> <span class="n">to</span> <span class="n">a</span> <span class="n">method</span> <span class="nb">object</span><span class="p">)</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>In PyClass_New, methods of the appropriate form will be detected and
|
|||
|
converted into objects (just like unbound method objects). These are
|
|||
|
stored in the class <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> under the name XXX. The original method
|
|||
|
is stored as an unbound method under its original name.</p>
|
|||
|
<p>If there are any attribute access handlers in an instance at all,
|
|||
|
a flag is set. Let’s call it “I_have_computed_attributes” for
|
|||
|
now. Derived classes inherit the flag from base classes. Instances
|
|||
|
inherit the flag from classes.</p>
|
|||
|
<p>A get proceeds as usual until just before the object is returned.
|
|||
|
In addition to the current check whether the returned object is a
|
|||
|
method it would also check whether a returned object is an access
|
|||
|
handler. If so, it would invoke the getter method and return
|
|||
|
the value. To remove an attribute access handler you could directly
|
|||
|
fiddle with the dictionary.</p>
|
|||
|
<p>A set proceeds by checking the “I_have_computed_attributes” flag. If
|
|||
|
it is not set, everything proceeds as it does today. If it is set
|
|||
|
then we must do a dictionary get on the requested object name. If it
|
|||
|
returns an attribute access handler then we call the setter function
|
|||
|
with the value. If it returns any other object then we discard the
|
|||
|
result and continue as we do today. Note that having an attribute
|
|||
|
access handler will mildly affect attribute “setting” performance for
|
|||
|
all sets on a particular instance, but no more so than today, using
|
|||
|
<code class="docutils literal notranslate"><span class="pre">__setattr__</span></code>. Gets are more efficient than they are today with
|
|||
|
<code class="docutils literal notranslate"><span class="pre">__getattr__</span></code>.</p>
|
|||
|
<p>The I_have_computed_attributes flag is intended to eliminate the
|
|||
|
performance degradation of an extra “get” per “set” for objects not
|
|||
|
using this feature. Checking this flag should have minuscule
|
|||
|
performance implications for all objects.</p>
|
|||
|
<p>The implementation of delete is analogous to the implementation
|
|||
|
of set.</p>
|
|||
|
</section>
|
|||
|
<section id="caveats">
|
|||
|
<h2><a class="toc-backref" href="#caveats" role="doc-backlink">Caveats</a></h2>
|
|||
|
<ol class="arabic">
|
|||
|
<li>You might note that I have not proposed any logic to keep
|
|||
|
the I_have_computed_attributes flag up to date as attributes
|
|||
|
are added and removed from the instance’s dictionary. This is
|
|||
|
consistent with current Python. If you add a <code class="docutils literal notranslate"><span class="pre">__setattr__</span></code> method
|
|||
|
to an object after it is in use, that method will not behave as
|
|||
|
it would if it were available at “compile” time. The dynamism is
|
|||
|
arguably not worth the extra implementation effort. This snippet
|
|||
|
demonstrates the current behavior:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">def</span> <span class="nf">prn</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">):</span><span class="nb">print</span> <span class="n">args</span>
|
|||
|
<span class="gp">>>> </span><span class="k">class</span> <span class="nc">a</span><span class="p">:</span>
|
|||
|
|
|||
|
<span class="go">... __setattr__=prn</span>
|
|||
|
<span class="gp">>>> </span><span class="n">a</span><span class="p">()</span><span class="o">.</span><span class="n">foo</span><span class="o">=</span><span class="mi">5</span>
|
|||
|
<span class="go">(<__main__.a instance at 882890>, 'foo', 5)</span>
|
|||
|
|
|||
|
<span class="gp">>>> </span><span class="k">class</span> <span class="nc">b</span><span class="p">:</span> <span class="k">pass</span>
|
|||
|
<span class="gp">>>> </span><span class="n">bi</span><span class="o">=</span><span class="n">b</span><span class="p">()</span>
|
|||
|
<span class="gp">>>> </span><span class="n">bi</span><span class="o">.</span><span class="fm">__setattr__</span><span class="o">=</span><span class="n">prn</span>
|
|||
|
<span class="gp">>>> </span><span class="n">b</span><span class="o">.</span><span class="n">foo</span><span class="o">=</span><span class="mi">5</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
</li>
|
|||
|
<li>Assignment to __dict__[“XXX”] can overwrite the attribute
|
|||
|
access handler for __attr_XXX__. Typically the access handlers will
|
|||
|
store information away in private __XXX variables</li>
|
|||
|
<li>An attribute access handler that attempts to call setattr or getattr
|
|||
|
on the object itself can cause an infinite loop (as with <code class="docutils literal notranslate"><span class="pre">__getattr__</span></code>)
|
|||
|
Once again, the solution is to use a special (typically private)
|
|||
|
variable such as __XXX.</li>
|
|||
|
</ol>
|
|||
|
</section>
|
|||
|
<section id="note">
|
|||
|
<h2><a class="toc-backref" href="#note" role="doc-backlink">Note</a></h2>
|
|||
|
<p>The descriptor mechanism described in <a class="pep reference internal" href="../pep-0252/" title="PEP 252 – Making Types Look More Like Classes">PEP 252</a> is powerful enough
|
|||
|
to support this more directly. A ‘getset’ constructor may be
|
|||
|
added to the language making this possible:</p>
|
|||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
|
|||
|
<span class="k">def</span> <span class="nf">get_x</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">__x</span>
|
|||
|
<span class="k">def</span> <span class="nf">set_x</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span>
|
|||
|
<span class="bp">self</span><span class="o">.</span><span class="n">__x</span> <span class="o">=</span> <span class="n">v</span>
|
|||
|
<span class="n">x</span> <span class="o">=</span> <span class="n">getset</span><span class="p">(</span><span class="n">get_x</span><span class="p">,</span> <span class="n">set_x</span><span class="p">)</span>
|
|||
|
</pre></div>
|
|||
|
</div>
|
|||
|
<p>Additional syntactic sugar might be added, or a naming convention
|
|||
|
could be recognized.</p>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<hr class="docutils" />
|
|||
|
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0213.rst">https://github.com/python/peps/blob/main/peps/pep-0213.rst</a></p>
|
|||
|
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0213.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="#introduction">Introduction</a></li>
|
|||
|
<li><a class="reference internal" href="#justification">Justification</a><ul>
|
|||
|
<li><a class="reference internal" href="#scenario-1">Scenario 1</a></li>
|
|||
|
<li><a class="reference internal" href="#scenario-2">Scenario 2</a></li>
|
|||
|
<li><a class="reference internal" href="#scenario-3">Scenario 3</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a class="reference internal" href="#current-solution">Current Solution</a></li>
|
|||
|
<li><a class="reference internal" href="#proposed-syntax">Proposed Syntax</a></li>
|
|||
|
<li><a class="reference internal" href="#semantics">Semantics</a></li>
|
|||
|
<li><a class="reference internal" href="#proposed-implementation">Proposed Implementation</a></li>
|
|||
|
<li><a class="reference internal" href="#caveats">Caveats</a></li>
|
|||
|
<li><a class="reference internal" href="#note">Note</a></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<br>
|
|||
|
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0213.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>
|