gooderp18绿色标准版
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

1645 rindas
166KB

  1. <!DOCTYPE html>
  2. <html lang="en" data-content_root="../">
  3. <head>
  4. <meta charset="utf-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
  6. <meta property="og:title" content="Descriptor Guide" />
  7. <meta property="og:type" content="website" />
  8. <meta property="og:url" content="https://docs.python.org/3/howto/descriptor.html" />
  9. <meta property="og:site_name" content="Python documentation" />
  10. <meta property="og:description" content="Author, Raymond Hettinger,, Contact,<python at rcn dot com>,. Contents: Descriptor Guide- Primer- Simple example: A descriptor that returns a constant, Dynamic lookups, Managed attributes, Customiz..." />
  11. <meta property="og:image" content="https://docs.python.org/3/_static/og-image.png" />
  12. <meta property="og:image:alt" content="Python documentation" />
  13. <meta name="description" content="Author, Raymond Hettinger,, Contact,<python at rcn dot com>,. Contents: Descriptor Guide- Primer- Simple example: A descriptor that returns a constant, Dynamic lookups, Managed attributes, Customiz..." />
  14. <meta property="og:image:width" content="200" />
  15. <meta property="og:image:height" content="200" />
  16. <meta name="theme-color" content="#3776ab" />
  17. <title>Descriptor Guide &#8212; Python 3.12.3 documentation</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
  18. <link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=80d5e7a1" />
  19. <link rel="stylesheet" type="text/css" href="../_static/pydoctheme.css?v=bb723527" />
  20. <link id="pygments_dark_css" media="(prefers-color-scheme: dark)" rel="stylesheet" type="text/css" href="../_static/pygments_dark.css?v=b20cc3f5" />
  21. <script src="../_static/documentation_options.js?v=2c828074"></script>
  22. <script src="../_static/doctools.js?v=888ff710"></script>
  23. <script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
  24. <script src="../_static/sidebar.js"></script>
  25. <link rel="search" type="application/opensearchdescription+xml"
  26. title="Search within Python 3.12.3 documentation"
  27. href="../_static/opensearch.xml"/>
  28. <link rel="author" title="About these documents" href="../about.html" />
  29. <link rel="index" title="Index" href="../genindex.html" />
  30. <link rel="search" title="Search" href="../search.html" />
  31. <link rel="copyright" title="Copyright" href="../copyright.html" />
  32. <link rel="next" title="Debugging C API extensions and CPython Internals with GDB" href="gdb_helpers.html" />
  33. <link rel="prev" title="Curses Programming with Python" href="curses.html" />
  34. <link rel="canonical" href="https://docs.python.org/3/howto/descriptor.html" />
  35. <style>
  36. @media only screen {
  37. table.full-width-table {
  38. width: 100%;
  39. }
  40. }
  41. </style>
  42. <link rel="stylesheet" href="../_static/pydoctheme_dark.css" media="(prefers-color-scheme: dark)" id="pydoctheme_dark_css">
  43. <link rel="shortcut icon" type="image/png" href="../_static/py.svg" />
  44. <script type="text/javascript" src="../_static/copybutton.js"></script>
  45. <script type="text/javascript" src="../_static/menu.js"></script>
  46. <script type="text/javascript" src="../_static/search-focus.js"></script>
  47. <script type="text/javascript" src="../_static/themetoggle.js"></script>
  48. </head>
  49. <body>
  50. <div class="mobile-nav">
  51. <input type="checkbox" id="menuToggler" class="toggler__input" aria-controls="navigation"
  52. aria-pressed="false" aria-expanded="false" role="button" aria-label="Menu" />
  53. <nav class="nav-content" role="navigation">
  54. <label for="menuToggler" class="toggler__label">
  55. <span></span>
  56. </label>
  57. <span class="nav-items-wrapper">
  58. <a href="https://www.python.org/" class="nav-logo">
  59. <img src="../_static/py.svg" alt="Python logo"/>
  60. </a>
  61. <span class="version_switcher_placeholder"></span>
  62. <form role="search" class="search" action="../search.html" method="get">
  63. <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" class="search-icon">
  64. <path fill-rule="nonzero" fill="currentColor" d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 001.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 00-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 005.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path>
  65. </svg>
  66. <input placeholder="Quick search" aria-label="Quick search" type="search" name="q" />
  67. <input type="submit" value="Go"/>
  68. </form>
  69. </span>
  70. </nav>
  71. <div class="menu-wrapper">
  72. <nav class="menu" role="navigation" aria-label="main navigation">
  73. <div class="language_switcher_placeholder"></div>
  74. <label class="theme-selector-label">
  75. Theme
  76. <select class="theme-selector" oninput="activateTheme(this.value)">
  77. <option value="auto" selected>Auto</option>
  78. <option value="light">Light</option>
  79. <option value="dark">Dark</option>
  80. </select>
  81. </label>
  82. <div>
  83. <h3><a href="../contents.html">Table of Contents</a></h3>
  84. <ul>
  85. <li><a class="reference internal" href="#">Descriptor Guide</a><ul>
  86. <li><a class="reference internal" href="#primer">Primer</a><ul>
  87. <li><a class="reference internal" href="#simple-example-a-descriptor-that-returns-a-constant">Simple example: A descriptor that returns a constant</a></li>
  88. <li><a class="reference internal" href="#dynamic-lookups">Dynamic lookups</a></li>
  89. <li><a class="reference internal" href="#managed-attributes">Managed attributes</a></li>
  90. <li><a class="reference internal" href="#customized-names">Customized names</a></li>
  91. <li><a class="reference internal" href="#closing-thoughts">Closing thoughts</a></li>
  92. </ul>
  93. </li>
  94. <li><a class="reference internal" href="#complete-practical-example">Complete Practical Example</a><ul>
  95. <li><a class="reference internal" href="#validator-class">Validator class</a></li>
  96. <li><a class="reference internal" href="#custom-validators">Custom validators</a></li>
  97. <li><a class="reference internal" href="#practical-application">Practical application</a></li>
  98. </ul>
  99. </li>
  100. <li><a class="reference internal" href="#technical-tutorial">Technical Tutorial</a><ul>
  101. <li><a class="reference internal" href="#abstract">Abstract</a></li>
  102. <li><a class="reference internal" href="#definition-and-introduction">Definition and introduction</a></li>
  103. <li><a class="reference internal" href="#descriptor-protocol">Descriptor protocol</a></li>
  104. <li><a class="reference internal" href="#overview-of-descriptor-invocation">Overview of descriptor invocation</a></li>
  105. <li><a class="reference internal" href="#invocation-from-an-instance">Invocation from an instance</a></li>
  106. <li><a class="reference internal" href="#invocation-from-a-class">Invocation from a class</a></li>
  107. <li><a class="reference internal" href="#invocation-from-super">Invocation from super</a></li>
  108. <li><a class="reference internal" href="#summary-of-invocation-logic">Summary of invocation logic</a></li>
  109. <li><a class="reference internal" href="#automatic-name-notification">Automatic name notification</a></li>
  110. <li><a class="reference internal" href="#orm-example">ORM example</a></li>
  111. </ul>
  112. </li>
  113. <li><a class="reference internal" href="#pure-python-equivalents">Pure Python Equivalents</a><ul>
  114. <li><a class="reference internal" href="#properties">Properties</a></li>
  115. <li><a class="reference internal" href="#functions-and-methods">Functions and methods</a></li>
  116. <li><a class="reference internal" href="#kinds-of-methods">Kinds of methods</a></li>
  117. <li><a class="reference internal" href="#static-methods">Static methods</a></li>
  118. <li><a class="reference internal" href="#class-methods">Class methods</a></li>
  119. <li><a class="reference internal" href="#member-objects-and-slots">Member objects and __slots__</a></li>
  120. </ul>
  121. </li>
  122. </ul>
  123. </li>
  124. </ul>
  125. </div>
  126. <div>
  127. <h4>Previous topic</h4>
  128. <p class="topless"><a href="curses.html"
  129. title="previous chapter">Curses Programming with Python</a></p>
  130. </div>
  131. <div>
  132. <h4>Next topic</h4>
  133. <p class="topless"><a href="gdb_helpers.html"
  134. title="next chapter">Debugging C API extensions and CPython Internals with GDB</a></p>
  135. </div>
  136. <div role="note" aria-label="source link">
  137. <h3>This Page</h3>
  138. <ul class="this-page-menu">
  139. <li><a href="../bugs.html">Report a Bug</a></li>
  140. <li>
  141. <a href="https://github.com/python/cpython/blob/main/Doc/howto/descriptor.rst"
  142. rel="nofollow">Show Source
  143. </a>
  144. </li>
  145. </ul>
  146. </div>
  147. </nav>
  148. </div>
  149. </div>
  150. <div class="related" role="navigation" aria-label="related navigation">
  151. <h3>Navigation</h3>
  152. <ul>
  153. <li class="right" style="margin-right: 10px">
  154. <a href="../genindex.html" title="General Index"
  155. accesskey="I">index</a></li>
  156. <li class="right" >
  157. <a href="../py-modindex.html" title="Python Module Index"
  158. >modules</a> |</li>
  159. <li class="right" >
  160. <a href="gdb_helpers.html" title="Debugging C API extensions and CPython Internals with GDB"
  161. accesskey="N">next</a> |</li>
  162. <li class="right" >
  163. <a href="curses.html" title="Curses Programming with Python"
  164. accesskey="P">previous</a> |</li>
  165. <li><img src="../_static/py.svg" alt="Python logo" style="vertical-align: middle; margin-top: -1px"/></li>
  166. <li><a href="https://www.python.org/">Python</a> &#187;</li>
  167. <li class="switchers">
  168. <div class="language_switcher_placeholder"></div>
  169. <div class="version_switcher_placeholder"></div>
  170. </li>
  171. <li>
  172. </li>
  173. <li id="cpython-language-and-version">
  174. <a href="../index.html">3.12.3 Documentation</a> &#187;
  175. </li>
  176. <li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python HOWTOs</a> &#187;</li>
  177. <li class="nav-item nav-item-this"><a href="">Descriptor Guide</a></li>
  178. <li class="right">
  179. <div class="inline-search" role="search">
  180. <form class="inline-search" action="../search.html" method="get">
  181. <input placeholder="Quick search" aria-label="Quick search" type="search" name="q" id="search-box" />
  182. <input type="submit" value="Go" />
  183. </form>
  184. </div>
  185. |
  186. </li>
  187. <li class="right">
  188. <label class="theme-selector-label">
  189. Theme
  190. <select class="theme-selector" oninput="activateTheme(this.value)">
  191. <option value="auto" selected>Auto</option>
  192. <option value="light">Light</option>
  193. <option value="dark">Dark</option>
  194. </select>
  195. </label> |</li>
  196. </ul>
  197. </div>
  198. <div class="document">
  199. <div class="documentwrapper">
  200. <div class="bodywrapper">
  201. <div class="body" role="main">
  202. <section id="descriptor-guide">
  203. <span id="descriptorhowto"></span><h1><a class="toc-backref" href="#id1" role="doc-backlink">Descriptor Guide</a><a class="headerlink" href="#descriptor-guide" title="Link to this heading">¶</a></h1>
  204. <dl class="field-list simple">
  205. <dt class="field-odd">Author<span class="colon">:</span></dt>
  206. <dd class="field-odd"><p>Raymond Hettinger</p>
  207. </dd>
  208. <dt class="field-even">Contact<span class="colon">:</span></dt>
  209. <dd class="field-even"><p>&lt;python at rcn dot com&gt;</p>
  210. </dd>
  211. </dl>
  212. <nav class="contents" id="contents">
  213. <p class="topic-title">Contents</p>
  214. <ul class="simple">
  215. <li><p><a class="reference internal" href="#descriptor-guide" id="id1">Descriptor Guide</a></p>
  216. <ul>
  217. <li><p><a class="reference internal" href="#primer" id="id2">Primer</a></p>
  218. <ul>
  219. <li><p><a class="reference internal" href="#simple-example-a-descriptor-that-returns-a-constant" id="id3">Simple example: A descriptor that returns a constant</a></p></li>
  220. <li><p><a class="reference internal" href="#dynamic-lookups" id="id4">Dynamic lookups</a></p></li>
  221. <li><p><a class="reference internal" href="#managed-attributes" id="id5">Managed attributes</a></p></li>
  222. <li><p><a class="reference internal" href="#customized-names" id="id6">Customized names</a></p></li>
  223. <li><p><a class="reference internal" href="#closing-thoughts" id="id7">Closing thoughts</a></p></li>
  224. </ul>
  225. </li>
  226. <li><p><a class="reference internal" href="#complete-practical-example" id="id8">Complete Practical Example</a></p>
  227. <ul>
  228. <li><p><a class="reference internal" href="#validator-class" id="id9">Validator class</a></p></li>
  229. <li><p><a class="reference internal" href="#custom-validators" id="id10">Custom validators</a></p></li>
  230. <li><p><a class="reference internal" href="#practical-application" id="id11">Practical application</a></p></li>
  231. </ul>
  232. </li>
  233. <li><p><a class="reference internal" href="#technical-tutorial" id="id12">Technical Tutorial</a></p>
  234. <ul>
  235. <li><p><a class="reference internal" href="#abstract" id="id13">Abstract</a></p></li>
  236. <li><p><a class="reference internal" href="#definition-and-introduction" id="id14">Definition and introduction</a></p></li>
  237. <li><p><a class="reference internal" href="#descriptor-protocol" id="id15">Descriptor protocol</a></p></li>
  238. <li><p><a class="reference internal" href="#overview-of-descriptor-invocation" id="id16">Overview of descriptor invocation</a></p></li>
  239. <li><p><a class="reference internal" href="#invocation-from-an-instance" id="id17">Invocation from an instance</a></p></li>
  240. <li><p><a class="reference internal" href="#invocation-from-a-class" id="id18">Invocation from a class</a></p></li>
  241. <li><p><a class="reference internal" href="#invocation-from-super" id="id19">Invocation from super</a></p></li>
  242. <li><p><a class="reference internal" href="#summary-of-invocation-logic" id="id20">Summary of invocation logic</a></p></li>
  243. <li><p><a class="reference internal" href="#automatic-name-notification" id="id21">Automatic name notification</a></p></li>
  244. <li><p><a class="reference internal" href="#orm-example" id="id22">ORM example</a></p></li>
  245. </ul>
  246. </li>
  247. <li><p><a class="reference internal" href="#pure-python-equivalents" id="id23">Pure Python Equivalents</a></p>
  248. <ul>
  249. <li><p><a class="reference internal" href="#properties" id="id24">Properties</a></p></li>
  250. <li><p><a class="reference internal" href="#functions-and-methods" id="id25">Functions and methods</a></p></li>
  251. <li><p><a class="reference internal" href="#kinds-of-methods" id="id26">Kinds of methods</a></p></li>
  252. <li><p><a class="reference internal" href="#static-methods" id="id27">Static methods</a></p></li>
  253. <li><p><a class="reference internal" href="#class-methods" id="id28">Class methods</a></p></li>
  254. <li><p><a class="reference internal" href="#member-objects-and-slots" id="id29">Member objects and __slots__</a></p></li>
  255. </ul>
  256. </li>
  257. </ul>
  258. </li>
  259. </ul>
  260. </nav>
  261. <p><a class="reference internal" href="../glossary.html#term-descriptor"><span class="xref std std-term">Descriptors</span></a> let objects customize attribute lookup,
  262. storage, and deletion.</p>
  263. <p>This guide has four major sections:</p>
  264. <ol class="arabic simple">
  265. <li><p>The “primer” gives a basic overview, moving gently from simple examples,
  266. adding one feature at a time. Start here if you’re new to descriptors.</p></li>
  267. <li><p>The second section shows a complete, practical descriptor example. If you
  268. already know the basics, start there.</p></li>
  269. <li><p>The third section provides a more technical tutorial that goes into the
  270. detailed mechanics of how descriptors work. Most people don’t need this
  271. level of detail.</p></li>
  272. <li><p>The last section has pure Python equivalents for built-in descriptors that
  273. are written in C. Read this if you’re curious about how functions turn
  274. into bound methods or about the implementation of common tools like
  275. <a class="reference internal" href="../library/functions.html#classmethod" title="classmethod"><code class="xref py py-func docutils literal notranslate"><span class="pre">classmethod()</span></code></a>, <a class="reference internal" href="../library/functions.html#staticmethod" title="staticmethod"><code class="xref py py-func docutils literal notranslate"><span class="pre">staticmethod()</span></code></a>, <a class="reference internal" href="../library/functions.html#property" title="property"><code class="xref py py-func docutils literal notranslate"><span class="pre">property()</span></code></a>, and
  276. <a class="reference internal" href="../glossary.html#term-__slots__"><span class="xref std std-term">__slots__</span></a>.</p></li>
  277. </ol>
  278. <section id="primer">
  279. <h2><a class="toc-backref" href="#id2" role="doc-backlink">Primer</a><a class="headerlink" href="#primer" title="Link to this heading">¶</a></h2>
  280. <p>In this primer, we start with the most basic possible example and then we’ll
  281. add new capabilities one by one.</p>
  282. <section id="simple-example-a-descriptor-that-returns-a-constant">
  283. <h3><a class="toc-backref" href="#id3" role="doc-backlink">Simple example: A descriptor that returns a constant</a><a class="headerlink" href="#simple-example-a-descriptor-that-returns-a-constant" title="Link to this heading">¶</a></h3>
  284. <p>The <code class="xref py py-class docutils literal notranslate"><span class="pre">Ten</span></code> class is a descriptor whose <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code> method always
  285. returns the constant <code class="docutils literal notranslate"><span class="pre">10</span></code>:</p>
  286. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Ten</span><span class="p">:</span>
  287. <span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  288. <span class="k">return</span> <span class="mi">10</span>
  289. </pre></div>
  290. </div>
  291. <p>To use the descriptor, it must be stored as a class variable in another class:</p>
  292. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">A</span><span class="p">:</span>
  293. <span class="n">x</span> <span class="o">=</span> <span class="mi">5</span> <span class="c1"># Regular class attribute</span>
  294. <span class="n">y</span> <span class="o">=</span> <span class="n">Ten</span><span class="p">()</span> <span class="c1"># Descriptor instance</span>
  295. </pre></div>
  296. </div>
  297. <p>An interactive session shows the difference between normal attribute lookup
  298. and descriptor lookup:</p>
  299. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="o">=</span> <span class="n">A</span><span class="p">()</span> <span class="c1"># Make an instance of class A</span>
  300. <span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="o">.</span><span class="n">x</span> <span class="c1"># Normal attribute lookup</span>
  301. <span class="go">5</span>
  302. <span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="o">.</span><span class="n">y</span> <span class="c1"># Descriptor lookup</span>
  303. <span class="go">10</span>
  304. </pre></div>
  305. </div>
  306. <p>In the <code class="docutils literal notranslate"><span class="pre">a.x</span></code> attribute lookup, the dot operator finds <code class="docutils literal notranslate"><span class="pre">'x':</span> <span class="pre">5</span></code>
  307. in the class dictionary. In the <code class="docutils literal notranslate"><span class="pre">a.y</span></code> lookup, the dot operator
  308. finds a descriptor instance, recognized by its <code class="docutils literal notranslate"><span class="pre">__get__</span></code> method.
  309. Calling that method returns <code class="docutils literal notranslate"><span class="pre">10</span></code>.</p>
  310. <p>Note that the value <code class="docutils literal notranslate"><span class="pre">10</span></code> is not stored in either the class dictionary or the
  311. instance dictionary. Instead, the value <code class="docutils literal notranslate"><span class="pre">10</span></code> is computed on demand.</p>
  312. <p>This example shows how a simple descriptor works, but it isn’t very useful.
  313. For retrieving constants, normal attribute lookup would be better.</p>
  314. <p>In the next section, we’ll create something more useful, a dynamic lookup.</p>
  315. </section>
  316. <section id="dynamic-lookups">
  317. <h3><a class="toc-backref" href="#id4" role="doc-backlink">Dynamic lookups</a><a class="headerlink" href="#dynamic-lookups" title="Link to this heading">¶</a></h3>
  318. <p>Interesting descriptors typically run computations instead of returning
  319. constants:</p>
  320. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>
  321. <span class="k">class</span> <span class="nc">DirectorySize</span><span class="p">:</span>
  322. <span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  323. <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">dirname</span><span class="p">))</span>
  324. <span class="k">class</span> <span class="nc">Directory</span><span class="p">:</span>
  325. <span class="n">size</span> <span class="o">=</span> <span class="n">DirectorySize</span><span class="p">()</span> <span class="c1"># Descriptor instance</span>
  326. <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">dirname</span><span class="p">):</span>
  327. <span class="bp">self</span><span class="o">.</span><span class="n">dirname</span> <span class="o">=</span> <span class="n">dirname</span> <span class="c1"># Regular instance attribute</span>
  328. </pre></div>
  329. </div>
  330. <p>An interactive session shows that the lookup is dynamic — it computes
  331. different, updated answers each time:</p>
  332. <div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">s</span> <span class="o">=</span> <span class="n">Directory</span><span class="p">(</span><span class="s1">&#39;songs&#39;</span><span class="p">)</span>
  333. <span class="gp">&gt;&gt;&gt; </span><span class="n">g</span> <span class="o">=</span> <span class="n">Directory</span><span class="p">(</span><span class="s1">&#39;games&#39;</span><span class="p">)</span>
  334. <span class="gp">&gt;&gt;&gt; </span><span class="n">s</span><span class="o">.</span><span class="n">size</span> <span class="c1"># The songs directory has twenty files</span>
  335. <span class="go">20</span>
  336. <span class="gp">&gt;&gt;&gt; </span><span class="n">g</span><span class="o">.</span><span class="n">size</span> <span class="c1"># The games directory has three files</span>
  337. <span class="go">3</span>
  338. <span class="gp">&gt;&gt;&gt; </span><span class="n">os</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="s1">&#39;games/chess&#39;</span><span class="p">)</span> <span class="c1"># Delete a game</span>
  339. <span class="gp">&gt;&gt;&gt; </span><span class="n">g</span><span class="o">.</span><span class="n">size</span> <span class="c1"># File count is automatically updated</span>
  340. <span class="go">2</span>
  341. </pre></div>
  342. </div>
  343. <p>Besides showing how descriptors can run computations, this example also
  344. reveals the purpose of the parameters to <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code>. The <em>self</em>
  345. parameter is <em>size</em>, an instance of <em>DirectorySize</em>. The <em>obj</em> parameter is
  346. either <em>g</em> or <em>s</em>, an instance of <em>Directory</em>. It is the <em>obj</em> parameter that
  347. lets the <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code> method learn the target directory. The <em>objtype</em>
  348. parameter is the class <em>Directory</em>.</p>
  349. </section>
  350. <section id="managed-attributes">
  351. <h3><a class="toc-backref" href="#id5" role="doc-backlink">Managed attributes</a><a class="headerlink" href="#managed-attributes" title="Link to this heading">¶</a></h3>
  352. <p>A popular use for descriptors is managing access to instance data. The
  353. descriptor is assigned to a public attribute in the class dictionary while the
  354. actual data is stored as a private attribute in the instance dictionary. The
  355. descriptor’s <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code> and <code class="xref py py-meth docutils literal notranslate"><span class="pre">__set__()</span></code> methods are triggered when
  356. the public attribute is accessed.</p>
  357. <p>In the following example, <em>age</em> is the public attribute and <em>_age</em> is the
  358. private attribute. When the public attribute is accessed, the descriptor logs
  359. the lookup or update:</p>
  360. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
  361. <span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">)</span>
  362. <span class="k">class</span> <span class="nc">LoggedAgeAccess</span><span class="p">:</span>
  363. <span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  364. <span class="n">value</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">_age</span>
  365. <span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Accessing </span><span class="si">%r</span><span class="s1"> giving </span><span class="si">%r</span><span class="s1">&#39;</span><span class="p">,</span> <span class="s1">&#39;age&#39;</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
  366. <span class="k">return</span> <span class="n">value</span>
  367. <span class="k">def</span> <span class="fm">__set__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
  368. <span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Updating </span><span class="si">%r</span><span class="s1"> to </span><span class="si">%r</span><span class="s1">&#39;</span><span class="p">,</span> <span class="s1">&#39;age&#39;</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
  369. <span class="n">obj</span><span class="o">.</span><span class="n">_age</span> <span class="o">=</span> <span class="n">value</span>
  370. <span class="k">class</span> <span class="nc">Person</span><span class="p">:</span>
  371. <span class="n">age</span> <span class="o">=</span> <span class="n">LoggedAgeAccess</span><span class="p">()</span> <span class="c1"># Descriptor instance</span>
  372. <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">name</span><span class="p">,</span> <span class="n">age</span><span class="p">):</span>
  373. <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span> <span class="c1"># Regular instance attribute</span>
  374. <span class="bp">self</span><span class="o">.</span><span class="n">age</span> <span class="o">=</span> <span class="n">age</span> <span class="c1"># Calls __set__()</span>
  375. <span class="k">def</span> <span class="nf">birthday</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  376. <span class="bp">self</span><span class="o">.</span><span class="n">age</span> <span class="o">+=</span> <span class="mi">1</span> <span class="c1"># Calls both __get__() and __set__()</span>
  377. </pre></div>
  378. </div>
  379. <p>An interactive session shows that all access to the managed attribute <em>age</em> is
  380. logged, but that the regular attribute <em>name</em> is not logged:</p>
  381. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">mary</span> <span class="o">=</span> <span class="n">Person</span><span class="p">(</span><span class="s1">&#39;Mary M&#39;</span><span class="p">,</span> <span class="mi">30</span><span class="p">)</span> <span class="c1"># The initial age update is logged</span>
  382. <span class="go">INFO:root:Updating &#39;age&#39; to 30</span>
  383. <span class="gp">&gt;&gt;&gt; </span><span class="n">dave</span> <span class="o">=</span> <span class="n">Person</span><span class="p">(</span><span class="s1">&#39;David D&#39;</span><span class="p">,</span> <span class="mi">40</span><span class="p">)</span>
  384. <span class="go">INFO:root:Updating &#39;age&#39; to 40</span>
  385. <span class="gp">&gt;&gt;&gt; </span><span class="nb">vars</span><span class="p">(</span><span class="n">mary</span><span class="p">)</span> <span class="c1"># The actual data is in a private attribute</span>
  386. <span class="go">{&#39;name&#39;: &#39;Mary M&#39;, &#39;_age&#39;: 30}</span>
  387. <span class="gp">&gt;&gt;&gt; </span><span class="nb">vars</span><span class="p">(</span><span class="n">dave</span><span class="p">)</span>
  388. <span class="go">{&#39;name&#39;: &#39;David D&#39;, &#39;_age&#39;: 40}</span>
  389. <span class="gp">&gt;&gt;&gt; </span><span class="n">mary</span><span class="o">.</span><span class="n">age</span> <span class="c1"># Access the data and log the lookup</span>
  390. <span class="go">INFO:root:Accessing &#39;age&#39; giving 30</span>
  391. <span class="go">30</span>
  392. <span class="gp">&gt;&gt;&gt; </span><span class="n">mary</span><span class="o">.</span><span class="n">birthday</span><span class="p">()</span> <span class="c1"># Updates are logged as well</span>
  393. <span class="go">INFO:root:Accessing &#39;age&#39; giving 30</span>
  394. <span class="go">INFO:root:Updating &#39;age&#39; to 31</span>
  395. <span class="gp">&gt;&gt;&gt; </span><span class="n">dave</span><span class="o">.</span><span class="n">name</span> <span class="c1"># Regular attribute lookup isn&#39;t logged</span>
  396. <span class="go">&#39;David D&#39;</span>
  397. <span class="gp">&gt;&gt;&gt; </span><span class="n">dave</span><span class="o">.</span><span class="n">age</span> <span class="c1"># Only the managed attribute is logged</span>
  398. <span class="go">INFO:root:Accessing &#39;age&#39; giving 40</span>
  399. <span class="go">40</span>
  400. </pre></div>
  401. </div>
  402. <p>One major issue with this example is that the private name <em>_age</em> is hardwired in
  403. the <em>LoggedAgeAccess</em> class. That means that each instance can only have one
  404. logged attribute and that its name is unchangeable. In the next example,
  405. we’ll fix that problem.</p>
  406. </section>
  407. <section id="customized-names">
  408. <h3><a class="toc-backref" href="#id6" role="doc-backlink">Customized names</a><a class="headerlink" href="#customized-names" title="Link to this heading">¶</a></h3>
  409. <p>When a class uses descriptors, it can inform each descriptor about which
  410. variable name was used.</p>
  411. <p>In this example, the <code class="xref py py-class docutils literal notranslate"><span class="pre">Person</span></code> class has two descriptor instances,
  412. <em>name</em> and <em>age</em>. When the <code class="xref py py-class docutils literal notranslate"><span class="pre">Person</span></code> class is defined, it makes a
  413. callback to <code class="xref py py-meth docutils literal notranslate"><span class="pre">__set_name__()</span></code> in <em>LoggedAccess</em> so that the field names can
  414. be recorded, giving each descriptor its own <em>public_name</em> and <em>private_name</em>:</p>
  415. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
  416. <span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">)</span>
  417. <span class="k">class</span> <span class="nc">LoggedAccess</span><span class="p">:</span>
  418. <span class="k">def</span> <span class="nf">__set_name__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">owner</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
  419. <span class="bp">self</span><span class="o">.</span><span class="n">public_name</span> <span class="o">=</span> <span class="n">name</span>
  420. <span class="bp">self</span><span class="o">.</span><span class="n">private_name</span> <span class="o">=</span> <span class="s1">&#39;_&#39;</span> <span class="o">+</span> <span class="n">name</span>
  421. <span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  422. <span class="n">value</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">private_name</span><span class="p">)</span>
  423. <span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Accessing </span><span class="si">%r</span><span class="s1"> giving </span><span class="si">%r</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">public_name</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
  424. <span class="k">return</span> <span class="n">value</span>
  425. <span class="k">def</span> <span class="fm">__set__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
  426. <span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;Updating </span><span class="si">%r</span><span class="s1"> to </span><span class="si">%r</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">public_name</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
  427. <span class="nb">setattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">private_name</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
  428. <span class="k">class</span> <span class="nc">Person</span><span class="p">:</span>
  429. <span class="n">name</span> <span class="o">=</span> <span class="n">LoggedAccess</span><span class="p">()</span> <span class="c1"># First descriptor instance</span>
  430. <span class="n">age</span> <span class="o">=</span> <span class="n">LoggedAccess</span><span class="p">()</span> <span class="c1"># Second descriptor instance</span>
  431. <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">name</span><span class="p">,</span> <span class="n">age</span><span class="p">):</span>
  432. <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span> <span class="c1"># Calls the first descriptor</span>
  433. <span class="bp">self</span><span class="o">.</span><span class="n">age</span> <span class="o">=</span> <span class="n">age</span> <span class="c1"># Calls the second descriptor</span>
  434. <span class="k">def</span> <span class="nf">birthday</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  435. <span class="bp">self</span><span class="o">.</span><span class="n">age</span> <span class="o">+=</span> <span class="mi">1</span>
  436. </pre></div>
  437. </div>
  438. <p>An interactive session shows that the <code class="xref py py-class docutils literal notranslate"><span class="pre">Person</span></code> class has called
  439. <code class="xref py py-meth docutils literal notranslate"><span class="pre">__set_name__()</span></code> so that the field names would be recorded. Here
  440. we call <a class="reference internal" href="../library/functions.html#vars" title="vars"><code class="xref py py-func docutils literal notranslate"><span class="pre">vars()</span></code></a> to look up the descriptor without triggering it:</p>
  441. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nb">vars</span><span class="p">(</span><span class="nb">vars</span><span class="p">(</span><span class="n">Person</span><span class="p">)[</span><span class="s1">&#39;name&#39;</span><span class="p">])</span>
  442. <span class="go">{&#39;public_name&#39;: &#39;name&#39;, &#39;private_name&#39;: &#39;_name&#39;}</span>
  443. <span class="gp">&gt;&gt;&gt; </span><span class="nb">vars</span><span class="p">(</span><span class="nb">vars</span><span class="p">(</span><span class="n">Person</span><span class="p">)[</span><span class="s1">&#39;age&#39;</span><span class="p">])</span>
  444. <span class="go">{&#39;public_name&#39;: &#39;age&#39;, &#39;private_name&#39;: &#39;_age&#39;}</span>
  445. </pre></div>
  446. </div>
  447. <p>The new class now logs access to both <em>name</em> and <em>age</em>:</p>
  448. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">pete</span> <span class="o">=</span> <span class="n">Person</span><span class="p">(</span><span class="s1">&#39;Peter P&#39;</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span>
  449. <span class="go">INFO:root:Updating &#39;name&#39; to &#39;Peter P&#39;</span>
  450. <span class="go">INFO:root:Updating &#39;age&#39; to 10</span>
  451. <span class="gp">&gt;&gt;&gt; </span><span class="n">kate</span> <span class="o">=</span> <span class="n">Person</span><span class="p">(</span><span class="s1">&#39;Catherine C&#39;</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span>
  452. <span class="go">INFO:root:Updating &#39;name&#39; to &#39;Catherine C&#39;</span>
  453. <span class="go">INFO:root:Updating &#39;age&#39; to 20</span>
  454. </pre></div>
  455. </div>
  456. <p>The two <em>Person</em> instances contain only the private names:</p>
  457. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nb">vars</span><span class="p">(</span><span class="n">pete</span><span class="p">)</span>
  458. <span class="go">{&#39;_name&#39;: &#39;Peter P&#39;, &#39;_age&#39;: 10}</span>
  459. <span class="gp">&gt;&gt;&gt; </span><span class="nb">vars</span><span class="p">(</span><span class="n">kate</span><span class="p">)</span>
  460. <span class="go">{&#39;_name&#39;: &#39;Catherine C&#39;, &#39;_age&#39;: 20}</span>
  461. </pre></div>
  462. </div>
  463. </section>
  464. <section id="closing-thoughts">
  465. <h3><a class="toc-backref" href="#id7" role="doc-backlink">Closing thoughts</a><a class="headerlink" href="#closing-thoughts" title="Link to this heading">¶</a></h3>
  466. <p>A <a class="reference internal" href="../glossary.html#term-descriptor"><span class="xref std std-term">descriptor</span></a> is what we call any object that defines <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code>,
  467. <code class="xref py py-meth docutils literal notranslate"><span class="pre">__set__()</span></code>, or <code class="xref py py-meth docutils literal notranslate"><span class="pre">__delete__()</span></code>.</p>
  468. <p>Optionally, descriptors can have a <code class="xref py py-meth docutils literal notranslate"><span class="pre">__set_name__()</span></code> method. This is only
  469. used in cases where a descriptor needs to know either the class where it was
  470. created or the name of class variable it was assigned to. (This method, if
  471. present, is called even if the class is not a descriptor.)</p>
  472. <p>Descriptors get invoked by the dot operator during attribute lookup. If a
  473. descriptor is accessed indirectly with <code class="docutils literal notranslate"><span class="pre">vars(some_class)[descriptor_name]</span></code>,
  474. the descriptor instance is returned without invoking it.</p>
  475. <p>Descriptors only work when used as class variables. When put in instances,
  476. they have no effect.</p>
  477. <p>The main motivation for descriptors is to provide a hook allowing objects
  478. stored in class variables to control what happens during attribute lookup.</p>
  479. <p>Traditionally, the calling class controls what happens during lookup.
  480. Descriptors invert that relationship and allow the data being looked-up to
  481. have a say in the matter.</p>
  482. <p>Descriptors are used throughout the language. It is how functions turn into
  483. bound methods. Common tools like <a class="reference internal" href="../library/functions.html#classmethod" title="classmethod"><code class="xref py py-func docutils literal notranslate"><span class="pre">classmethod()</span></code></a>, <a class="reference internal" href="../library/functions.html#staticmethod" title="staticmethod"><code class="xref py py-func docutils literal notranslate"><span class="pre">staticmethod()</span></code></a>,
  484. <a class="reference internal" href="../library/functions.html#property" title="property"><code class="xref py py-func docutils literal notranslate"><span class="pre">property()</span></code></a>, and <a class="reference internal" href="../library/functools.html#functools.cached_property" title="functools.cached_property"><code class="xref py py-func docutils literal notranslate"><span class="pre">functools.cached_property()</span></code></a> are all implemented as
  485. descriptors.</p>
  486. </section>
  487. </section>
  488. <section id="complete-practical-example">
  489. <h2><a class="toc-backref" href="#id8" role="doc-backlink">Complete Practical Example</a><a class="headerlink" href="#complete-practical-example" title="Link to this heading">¶</a></h2>
  490. <p>In this example, we create a practical and powerful tool for locating
  491. notoriously hard to find data corruption bugs.</p>
  492. <section id="validator-class">
  493. <h3><a class="toc-backref" href="#id9" role="doc-backlink">Validator class</a><a class="headerlink" href="#validator-class" title="Link to this heading">¶</a></h3>
  494. <p>A validator is a descriptor for managed attribute access. Prior to storing
  495. any data, it verifies that the new value meets various type and range
  496. restrictions. If those restrictions aren’t met, it raises an exception to
  497. prevent data corruption at its source.</p>
  498. <p>This <code class="xref py py-class docutils literal notranslate"><span class="pre">Validator</span></code> class is both an <a class="reference internal" href="../glossary.html#term-abstract-base-class"><span class="xref std std-term">abstract base class</span></a> and a
  499. managed attribute descriptor:</p>
  500. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">abc</span> <span class="kn">import</span> <span class="n">ABC</span><span class="p">,</span> <span class="n">abstractmethod</span>
  501. <span class="k">class</span> <span class="nc">Validator</span><span class="p">(</span><span class="n">ABC</span><span class="p">):</span>
  502. <span class="k">def</span> <span class="nf">__set_name__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">owner</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
  503. <span class="bp">self</span><span class="o">.</span><span class="n">private_name</span> <span class="o">=</span> <span class="s1">&#39;_&#39;</span> <span class="o">+</span> <span class="n">name</span>
  504. <span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  505. <span class="k">return</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">private_name</span><span class="p">)</span>
  506. <span class="k">def</span> <span class="fm">__set__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
  507. <span class="bp">self</span><span class="o">.</span><span class="n">validate</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
  508. <span class="nb">setattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">private_name</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
  509. <span class="nd">@abstractmethod</span>
  510. <span class="k">def</span> <span class="nf">validate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
  511. <span class="k">pass</span>
  512. </pre></div>
  513. </div>
  514. <p>Custom validators need to inherit from <code class="xref py py-class docutils literal notranslate"><span class="pre">Validator</span></code> and must supply a
  515. <code class="xref py py-meth docutils literal notranslate"><span class="pre">validate()</span></code> method to test various restrictions as needed.</p>
  516. </section>
  517. <section id="custom-validators">
  518. <h3><a class="toc-backref" href="#id10" role="doc-backlink">Custom validators</a><a class="headerlink" href="#custom-validators" title="Link to this heading">¶</a></h3>
  519. <p>Here are three practical data validation utilities:</p>
  520. <ol class="arabic simple">
  521. <li><p><code class="xref py py-class docutils literal notranslate"><span class="pre">OneOf</span></code> verifies that a value is one of a restricted set of options.</p></li>
  522. <li><p><code class="xref py py-class docutils literal notranslate"><span class="pre">Number</span></code> verifies that a value is either an <a class="reference internal" href="../library/functions.html#int" title="int"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> or
  523. <a class="reference internal" href="../library/functions.html#float" title="float"><code class="xref py py-class docutils literal notranslate"><span class="pre">float</span></code></a>. Optionally, it verifies that a value is between a given
  524. minimum or maximum.</p></li>
  525. <li><p><code class="xref py py-class docutils literal notranslate"><span class="pre">String</span></code> verifies that a value is a <a class="reference internal" href="../library/stdtypes.html#str" title="str"><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></a>. Optionally, it
  526. validates a given minimum or maximum length. It can validate a
  527. user-defined <a class="reference external" href="https://en.wikipedia.org/wiki/Predicate_(mathematical_logic)">predicate</a> as well.</p></li>
  528. </ol>
  529. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">OneOf</span><span class="p">(</span><span class="n">Validator</span><span class="p">):</span>
  530. <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="o">*</span><span class="n">options</span><span class="p">):</span>
  531. <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
  532. <span class="k">def</span> <span class="nf">validate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
  533. <span class="k">if</span> <span class="n">value</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="p">:</span>
  534. <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;Expected </span><span class="si">{</span><span class="n">value</span><span class="si">!r}</span><span class="s1"> to be one of </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="si">!r}</span><span class="s1">&#39;</span><span class="p">)</span>
  535. <span class="k">class</span> <span class="nc">Number</span><span class="p">(</span><span class="n">Validator</span><span class="p">):</span>
  536. <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">minvalue</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">maxvalue</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  537. <span class="bp">self</span><span class="o">.</span><span class="n">minvalue</span> <span class="o">=</span> <span class="n">minvalue</span>
  538. <span class="bp">self</span><span class="o">.</span><span class="n">maxvalue</span> <span class="o">=</span> <span class="n">maxvalue</span>
  539. <span class="k">def</span> <span class="nf">validate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
  540. <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="nb">float</span><span class="p">)):</span>
  541. <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;Expected </span><span class="si">{</span><span class="n">value</span><span class="si">!r}</span><span class="s1"> to be an int or float&#39;</span><span class="p">)</span>
  542. <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">minvalue</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">value</span> <span class="o">&lt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">minvalue</span><span class="p">:</span>
  543. <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
  544. <span class="sa">f</span><span class="s1">&#39;Expected </span><span class="si">{</span><span class="n">value</span><span class="si">!r}</span><span class="s1"> to be at least </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">minvalue</span><span class="si">!r}</span><span class="s1">&#39;</span>
  545. <span class="p">)</span>
  546. <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">maxvalue</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">value</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">maxvalue</span><span class="p">:</span>
  547. <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
  548. <span class="sa">f</span><span class="s1">&#39;Expected </span><span class="si">{</span><span class="n">value</span><span class="si">!r}</span><span class="s1"> to be no more than </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">maxvalue</span><span class="si">!r}</span><span class="s1">&#39;</span>
  549. <span class="p">)</span>
  550. <span class="k">class</span> <span class="nc">String</span><span class="p">(</span><span class="n">Validator</span><span class="p">):</span>
  551. <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">minsize</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">maxsize</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">predicate</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  552. <span class="bp">self</span><span class="o">.</span><span class="n">minsize</span> <span class="o">=</span> <span class="n">minsize</span>
  553. <span class="bp">self</span><span class="o">.</span><span class="n">maxsize</span> <span class="o">=</span> <span class="n">maxsize</span>
  554. <span class="bp">self</span><span class="o">.</span><span class="n">predicate</span> <span class="o">=</span> <span class="n">predicate</span>
  555. <span class="k">def</span> <span class="nf">validate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
  556. <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
  557. <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;Expected </span><span class="si">{</span><span class="n">value</span><span class="si">!r}</span><span class="s1"> to be an str&#39;</span><span class="p">)</span>
  558. <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">minsize</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="o">&lt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">minsize</span><span class="p">:</span>
  559. <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
  560. <span class="sa">f</span><span class="s1">&#39;Expected </span><span class="si">{</span><span class="n">value</span><span class="si">!r}</span><span class="s1"> to be no smaller than </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">minsize</span><span class="si">!r}</span><span class="s1">&#39;</span>
  561. <span class="p">)</span>
  562. <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">maxsize</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">maxsize</span><span class="p">:</span>
  563. <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
  564. <span class="sa">f</span><span class="s1">&#39;Expected </span><span class="si">{</span><span class="n">value</span><span class="si">!r}</span><span class="s1"> to be no bigger than </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">maxsize</span><span class="si">!r}</span><span class="s1">&#39;</span>
  565. <span class="p">)</span>
  566. <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">predicate</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">predicate</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
  567. <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
  568. <span class="sa">f</span><span class="s1">&#39;Expected </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">predicate</span><span class="si">}</span><span class="s1"> to be true for </span><span class="si">{</span><span class="n">value</span><span class="si">!r}</span><span class="s1">&#39;</span>
  569. <span class="p">)</span>
  570. </pre></div>
  571. </div>
  572. </section>
  573. <section id="practical-application">
  574. <h3><a class="toc-backref" href="#id11" role="doc-backlink">Practical application</a><a class="headerlink" href="#practical-application" title="Link to this heading">¶</a></h3>
  575. <p>Here’s how the data validators can be used in a real class:</p>
  576. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Component</span><span class="p">:</span>
  577. <span class="n">name</span> <span class="o">=</span> <span class="n">String</span><span class="p">(</span><span class="n">minsize</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">maxsize</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">predicate</span><span class="o">=</span><span class="nb">str</span><span class="o">.</span><span class="n">isupper</span><span class="p">)</span>
  578. <span class="n">kind</span> <span class="o">=</span> <span class="n">OneOf</span><span class="p">(</span><span class="s1">&#39;wood&#39;</span><span class="p">,</span> <span class="s1">&#39;metal&#39;</span><span class="p">,</span> <span class="s1">&#39;plastic&#39;</span><span class="p">)</span>
  579. <span class="n">quantity</span> <span class="o">=</span> <span class="n">Number</span><span class="p">(</span><span class="n">minvalue</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
  580. <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">name</span><span class="p">,</span> <span class="n">kind</span><span class="p">,</span> <span class="n">quantity</span><span class="p">):</span>
  581. <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
  582. <span class="bp">self</span><span class="o">.</span><span class="n">kind</span> <span class="o">=</span> <span class="n">kind</span>
  583. <span class="bp">self</span><span class="o">.</span><span class="n">quantity</span> <span class="o">=</span> <span class="n">quantity</span>
  584. </pre></div>
  585. </div>
  586. <p>The descriptors prevent invalid instances from being created:</p>
  587. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Component</span><span class="p">(</span><span class="s1">&#39;Widget&#39;</span><span class="p">,</span> <span class="s1">&#39;metal&#39;</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span> <span class="c1"># Blocked: &#39;Widget&#39; is not all uppercase</span>
  588. <span class="gt">Traceback (most recent call last):</span>
  589. <span class="w"> </span><span class="o">...</span>
  590. <span class="gr">ValueError</span>: <span class="n">Expected &lt;method &#39;isupper&#39; of &#39;str&#39; objects&gt; to be true for &#39;Widget&#39;</span>
  591. <span class="gp">&gt;&gt;&gt; </span><span class="n">Component</span><span class="p">(</span><span class="s1">&#39;WIDGET&#39;</span><span class="p">,</span> <span class="s1">&#39;metle&#39;</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span> <span class="c1"># Blocked: &#39;metle&#39; is misspelled</span>
  592. <span class="gt">Traceback (most recent call last):</span>
  593. <span class="w"> </span><span class="o">...</span>
  594. <span class="gr">ValueError</span>: <span class="n">Expected &#39;metle&#39; to be one of {&#39;metal&#39;, &#39;plastic&#39;, &#39;wood&#39;}</span>
  595. <span class="gp">&gt;&gt;&gt; </span><span class="n">Component</span><span class="p">(</span><span class="s1">&#39;WIDGET&#39;</span><span class="p">,</span> <span class="s1">&#39;metal&#39;</span><span class="p">,</span> <span class="o">-</span><span class="mi">5</span><span class="p">)</span> <span class="c1"># Blocked: -5 is negative</span>
  596. <span class="gt">Traceback (most recent call last):</span>
  597. <span class="w"> </span><span class="o">...</span>
  598. <span class="gr">ValueError</span>: <span class="n">Expected -5 to be at least 0</span>
  599. <span class="gp">&gt;&gt;&gt; </span><span class="n">Component</span><span class="p">(</span><span class="s1">&#39;WIDGET&#39;</span><span class="p">,</span> <span class="s1">&#39;metal&#39;</span><span class="p">,</span> <span class="s1">&#39;V&#39;</span><span class="p">)</span> <span class="c1"># Blocked: &#39;V&#39; isn&#39;t a number</span>
  600. <span class="gt">Traceback (most recent call last):</span>
  601. <span class="w"> </span><span class="o">...</span>
  602. <span class="gr">TypeError</span>: <span class="n">Expected &#39;V&#39; to be an int or float</span>
  603. <span class="gp">&gt;&gt;&gt; </span><span class="n">c</span> <span class="o">=</span> <span class="n">Component</span><span class="p">(</span><span class="s1">&#39;WIDGET&#39;</span><span class="p">,</span> <span class="s1">&#39;metal&#39;</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span> <span class="c1"># Allowed: The inputs are valid</span>
  604. </pre></div>
  605. </div>
  606. </section>
  607. </section>
  608. <section id="technical-tutorial">
  609. <h2><a class="toc-backref" href="#id12" role="doc-backlink">Technical Tutorial</a><a class="headerlink" href="#technical-tutorial" title="Link to this heading">¶</a></h2>
  610. <p>What follows is a more technical tutorial for the mechanics and details of how
  611. descriptors work.</p>
  612. <section id="abstract">
  613. <h3><a class="toc-backref" href="#id13" role="doc-backlink">Abstract</a><a class="headerlink" href="#abstract" title="Link to this heading">¶</a></h3>
  614. <p>Defines descriptors, summarizes the protocol, and shows how descriptors are
  615. called. Provides an example showing how object relational mappings work.</p>
  616. <p>Learning about descriptors not only provides access to a larger toolset, it
  617. creates a deeper understanding of how Python works.</p>
  618. </section>
  619. <section id="definition-and-introduction">
  620. <h3><a class="toc-backref" href="#id14" role="doc-backlink">Definition and introduction</a><a class="headerlink" href="#definition-and-introduction" title="Link to this heading">¶</a></h3>
  621. <p>In general, a descriptor is an attribute value that has one of the methods in
  622. the descriptor protocol. Those methods are <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code>, <code class="xref py py-meth docutils literal notranslate"><span class="pre">__set__()</span></code>,
  623. and <code class="xref py py-meth docutils literal notranslate"><span class="pre">__delete__()</span></code>. If any of those methods are defined for an
  624. attribute, it is said to be a <a class="reference internal" href="../glossary.html#term-descriptor"><span class="xref std std-term">descriptor</span></a>.</p>
  625. <p>The default behavior for attribute access is to get, set, or delete the
  626. attribute from an object’s dictionary. For instance, <code class="docutils literal notranslate"><span class="pre">a.x</span></code> has a lookup chain
  627. starting with <code class="docutils literal notranslate"><span class="pre">a.__dict__['x']</span></code>, then <code class="docutils literal notranslate"><span class="pre">type(a).__dict__['x']</span></code>, and
  628. continuing through the method resolution order of <code class="docutils literal notranslate"><span class="pre">type(a)</span></code>. If the
  629. looked-up value is an object defining one of the descriptor methods, then Python
  630. may override the default behavior and invoke the descriptor method instead.
  631. Where this occurs in the precedence chain depends on which descriptor methods
  632. were defined.</p>
  633. <p>Descriptors are a powerful, general purpose protocol. They are the mechanism
  634. behind properties, methods, static methods, class methods, and
  635. <a class="reference internal" href="../library/functions.html#super" title="super"><code class="xref py py-func docutils literal notranslate"><span class="pre">super()</span></code></a>. They are used throughout Python itself. Descriptors
  636. simplify the underlying C code and offer a flexible set of new tools for
  637. everyday Python programs.</p>
  638. </section>
  639. <section id="descriptor-protocol">
  640. <h3><a class="toc-backref" href="#id15" role="doc-backlink">Descriptor protocol</a><a class="headerlink" href="#descriptor-protocol" title="Link to this heading">¶</a></h3>
  641. <p><code class="docutils literal notranslate"><span class="pre">descr.__get__(self,</span> <span class="pre">obj,</span> <span class="pre">type=None)</span></code></p>
  642. <p><code class="docutils literal notranslate"><span class="pre">descr.__set__(self,</span> <span class="pre">obj,</span> <span class="pre">value)</span></code></p>
  643. <p><code class="docutils literal notranslate"><span class="pre">descr.__delete__(self,</span> <span class="pre">obj)</span></code></p>
  644. <p>That is all there is to it. Define any of these methods and an object is
  645. considered a descriptor and can override default behavior upon being looked up
  646. as an attribute.</p>
  647. <p>If an object defines <code class="xref py py-meth docutils literal notranslate"><span class="pre">__set__()</span></code> or <code class="xref py py-meth docutils literal notranslate"><span class="pre">__delete__()</span></code>, it is considered
  648. a data descriptor. Descriptors that only define <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code> are called
  649. non-data descriptors (they are often used for methods but other uses are
  650. possible).</p>
  651. <p>Data and non-data descriptors differ in how overrides are calculated with
  652. respect to entries in an instance’s dictionary. If an instance’s dictionary
  653. has an entry with the same name as a data descriptor, the data descriptor
  654. takes precedence. If an instance’s dictionary has an entry with the same
  655. name as a non-data descriptor, the dictionary entry takes precedence.</p>
  656. <p>To make a read-only data descriptor, define both <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code> and
  657. <code class="xref py py-meth docutils literal notranslate"><span class="pre">__set__()</span></code> with the <code class="xref py py-meth docutils literal notranslate"><span class="pre">__set__()</span></code> raising an <a class="reference internal" href="../library/exceptions.html#AttributeError" title="AttributeError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">AttributeError</span></code></a> when
  658. called. Defining the <code class="xref py py-meth docutils literal notranslate"><span class="pre">__set__()</span></code> method with an exception raising
  659. placeholder is enough to make it a data descriptor.</p>
  660. </section>
  661. <section id="overview-of-descriptor-invocation">
  662. <h3><a class="toc-backref" href="#id16" role="doc-backlink">Overview of descriptor invocation</a><a class="headerlink" href="#overview-of-descriptor-invocation" title="Link to this heading">¶</a></h3>
  663. <p>A descriptor can be called directly with <code class="docutils literal notranslate"><span class="pre">desc.__get__(obj)</span></code> or
  664. <code class="docutils literal notranslate"><span class="pre">desc.__get__(None,</span> <span class="pre">cls)</span></code>.</p>
  665. <p>But it is more common for a descriptor to be invoked automatically from
  666. attribute access.</p>
  667. <p>The expression <code class="docutils literal notranslate"><span class="pre">obj.x</span></code> looks up the attribute <code class="docutils literal notranslate"><span class="pre">x</span></code> in the chain of
  668. namespaces for <code class="docutils literal notranslate"><span class="pre">obj</span></code>. If the search finds a descriptor outside of the
  669. instance <code class="docutils literal notranslate"><span class="pre">__dict__</span></code>, its <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code> method is invoked according to the
  670. precedence rules listed below.</p>
  671. <p>The details of invocation depend on whether <code class="docutils literal notranslate"><span class="pre">obj</span></code> is an object, class, or
  672. instance of super.</p>
  673. </section>
  674. <section id="invocation-from-an-instance">
  675. <h3><a class="toc-backref" href="#id17" role="doc-backlink">Invocation from an instance</a><a class="headerlink" href="#invocation-from-an-instance" title="Link to this heading">¶</a></h3>
  676. <p>Instance lookup scans through a chain of namespaces giving data descriptors
  677. the highest priority, followed by instance variables, then non-data
  678. descriptors, then class variables, and lastly <code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattr__()</span></code> if it is
  679. provided.</p>
  680. <p>If a descriptor is found for <code class="docutils literal notranslate"><span class="pre">a.x</span></code>, then it is invoked with:
  681. <code class="docutils literal notranslate"><span class="pre">desc.__get__(a,</span> <span class="pre">type(a))</span></code>.</p>
  682. <p>The logic for a dotted lookup is in <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">object.__getattribute__()</span></code></a>. Here is
  683. a pure Python equivalent:</p>
  684. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">find_name_in_mro</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">default</span><span class="p">):</span>
  685. <span class="s2">&quot;Emulate _PyType_Lookup() in Objects/typeobject.c&quot;</span>
  686. <span class="k">for</span> <span class="n">base</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__mro__</span><span class="p">:</span>
  687. <span class="k">if</span> <span class="n">name</span> <span class="ow">in</span> <span class="nb">vars</span><span class="p">(</span><span class="n">base</span><span class="p">):</span>
  688. <span class="k">return</span> <span class="nb">vars</span><span class="p">(</span><span class="n">base</span><span class="p">)[</span><span class="n">name</span><span class="p">]</span>
  689. <span class="k">return</span> <span class="n">default</span>
  690. <span class="k">def</span> <span class="nf">object_getattribute</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
  691. <span class="s2">&quot;Emulate PyObject_GenericGetAttr() in Objects/object.c&quot;</span>
  692. <span class="n">null</span> <span class="o">=</span> <span class="nb">object</span><span class="p">()</span>
  693. <span class="n">objtype</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
  694. <span class="n">cls_var</span> <span class="o">=</span> <span class="n">find_name_in_mro</span><span class="p">(</span><span class="n">objtype</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">null</span><span class="p">)</span>
  695. <span class="n">descr_get</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">cls_var</span><span class="p">),</span> <span class="s1">&#39;__get__&#39;</span><span class="p">,</span> <span class="n">null</span><span class="p">)</span>
  696. <span class="k">if</span> <span class="n">descr_get</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">null</span><span class="p">:</span>
  697. <span class="k">if</span> <span class="p">(</span><span class="nb">hasattr</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">cls_var</span><span class="p">),</span> <span class="s1">&#39;__set__&#39;</span><span class="p">)</span>
  698. <span class="ow">or</span> <span class="nb">hasattr</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">cls_var</span><span class="p">),</span> <span class="s1">&#39;__delete__&#39;</span><span class="p">)):</span>
  699. <span class="k">return</span> <span class="n">descr_get</span><span class="p">(</span><span class="n">cls_var</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="p">)</span> <span class="c1"># data descriptor</span>
  700. <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s1">&#39;__dict__&#39;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">name</span> <span class="ow">in</span> <span class="nb">vars</span><span class="p">(</span><span class="n">obj</span><span class="p">):</span>
  701. <span class="k">return</span> <span class="nb">vars</span><span class="p">(</span><span class="n">obj</span><span class="p">)[</span><span class="n">name</span><span class="p">]</span> <span class="c1"># instance variable</span>
  702. <span class="k">if</span> <span class="n">descr_get</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">null</span><span class="p">:</span>
  703. <span class="k">return</span> <span class="n">descr_get</span><span class="p">(</span><span class="n">cls_var</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="p">)</span> <span class="c1"># non-data descriptor</span>
  704. <span class="k">if</span> <span class="n">cls_var</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">null</span><span class="p">:</span>
  705. <span class="k">return</span> <span class="n">cls_var</span> <span class="c1"># class variable</span>
  706. <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
  707. </pre></div>
  708. </div>
  709. <p>Note, there is no <code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattr__()</span></code> hook in the <code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattribute__()</span></code>
  710. code. That is why calling <code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattribute__()</span></code> directly or with
  711. <code class="docutils literal notranslate"><span class="pre">super().__getattribute__</span></code> will bypass <code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattr__()</span></code> entirely.</p>
  712. <p>Instead, it is the dot operator and the <a class="reference internal" href="../library/functions.html#getattr" title="getattr"><code class="xref py py-func docutils literal notranslate"><span class="pre">getattr()</span></code></a> function that are
  713. responsible for invoking <code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattr__()</span></code> whenever <code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattribute__()</span></code>
  714. raises an <a class="reference internal" href="../library/exceptions.html#AttributeError" title="AttributeError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">AttributeError</span></code></a>. Their logic is encapsulated in a helper
  715. function:</p>
  716. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">getattr_hook</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
  717. <span class="s2">&quot;Emulate slot_tp_getattr_hook() in Objects/typeobject.c&quot;</span>
  718. <span class="k">try</span><span class="p">:</span>
  719. <span class="k">return</span> <span class="n">obj</span><span class="o">.</span><span class="fm">__getattribute__</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
  720. <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
  721. <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">obj</span><span class="p">),</span> <span class="s1">&#39;__getattr__&#39;</span><span class="p">):</span>
  722. <span class="k">raise</span>
  723. <span class="k">return</span> <span class="nb">type</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span><span class="o">.</span><span class="fm">__getattr__</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span> <span class="c1"># __getattr__</span>
  724. </pre></div>
  725. </div>
  726. </section>
  727. <section id="invocation-from-a-class">
  728. <h3><a class="toc-backref" href="#id18" role="doc-backlink">Invocation from a class</a><a class="headerlink" href="#invocation-from-a-class" title="Link to this heading">¶</a></h3>
  729. <p>The logic for a dotted lookup such as <code class="docutils literal notranslate"><span class="pre">A.x</span></code> is in
  730. <code class="xref py py-meth docutils literal notranslate"><span class="pre">type.__getattribute__()</span></code>. The steps are similar to those for
  731. <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">object.__getattribute__()</span></code></a> but the instance dictionary lookup is replaced
  732. by a search through the class’s <a class="reference internal" href="../glossary.html#term-method-resolution-order"><span class="xref std std-term">method resolution order</span></a>.</p>
  733. <p>If a descriptor is found, it is invoked with <code class="docutils literal notranslate"><span class="pre">desc.__get__(None,</span> <span class="pre">A)</span></code>.</p>
  734. <p>The full C implementation can be found in <code class="xref c c-func docutils literal notranslate"><span class="pre">type_getattro()</span></code> and
  735. <code class="xref c c-func docutils literal notranslate"><span class="pre">_PyType_Lookup()</span></code> in <a class="reference external" href="https://github.com/python/cpython/tree/3.12/Objects/typeobject.c">Objects/typeobject.c</a>.</p>
  736. </section>
  737. <section id="invocation-from-super">
  738. <h3><a class="toc-backref" href="#id19" role="doc-backlink">Invocation from super</a><a class="headerlink" href="#invocation-from-super" title="Link to this heading">¶</a></h3>
  739. <p>The logic for super’s dotted lookup is in the <code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattribute__()</span></code> method for
  740. object returned by <a class="reference internal" href="../library/functions.html#super" title="super"><code class="xref py py-class docutils literal notranslate"><span class="pre">super()</span></code></a>.</p>
  741. <p>A dotted lookup such as <code class="docutils literal notranslate"><span class="pre">super(A,</span> <span class="pre">obj).m</span></code> searches <code class="docutils literal notranslate"><span class="pre">obj.__class__.__mro__</span></code>
  742. for the base class <code class="docutils literal notranslate"><span class="pre">B</span></code> immediately following <code class="docutils literal notranslate"><span class="pre">A</span></code> and then returns
  743. <code class="docutils literal notranslate"><span class="pre">B.__dict__['m'].__get__(obj,</span> <span class="pre">A)</span></code>. If not a descriptor, <code class="docutils literal notranslate"><span class="pre">m</span></code> is returned
  744. unchanged.</p>
  745. <p>The full C implementation can be found in <code class="xref c c-func docutils literal notranslate"><span class="pre">super_getattro()</span></code> in
  746. <a class="reference external" href="https://github.com/python/cpython/tree/3.12/Objects/typeobject.c">Objects/typeobject.c</a>. A pure Python equivalent can be found in
  747. <a class="reference external" href="https://www.python.org/download/releases/2.2.3/descrintro/#cooperation">Guido’s Tutorial</a>.</p>
  748. </section>
  749. <section id="summary-of-invocation-logic">
  750. <h3><a class="toc-backref" href="#id20" role="doc-backlink">Summary of invocation logic</a><a class="headerlink" href="#summary-of-invocation-logic" title="Link to this heading">¶</a></h3>
  751. <p>The mechanism for descriptors is embedded in the <code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattribute__()</span></code>
  752. methods for <a class="reference internal" href="../library/functions.html#object" title="object"><code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></a>, <a class="reference internal" href="../library/functions.html#type" title="type"><code class="xref py py-class docutils literal notranslate"><span class="pre">type</span></code></a>, and <a class="reference internal" href="../library/functions.html#super" title="super"><code class="xref py py-func docutils literal notranslate"><span class="pre">super()</span></code></a>.</p>
  753. <p>The important points to remember are:</p>
  754. <ul class="simple">
  755. <li><p>Descriptors are invoked by the <code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattribute__()</span></code> method.</p></li>
  756. <li><p>Classes inherit this machinery from <a class="reference internal" href="../library/functions.html#object" title="object"><code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></a>, <a class="reference internal" href="../library/functions.html#type" title="type"><code class="xref py py-class docutils literal notranslate"><span class="pre">type</span></code></a>, or
  757. <a class="reference internal" href="../library/functions.html#super" title="super"><code class="xref py py-func docutils literal notranslate"><span class="pre">super()</span></code></a>.</p></li>
  758. <li><p>Overriding <code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattribute__()</span></code> prevents automatic descriptor calls
  759. because all the descriptor logic is in that method.</p></li>
  760. <li><p><a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">object.__getattribute__()</span></code></a> and <code class="xref py py-meth docutils literal notranslate"><span class="pre">type.__getattribute__()</span></code> make
  761. different calls to <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code>. The first includes the instance and may
  762. include the class. The second puts in <code class="docutils literal notranslate"><span class="pre">None</span></code> for the instance and always
  763. includes the class.</p></li>
  764. <li><p>Data descriptors always override instance dictionaries.</p></li>
  765. <li><p>Non-data descriptors may be overridden by instance dictionaries.</p></li>
  766. </ul>
  767. </section>
  768. <section id="automatic-name-notification">
  769. <h3><a class="toc-backref" href="#id21" role="doc-backlink">Automatic name notification</a><a class="headerlink" href="#automatic-name-notification" title="Link to this heading">¶</a></h3>
  770. <p>Sometimes it is desirable for a descriptor to know what class variable name it
  771. was assigned to. When a new class is created, the <a class="reference internal" href="../library/functions.html#type" title="type"><code class="xref py py-class docutils literal notranslate"><span class="pre">type</span></code></a> metaclass
  772. scans the dictionary of the new class. If any of the entries are descriptors
  773. and if they define <code class="xref py py-meth docutils literal notranslate"><span class="pre">__set_name__()</span></code>, that method is called with two
  774. arguments. The <em>owner</em> is the class where the descriptor is used, and the
  775. <em>name</em> is the class variable the descriptor was assigned to.</p>
  776. <p>The implementation details are in <code class="xref c c-func docutils literal notranslate"><span class="pre">type_new()</span></code> and
  777. <code class="xref c c-func docutils literal notranslate"><span class="pre">set_names()</span></code> in <a class="reference external" href="https://github.com/python/cpython/tree/3.12/Objects/typeobject.c">Objects/typeobject.c</a>.</p>
  778. <p>Since the update logic is in <code class="xref py py-meth docutils literal notranslate"><span class="pre">type.__new__()</span></code>, notifications only take
  779. place at the time of class creation. If descriptors are added to the class
  780. afterwards, <code class="xref py py-meth docutils literal notranslate"><span class="pre">__set_name__()</span></code> will need to be called manually.</p>
  781. </section>
  782. <section id="orm-example">
  783. <h3><a class="toc-backref" href="#id22" role="doc-backlink">ORM example</a><a class="headerlink" href="#orm-example" title="Link to this heading">¶</a></h3>
  784. <p>The following code is a simplified skeleton showing how data descriptors could
  785. be used to implement an <a class="reference external" href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping">object relational mapping</a>.</p>
  786. <p>The essential idea is that the data is stored in an external database. The
  787. Python instances only hold keys to the database’s tables. Descriptors take
  788. care of lookups or updates:</p>
  789. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Field</span><span class="p">:</span>
  790. <span class="k">def</span> <span class="nf">__set_name__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">owner</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
  791. <span class="bp">self</span><span class="o">.</span><span class="n">fetch</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;SELECT </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s1"> FROM </span><span class="si">{</span><span class="n">owner</span><span class="o">.</span><span class="n">table</span><span class="si">}</span><span class="s1"> WHERE </span><span class="si">{</span><span class="n">owner</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s1">=?;&#39;</span>
  792. <span class="bp">self</span><span class="o">.</span><span class="n">store</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;UPDATE </span><span class="si">{</span><span class="n">owner</span><span class="o">.</span><span class="n">table</span><span class="si">}</span><span class="s1"> SET </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s1">=? WHERE </span><span class="si">{</span><span class="n">owner</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s1">=?;&#39;</span>
  793. <span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  794. <span class="k">return</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">fetch</span><span class="p">,</span> <span class="p">[</span><span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="p">])</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
  795. <span class="k">def</span> <span class="fm">__set__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
  796. <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">store</span><span class="p">,</span> <span class="p">[</span><span class="n">value</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="p">])</span>
  797. <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
  798. </pre></div>
  799. </div>
  800. <p>We can use the <code class="xref py py-class docutils literal notranslate"><span class="pre">Field</span></code> class to define <a class="reference external" href="https://en.wikipedia.org/wiki/Database_model">models</a> that describe the schema for
  801. each table in a database:</p>
  802. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Movie</span><span class="p">:</span>
  803. <span class="n">table</span> <span class="o">=</span> <span class="s1">&#39;Movies&#39;</span> <span class="c1"># Table name</span>
  804. <span class="n">key</span> <span class="o">=</span> <span class="s1">&#39;title&#39;</span> <span class="c1"># Primary key</span>
  805. <span class="n">director</span> <span class="o">=</span> <span class="n">Field</span><span class="p">()</span>
  806. <span class="n">year</span> <span class="o">=</span> <span class="n">Field</span><span class="p">()</span>
  807. <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">key</span><span class="p">):</span>
  808. <span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">key</span>
  809. <span class="k">class</span> <span class="nc">Song</span><span class="p">:</span>
  810. <span class="n">table</span> <span class="o">=</span> <span class="s1">&#39;Music&#39;</span>
  811. <span class="n">key</span> <span class="o">=</span> <span class="s1">&#39;title&#39;</span>
  812. <span class="n">artist</span> <span class="o">=</span> <span class="n">Field</span><span class="p">()</span>
  813. <span class="n">year</span> <span class="o">=</span> <span class="n">Field</span><span class="p">()</span>
  814. <span class="n">genre</span> <span class="o">=</span> <span class="n">Field</span><span class="p">()</span>
  815. <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">key</span><span class="p">):</span>
  816. <span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">key</span>
  817. </pre></div>
  818. </div>
  819. <p>To use the models, first connect to the database:</p>
  820. <div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">sqlite3</span>
  821. <span class="gp">&gt;&gt;&gt; </span><span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s1">&#39;entertainment.db&#39;</span><span class="p">)</span>
  822. </pre></div>
  823. </div>
  824. <p>An interactive session shows how data is retrieved from the database and how
  825. it can be updated:</p>
  826. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Movie</span><span class="p">(</span><span class="s1">&#39;Star Wars&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">director</span>
  827. <span class="go">&#39;George Lucas&#39;</span>
  828. <span class="gp">&gt;&gt;&gt; </span><span class="n">jaws</span> <span class="o">=</span> <span class="n">Movie</span><span class="p">(</span><span class="s1">&#39;Jaws&#39;</span><span class="p">)</span>
  829. <span class="gp">&gt;&gt;&gt; </span><span class="sa">f</span><span class="s1">&#39;Released in </span><span class="si">{</span><span class="n">jaws</span><span class="o">.</span><span class="n">year</span><span class="si">}</span><span class="s1"> by </span><span class="si">{</span><span class="n">jaws</span><span class="o">.</span><span class="n">director</span><span class="si">}</span><span class="s1">&#39;</span>
  830. <span class="go">&#39;Released in 1975 by Steven Spielberg&#39;</span>
  831. <span class="gp">&gt;&gt;&gt; </span><span class="n">Song</span><span class="p">(</span><span class="s1">&#39;Country Roads&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">artist</span>
  832. <span class="go">&#39;John Denver&#39;</span>
  833. <span class="gp">&gt;&gt;&gt; </span><span class="n">Movie</span><span class="p">(</span><span class="s1">&#39;Star Wars&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">director</span> <span class="o">=</span> <span class="s1">&#39;J.J. Abrams&#39;</span>
  834. <span class="gp">&gt;&gt;&gt; </span><span class="n">Movie</span><span class="p">(</span><span class="s1">&#39;Star Wars&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">director</span>
  835. <span class="go">&#39;J.J. Abrams&#39;</span>
  836. </pre></div>
  837. </div>
  838. </section>
  839. </section>
  840. <section id="pure-python-equivalents">
  841. <h2><a class="toc-backref" href="#id23" role="doc-backlink">Pure Python Equivalents</a><a class="headerlink" href="#pure-python-equivalents" title="Link to this heading">¶</a></h2>
  842. <p>The descriptor protocol is simple and offers exciting possibilities. Several
  843. use cases are so common that they have been prepackaged into built-in tools.
  844. Properties, bound methods, static methods, class methods, and __slots__ are
  845. all based on the descriptor protocol.</p>
  846. <section id="properties">
  847. <h3><a class="toc-backref" href="#id24" role="doc-backlink">Properties</a><a class="headerlink" href="#properties" title="Link to this heading">¶</a></h3>
  848. <p>Calling <a class="reference internal" href="../library/functions.html#property" title="property"><code class="xref py py-func docutils literal notranslate"><span class="pre">property()</span></code></a> is a succinct way of building a data descriptor that
  849. triggers a function call upon access to an attribute. Its signature is:</p>
  850. <div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nb">property</span><span class="p">(</span><span class="n">fget</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">fset</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">fdel</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">doc</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">property</span>
  851. </pre></div>
  852. </div>
  853. <p>The documentation shows a typical use to define a managed attribute <code class="docutils literal notranslate"><span class="pre">x</span></code>:</p>
  854. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
  855. <span class="k">def</span> <span class="nf">getx</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>
  856. <span class="k">def</span> <span class="nf">setx</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</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">value</span>
  857. <span class="k">def</span> <span class="nf">delx</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">__x</span>
  858. <span class="n">x</span> <span class="o">=</span> <span class="nb">property</span><span class="p">(</span><span class="n">getx</span><span class="p">,</span> <span class="n">setx</span><span class="p">,</span> <span class="n">delx</span><span class="p">,</span> <span class="s2">&quot;I&#39;m the &#39;x&#39; property.&quot;</span><span class="p">)</span>
  859. </pre></div>
  860. </div>
  861. <p>To see how <a class="reference internal" href="../library/functions.html#property" title="property"><code class="xref py py-func docutils literal notranslate"><span class="pre">property()</span></code></a> is implemented in terms of the descriptor protocol,
  862. here is a pure Python equivalent:</p>
  863. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Property</span><span class="p">:</span>
  864. <span class="s2">&quot;Emulate PyProperty_Type() in Objects/descrobject.c&quot;</span>
  865. <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">fget</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">fset</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">fdel</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">doc</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  866. <span class="bp">self</span><span class="o">.</span><span class="n">fget</span> <span class="o">=</span> <span class="n">fget</span>
  867. <span class="bp">self</span><span class="o">.</span><span class="n">fset</span> <span class="o">=</span> <span class="n">fset</span>
  868. <span class="bp">self</span><span class="o">.</span><span class="n">fdel</span> <span class="o">=</span> <span class="n">fdel</span>
  869. <span class="k">if</span> <span class="n">doc</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">fget</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
  870. <span class="n">doc</span> <span class="o">=</span> <span class="n">fget</span><span class="o">.</span><span class="vm">__doc__</span>
  871. <span class="bp">self</span><span class="o">.</span><span class="vm">__doc__</span> <span class="o">=</span> <span class="n">doc</span>
  872. <span class="bp">self</span><span class="o">.</span><span class="n">_name</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
  873. <span class="k">def</span> <span class="nf">__set_name__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">owner</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
  874. <span class="bp">self</span><span class="o">.</span><span class="n">_name</span> <span class="o">=</span> <span class="n">name</span>
  875. <span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  876. <span class="k">if</span> <span class="n">obj</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
  877. <span class="k">return</span> <span class="bp">self</span>
  878. <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">fget</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
  879. <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
  880. <span class="sa">f</span><span class="s1">&#39;property </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_name</span><span class="si">!r}</span><span class="s1"> of </span><span class="si">{</span><span class="nb">type</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span><span class="o">.</span><span class="vm">__name__</span><span class="si">!r}</span><span class="s1"> object has no getter&#39;</span>
  881. <span class="p">)</span>
  882. <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">fget</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
  883. <span class="k">def</span> <span class="fm">__set__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
  884. <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">fset</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
  885. <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
  886. <span class="sa">f</span><span class="s1">&#39;property </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_name</span><span class="si">!r}</span><span class="s1"> of </span><span class="si">{</span><span class="nb">type</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span><span class="o">.</span><span class="vm">__name__</span><span class="si">!r}</span><span class="s1"> object has no setter&#39;</span>
  887. <span class="p">)</span>
  888. <span class="bp">self</span><span class="o">.</span><span class="n">fset</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
  889. <span class="k">def</span> <span class="fm">__delete__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
  890. <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">fdel</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
  891. <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
  892. <span class="sa">f</span><span class="s1">&#39;property </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_name</span><span class="si">!r}</span><span class="s1"> of </span><span class="si">{</span><span class="nb">type</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span><span class="o">.</span><span class="vm">__name__</span><span class="si">!r}</span><span class="s1"> object has no deleter&#39;</span>
  893. <span class="p">)</span>
  894. <span class="bp">self</span><span class="o">.</span><span class="n">fdel</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
  895. <span class="k">def</span> <span class="nf">getter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fget</span><span class="p">):</span>
  896. <span class="n">prop</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)(</span><span class="n">fget</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">fset</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">fdel</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__doc__</span><span class="p">)</span>
  897. <span class="n">prop</span><span class="o">.</span><span class="n">_name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_name</span>
  898. <span class="k">return</span> <span class="n">prop</span>
  899. <span class="k">def</span> <span class="nf">setter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fset</span><span class="p">):</span>
  900. <span class="n">prop</span> <span class="o">=</span> <span class="nb">type</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">fget</span><span class="p">,</span> <span class="n">fset</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">fdel</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__doc__</span><span class="p">)</span>
  901. <span class="n">prop</span><span class="o">.</span><span class="n">_name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_name</span>
  902. <span class="k">return</span> <span class="n">prop</span>
  903. <span class="k">def</span> <span class="nf">deleter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fdel</span><span class="p">):</span>
  904. <span class="n">prop</span> <span class="o">=</span> <span class="nb">type</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">fget</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">fset</span><span class="p">,</span> <span class="n">fdel</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__doc__</span><span class="p">)</span>
  905. <span class="n">prop</span><span class="o">.</span><span class="n">_name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_name</span>
  906. <span class="k">return</span> <span class="n">prop</span>
  907. </pre></div>
  908. </div>
  909. <p>The <a class="reference internal" href="../library/functions.html#property" title="property"><code class="xref py py-func docutils literal notranslate"><span class="pre">property()</span></code></a> builtin helps whenever a user interface has granted
  910. attribute access and then subsequent changes require the intervention of a
  911. method.</p>
  912. <p>For instance, a spreadsheet class may grant access to a cell value through
  913. <code class="docutils literal notranslate"><span class="pre">Cell('b10').value</span></code>. Subsequent improvements to the program require the cell
  914. to be recalculated on every access; however, the programmer does not want to
  915. affect existing client code accessing the attribute directly. The solution is
  916. to wrap access to the value attribute in a property data descriptor:</p>
  917. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Cell</span><span class="p">:</span>
  918. <span class="o">...</span>
  919. <span class="nd">@property</span>
  920. <span class="k">def</span> <span class="nf">value</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  921. <span class="s2">&quot;Recalculate the cell before returning value&quot;</span>
  922. <span class="bp">self</span><span class="o">.</span><span class="n">recalc</span><span class="p">()</span>
  923. <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_value</span>
  924. </pre></div>
  925. </div>
  926. <p>Either the built-in <a class="reference internal" href="../library/functions.html#property" title="property"><code class="xref py py-func docutils literal notranslate"><span class="pre">property()</span></code></a> or our <code class="xref py py-func docutils literal notranslate"><span class="pre">Property()</span></code> equivalent would
  927. work in this example.</p>
  928. </section>
  929. <section id="functions-and-methods">
  930. <h3><a class="toc-backref" href="#id25" role="doc-backlink">Functions and methods</a><a class="headerlink" href="#functions-and-methods" title="Link to this heading">¶</a></h3>
  931. <p>Python’s object oriented features are built upon a function based environment.
  932. Using non-data descriptors, the two are merged seamlessly.</p>
  933. <p>Functions stored in class dictionaries get turned into methods when invoked.
  934. Methods only differ from regular functions in that the object instance is
  935. prepended to the other arguments. By convention, the instance is called
  936. <em>self</em> but could be called <em>this</em> or any other variable name.</p>
  937. <p>Methods can be created manually with <a class="reference internal" href="../library/types.html#types.MethodType" title="types.MethodType"><code class="xref py py-class docutils literal notranslate"><span class="pre">types.MethodType</span></code></a> which is
  938. roughly equivalent to:</p>
  939. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MethodType</span><span class="p">:</span>
  940. <span class="s2">&quot;Emulate PyMethod_Type in Objects/classobject.c&quot;</span>
  941. <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">func</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
  942. <span class="bp">self</span><span class="o">.</span><span class="vm">__func__</span> <span class="o">=</span> <span class="n">func</span>
  943. <span class="bp">self</span><span class="o">.</span><span class="vm">__self__</span> <span class="o">=</span> <span class="n">obj</span>
  944. <span class="k">def</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">kwargs</span><span class="p">):</span>
  945. <span class="n">func</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__func__</span>
  946. <span class="n">obj</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__self__</span>
  947. <span class="k">return</span> <span class="n">func</span><span class="p">(</span><span class="n">obj</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">kwargs</span><span class="p">)</span>
  948. </pre></div>
  949. </div>
  950. <p>To support automatic creation of methods, functions include the
  951. <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code> method for binding methods during attribute access. This
  952. means that functions are non-data descriptors that return bound methods
  953. during dotted lookup from an instance. Here’s how it works:</p>
  954. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Function</span><span class="p">:</span>
  955. <span class="o">...</span>
  956. <span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  957. <span class="s2">&quot;Simulate func_descr_get() in Objects/funcobject.c&quot;</span>
  958. <span class="k">if</span> <span class="n">obj</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
  959. <span class="k">return</span> <span class="bp">self</span>
  960. <span class="k">return</span> <span class="n">MethodType</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">)</span>
  961. </pre></div>
  962. </div>
  963. <p>Running the following class in the interpreter shows how the function
  964. descriptor works in practice:</p>
  965. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">D</span><span class="p">:</span>
  966. <span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
  967. <span class="k">return</span> <span class="n">x</span>
  968. </pre></div>
  969. </div>
  970. <p>The function has a <a class="reference internal" href="../glossary.html#term-qualified-name"><span class="xref std std-term">qualified name</span></a> attribute to support introspection:</p>
  971. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">D</span><span class="o">.</span><span class="n">f</span><span class="o">.</span><span class="vm">__qualname__</span>
  972. <span class="go">&#39;D.f&#39;</span>
  973. </pre></div>
  974. </div>
  975. <p>Accessing the function through the class dictionary does not invoke
  976. <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code>. Instead, it just returns the underlying function object:</p>
  977. <div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">D</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="s1">&#39;f&#39;</span><span class="p">]</span>
  978. <span class="go">&lt;function D.f at 0x00C45070&gt;</span>
  979. </pre></div>
  980. </div>
  981. <p>Dotted access from a class calls <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code> which just returns the
  982. underlying function unchanged:</p>
  983. <div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">D</span><span class="o">.</span><span class="n">f</span>
  984. <span class="go">&lt;function D.f at 0x00C45070&gt;</span>
  985. </pre></div>
  986. </div>
  987. <p>The interesting behavior occurs during dotted access from an instance. The
  988. dotted lookup calls <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code> which returns a bound method object:</p>
  989. <div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">d</span> <span class="o">=</span> <span class="n">D</span><span class="p">()</span>
  990. <span class="gp">&gt;&gt;&gt; </span><span class="n">d</span><span class="o">.</span><span class="n">f</span>
  991. <span class="go">&lt;bound method D.f of &lt;__main__.D object at 0x00B18C90&gt;&gt;</span>
  992. </pre></div>
  993. </div>
  994. <p>Internally, the bound method stores the underlying function and the bound
  995. instance:</p>
  996. <div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">d</span><span class="o">.</span><span class="n">f</span><span class="o">.</span><span class="vm">__func__</span>
  997. <span class="go">&lt;function D.f at 0x00C45070&gt;</span>
  998. <span class="gp">&gt;&gt;&gt; </span><span class="n">d</span><span class="o">.</span><span class="n">f</span><span class="o">.</span><span class="vm">__self__</span>
  999. <span class="go">&lt;__main__.D object at 0x00B18C90&gt;</span>
  1000. </pre></div>
  1001. </div>
  1002. <p>If you have ever wondered where <em>self</em> comes from in regular methods or where
  1003. <em>cls</em> comes from in class methods, this is it!</p>
  1004. </section>
  1005. <section id="kinds-of-methods">
  1006. <h3><a class="toc-backref" href="#id26" role="doc-backlink">Kinds of methods</a><a class="headerlink" href="#kinds-of-methods" title="Link to this heading">¶</a></h3>
  1007. <p>Non-data descriptors provide a simple mechanism for variations on the usual
  1008. patterns of binding functions into methods.</p>
  1009. <p>To recap, functions have a <code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code> method so that they can be converted
  1010. to a method when accessed as attributes. The non-data descriptor transforms an
  1011. <code class="docutils literal notranslate"><span class="pre">obj.f(*args)</span></code> call into <code class="docutils literal notranslate"><span class="pre">f(obj,</span> <span class="pre">*args)</span></code>. Calling <code class="docutils literal notranslate"><span class="pre">cls.f(*args)</span></code>
  1012. becomes <code class="docutils literal notranslate"><span class="pre">f(*args)</span></code>.</p>
  1013. <p>This chart summarizes the binding and its two most useful variants:</p>
  1014. <blockquote>
  1015. <div><table class="docutils align-default">
  1016. <thead>
  1017. <tr class="row-odd"><th class="head"><p>Transformation</p></th>
  1018. <th class="head"><p>Called from an
  1019. object</p></th>
  1020. <th class="head"><p>Called from a
  1021. class</p></th>
  1022. </tr>
  1023. </thead>
  1024. <tbody>
  1025. <tr class="row-even"><td><p>function</p></td>
  1026. <td><p>f(obj, *args)</p></td>
  1027. <td><p>f(*args)</p></td>
  1028. </tr>
  1029. <tr class="row-odd"><td><p>staticmethod</p></td>
  1030. <td><p>f(*args)</p></td>
  1031. <td><p>f(*args)</p></td>
  1032. </tr>
  1033. <tr class="row-even"><td><p>classmethod</p></td>
  1034. <td><p>f(type(obj), *args)</p></td>
  1035. <td><p>f(cls, *args)</p></td>
  1036. </tr>
  1037. </tbody>
  1038. </table>
  1039. </div></blockquote>
  1040. </section>
  1041. <section id="static-methods">
  1042. <h3><a class="toc-backref" href="#id27" role="doc-backlink">Static methods</a><a class="headerlink" href="#static-methods" title="Link to this heading">¶</a></h3>
  1043. <p>Static methods return the underlying function without changes. Calling either
  1044. <code class="docutils literal notranslate"><span class="pre">c.f</span></code> or <code class="docutils literal notranslate"><span class="pre">C.f</span></code> is the equivalent of a direct lookup into
  1045. <code class="docutils literal notranslate"><span class="pre">object.__getattribute__(c,</span> <span class="pre">&quot;f&quot;)</span></code> or <code class="docutils literal notranslate"><span class="pre">object.__getattribute__(C,</span> <span class="pre">&quot;f&quot;)</span></code>. As a
  1046. result, the function becomes identically accessible from either an object or a
  1047. class.</p>
  1048. <p>Good candidates for static methods are methods that do not reference the
  1049. <code class="docutils literal notranslate"><span class="pre">self</span></code> variable.</p>
  1050. <p>For instance, a statistics package may include a container class for
  1051. experimental data. The class provides normal methods for computing the average,
  1052. mean, median, and other descriptive statistics that depend on the data. However,
  1053. there may be useful functions which are conceptually related but do not depend
  1054. on the data. For instance, <code class="docutils literal notranslate"><span class="pre">erf(x)</span></code> is handy conversion routine that comes up
  1055. in statistical work but does not directly depend on a particular dataset.
  1056. It can be called either from an object or the class: <code class="docutils literal notranslate"><span class="pre">s.erf(1.5)</span> <span class="pre">--&gt;</span> <span class="pre">.9332</span></code> or
  1057. <code class="docutils literal notranslate"><span class="pre">Sample.erf(1.5)</span> <span class="pre">--&gt;</span> <span class="pre">.9332</span></code>.</p>
  1058. <p>Since static methods return the underlying function with no changes, the
  1059. example calls are unexciting:</p>
  1060. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">E</span><span class="p">:</span>
  1061. <span class="nd">@staticmethod</span>
  1062. <span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
  1063. <span class="k">return</span> <span class="n">x</span> <span class="o">*</span> <span class="mi">10</span>
  1064. </pre></div>
  1065. </div>
  1066. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">E</span><span class="o">.</span><span class="n">f</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
  1067. <span class="go">30</span>
  1068. <span class="gp">&gt;&gt;&gt; </span><span class="n">E</span><span class="p">()</span><span class="o">.</span><span class="n">f</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
  1069. <span class="go">30</span>
  1070. </pre></div>
  1071. </div>
  1072. <p>Using the non-data descriptor protocol, a pure Python version of
  1073. <a class="reference internal" href="../library/functions.html#staticmethod" title="staticmethod"><code class="xref py py-func docutils literal notranslate"><span class="pre">staticmethod()</span></code></a> would look like this:</p>
  1074. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">functools</span>
  1075. <span class="k">class</span> <span class="nc">StaticMethod</span><span class="p">:</span>
  1076. <span class="s2">&quot;Emulate PyStaticMethod_Type() in Objects/funcobject.c&quot;</span>
  1077. <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">f</span><span class="p">):</span>
  1078. <span class="bp">self</span><span class="o">.</span><span class="n">f</span> <span class="o">=</span> <span class="n">f</span>
  1079. <span class="n">functools</span><span class="o">.</span><span class="n">update_wrapper</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span>
  1080. <span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  1081. <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">f</span>
  1082. <span class="k">def</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">kwds</span><span class="p">):</span>
  1083. <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">f</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">kwds</span><span class="p">)</span>
  1084. </pre></div>
  1085. </div>
  1086. <p>The <a class="reference internal" href="../library/functools.html#functools.update_wrapper" title="functools.update_wrapper"><code class="xref py py-func docutils literal notranslate"><span class="pre">functools.update_wrapper()</span></code></a> call adds a <code class="docutils literal notranslate"><span class="pre">__wrapped__</span></code> attribute
  1087. that refers to the underlying function. Also it carries forward
  1088. the attributes necessary to make the wrapper look like the wrapped
  1089. function: <a class="reference internal" href="../reference/datamodel.html#function.__name__" title="function.__name__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__name__</span></code></a>, <a class="reference internal" href="../reference/datamodel.html#function.__qualname__" title="function.__qualname__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__qualname__</span></code></a>,
  1090. <a class="reference internal" href="../reference/datamodel.html#function.__doc__" title="function.__doc__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__doc__</span></code></a>, and <a class="reference internal" href="../reference/datamodel.html#function.__annotations__" title="function.__annotations__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__annotations__</span></code></a>.</p>
  1091. </section>
  1092. <section id="class-methods">
  1093. <h3><a class="toc-backref" href="#id28" role="doc-backlink">Class methods</a><a class="headerlink" href="#class-methods" title="Link to this heading">¶</a></h3>
  1094. <p>Unlike static methods, class methods prepend the class reference to the
  1095. argument list before calling the function. This format is the same
  1096. for whether the caller is an object or a class:</p>
  1097. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">F</span><span class="p">:</span>
  1098. <span class="nd">@classmethod</span>
  1099. <span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
  1100. <span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="p">,</span> <span class="n">x</span>
  1101. </pre></div>
  1102. </div>
  1103. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">F</span><span class="o">.</span><span class="n">f</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
  1104. <span class="go">(&#39;F&#39;, 3)</span>
  1105. <span class="gp">&gt;&gt;&gt; </span><span class="n">F</span><span class="p">()</span><span class="o">.</span><span class="n">f</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
  1106. <span class="go">(&#39;F&#39;, 3)</span>
  1107. </pre></div>
  1108. </div>
  1109. <p>This behavior is useful whenever the method only needs to have a class
  1110. reference and does not rely on data stored in a specific instance. One use for
  1111. class methods is to create alternate class constructors. For example, the
  1112. classmethod <a class="reference internal" href="../library/stdtypes.html#dict.fromkeys" title="dict.fromkeys"><code class="xref py py-func docutils literal notranslate"><span class="pre">dict.fromkeys()</span></code></a> creates a new dictionary from a list of
  1113. keys. The pure Python equivalent is:</p>
  1114. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Dict</span><span class="p">(</span><span class="nb">dict</span><span class="p">):</span>
  1115. <span class="nd">@classmethod</span>
  1116. <span class="k">def</span> <span class="nf">fromkeys</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">iterable</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  1117. <span class="s2">&quot;Emulate dict_fromkeys() in Objects/dictobject.c&quot;</span>
  1118. <span class="n">d</span> <span class="o">=</span> <span class="bp">cls</span><span class="p">()</span>
  1119. <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">iterable</span><span class="p">:</span>
  1120. <span class="n">d</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
  1121. <span class="k">return</span> <span class="n">d</span>
  1122. </pre></div>
  1123. </div>
  1124. <p>Now a new dictionary of unique keys can be constructed like this:</p>
  1125. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">d</span> <span class="o">=</span> <span class="n">Dict</span><span class="o">.</span><span class="n">fromkeys</span><span class="p">(</span><span class="s1">&#39;abracadabra&#39;</span><span class="p">)</span>
  1126. <span class="gp">&gt;&gt;&gt; </span><span class="nb">type</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> <span class="ow">is</span> <span class="n">Dict</span>
  1127. <span class="go">True</span>
  1128. <span class="gp">&gt;&gt;&gt; </span><span class="n">d</span>
  1129. <span class="go">{&#39;a&#39;: None, &#39;b&#39;: None, &#39;r&#39;: None, &#39;c&#39;: None, &#39;d&#39;: None}</span>
  1130. </pre></div>
  1131. </div>
  1132. <p>Using the non-data descriptor protocol, a pure Python version of
  1133. <a class="reference internal" href="../library/functions.html#classmethod" title="classmethod"><code class="xref py py-func docutils literal notranslate"><span class="pre">classmethod()</span></code></a> would look like this:</p>
  1134. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">functools</span>
  1135. <span class="k">class</span> <span class="nc">ClassMethod</span><span class="p">:</span>
  1136. <span class="s2">&quot;Emulate PyClassMethod_Type() in Objects/funcobject.c&quot;</span>
  1137. <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">f</span><span class="p">):</span>
  1138. <span class="bp">self</span><span class="o">.</span><span class="n">f</span> <span class="o">=</span> <span class="n">f</span>
  1139. <span class="n">functools</span><span class="o">.</span><span class="n">update_wrapper</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span>
  1140. <span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="bp">cls</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  1141. <span class="k">if</span> <span class="bp">cls</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
  1142. <span class="bp">cls</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
  1143. <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">f</span><span class="p">),</span> <span class="s1">&#39;__get__&#39;</span><span class="p">):</span>
  1144. <span class="c1"># This code path was added in Python 3.9</span>
  1145. <span class="c1"># and was deprecated in Python 3.11.</span>
  1146. <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">f</span><span class="o">.</span><span class="fm">__get__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="bp">cls</span><span class="p">)</span>
  1147. <span class="k">return</span> <span class="n">MethodType</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">f</span><span class="p">,</span> <span class="bp">cls</span><span class="p">)</span>
  1148. </pre></div>
  1149. </div>
  1150. <p>The code path for <code class="docutils literal notranslate"><span class="pre">hasattr(type(self.f),</span> <span class="pre">'__get__')</span></code> was added in
  1151. Python 3.9 and makes it possible for <a class="reference internal" href="../library/functions.html#classmethod" title="classmethod"><code class="xref py py-func docutils literal notranslate"><span class="pre">classmethod()</span></code></a> to support
  1152. chained decorators. For example, a classmethod and property could be
  1153. chained together. In Python 3.11, this functionality was deprecated.</p>
  1154. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">G</span><span class="p">:</span>
  1155. <span class="nd">@classmethod</span>
  1156. <span class="nd">@property</span>
  1157. <span class="k">def</span> <span class="nf">__doc__</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
  1158. <span class="k">return</span> <span class="sa">f</span><span class="s1">&#39;A doc for </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">!r}</span><span class="s1">&#39;</span>
  1159. </pre></div>
  1160. </div>
  1161. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">G</span><span class="o">.</span><span class="vm">__doc__</span>
  1162. <span class="go">&quot;A doc for &#39;G&#39;&quot;</span>
  1163. </pre></div>
  1164. </div>
  1165. <p>The <a class="reference internal" href="../library/functools.html#functools.update_wrapper" title="functools.update_wrapper"><code class="xref py py-func docutils literal notranslate"><span class="pre">functools.update_wrapper()</span></code></a> call in <code class="docutils literal notranslate"><span class="pre">ClassMethod</span></code> adds a
  1166. <code class="docutils literal notranslate"><span class="pre">__wrapped__</span></code> attribute that refers to the underlying function. Also
  1167. it carries forward the attributes necessary to make the wrapper look
  1168. like the wrapped function: <a class="reference internal" href="../reference/datamodel.html#function.__name__" title="function.__name__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__name__</span></code></a>,
  1169. <a class="reference internal" href="../reference/datamodel.html#function.__qualname__" title="function.__qualname__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__qualname__</span></code></a>, <a class="reference internal" href="../reference/datamodel.html#function.__doc__" title="function.__doc__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__doc__</span></code></a>,
  1170. and <a class="reference internal" href="../reference/datamodel.html#function.__annotations__" title="function.__annotations__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__annotations__</span></code></a>.</p>
  1171. </section>
  1172. <section id="member-objects-and-slots">
  1173. <h3><a class="toc-backref" href="#id29" role="doc-backlink">Member objects and __slots__</a><a class="headerlink" href="#member-objects-and-slots" title="Link to this heading">¶</a></h3>
  1174. <p>When a class defines <code class="docutils literal notranslate"><span class="pre">__slots__</span></code>, it replaces instance dictionaries with a
  1175. fixed-length array of slot values. From a user point of view that has
  1176. several effects:</p>
  1177. <p>1. Provides immediate detection of bugs due to misspelled attribute
  1178. assignments. Only attribute names specified in <code class="docutils literal notranslate"><span class="pre">__slots__</span></code> are allowed:</p>
  1179. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Vehicle</span><span class="p">:</span>
  1180. <span class="vm">__slots__</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;id_number&#39;</span><span class="p">,</span> <span class="s1">&#39;make&#39;</span><span class="p">,</span> <span class="s1">&#39;model&#39;</span><span class="p">)</span>
  1181. </pre></div>
  1182. </div>
  1183. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">auto</span> <span class="o">=</span> <span class="n">Vehicle</span><span class="p">()</span>
  1184. <span class="gp">&gt;&gt;&gt; </span><span class="n">auto</span><span class="o">.</span><span class="n">id_nubmer</span> <span class="o">=</span> <span class="s1">&#39;VYE483814LQEX&#39;</span>
  1185. <span class="gt">Traceback (most recent call last):</span>
  1186. <span class="w"> </span><span class="o">...</span>
  1187. <span class="gr">AttributeError</span>: <span class="n">&#39;Vehicle&#39; object has no attribute &#39;id_nubmer&#39;</span>
  1188. </pre></div>
  1189. </div>
  1190. <p>2. Helps create immutable objects where descriptors manage access to private
  1191. attributes stored in <code class="docutils literal notranslate"><span class="pre">__slots__</span></code>:</p>
  1192. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Immutable</span><span class="p">:</span>
  1193. <span class="vm">__slots__</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;_dept&#39;</span><span class="p">,</span> <span class="s1">&#39;_name&#39;</span><span class="p">)</span> <span class="c1"># Replace the instance dictionary</span>
  1194. <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">dept</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
  1195. <span class="bp">self</span><span class="o">.</span><span class="n">_dept</span> <span class="o">=</span> <span class="n">dept</span> <span class="c1"># Store to private attribute</span>
  1196. <span class="bp">self</span><span class="o">.</span><span class="n">_name</span> <span class="o">=</span> <span class="n">name</span> <span class="c1"># Store to private attribute</span>
  1197. <span class="nd">@property</span> <span class="c1"># Read-only descriptor</span>
  1198. <span class="k">def</span> <span class="nf">dept</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  1199. <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dept</span>
  1200. <span class="nd">@property</span>
  1201. <span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="c1"># Read-only descriptor</span>
  1202. <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_name</span>
  1203. </pre></div>
  1204. </div>
  1205. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">mark</span> <span class="o">=</span> <span class="n">Immutable</span><span class="p">(</span><span class="s1">&#39;Botany&#39;</span><span class="p">,</span> <span class="s1">&#39;Mark Watney&#39;</span><span class="p">)</span>
  1206. <span class="gp">&gt;&gt;&gt; </span><span class="n">mark</span><span class="o">.</span><span class="n">dept</span>
  1207. <span class="go">&#39;Botany&#39;</span>
  1208. <span class="gp">&gt;&gt;&gt; </span><span class="n">mark</span><span class="o">.</span><span class="n">dept</span> <span class="o">=</span> <span class="s1">&#39;Space Pirate&#39;</span>
  1209. <span class="gt">Traceback (most recent call last):</span>
  1210. <span class="w"> </span><span class="o">...</span>
  1211. <span class="gr">AttributeError</span>: <span class="n">property &#39;dept&#39; of &#39;Immutable&#39; object has no setter</span>
  1212. <span class="gp">&gt;&gt;&gt; </span><span class="n">mark</span><span class="o">.</span><span class="n">location</span> <span class="o">=</span> <span class="s1">&#39;Mars&#39;</span>
  1213. <span class="gt">Traceback (most recent call last):</span>
  1214. <span class="w"> </span><span class="o">...</span>
  1215. <span class="gr">AttributeError</span>: <span class="n">&#39;Immutable&#39; object has no attribute &#39;location&#39;</span>
  1216. </pre></div>
  1217. </div>
  1218. <p>3. Saves memory. On a 64-bit Linux build, an instance with two attributes
  1219. takes 48 bytes with <code class="docutils literal notranslate"><span class="pre">__slots__</span></code> and 152 bytes without. This <a class="reference external" href="https://en.wikipedia.org/wiki/Flyweight_pattern">flyweight
  1220. design pattern</a> likely only
  1221. matters when a large number of instances are going to be created.</p>
  1222. <p>4. Improves speed. Reading instance variables is 35% faster with
  1223. <code class="docutils literal notranslate"><span class="pre">__slots__</span></code> (as measured with Python 3.10 on an Apple M1 processor).</p>
  1224. <p>5. Blocks tools like <a class="reference internal" href="../library/functools.html#functools.cached_property" title="functools.cached_property"><code class="xref py py-func docutils literal notranslate"><span class="pre">functools.cached_property()</span></code></a> which require an
  1225. instance dictionary to function correctly:</p>
  1226. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">functools</span> <span class="kn">import</span> <span class="n">cached_property</span>
  1227. <span class="k">class</span> <span class="nc">CP</span><span class="p">:</span>
  1228. <span class="vm">__slots__</span> <span class="o">=</span> <span class="p">()</span> <span class="c1"># Eliminates the instance dict</span>
  1229. <span class="nd">@cached_property</span> <span class="c1"># Requires an instance dict</span>
  1230. <span class="k">def</span> <span class="nf">pi</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  1231. <span class="k">return</span> <span class="mi">4</span> <span class="o">*</span> <span class="nb">sum</span><span class="p">((</span><span class="o">-</span><span class="mf">1.0</span><span class="p">)</span><span class="o">**</span><span class="n">n</span> <span class="o">/</span> <span class="p">(</span><span class="mf">2.0</span><span class="o">*</span><span class="n">n</span> <span class="o">+</span> <span class="mf">1.0</span><span class="p">)</span>
  1232. <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">reversed</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">100_000</span><span class="p">)))</span>
  1233. </pre></div>
  1234. </div>
  1235. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">CP</span><span class="p">()</span><span class="o">.</span><span class="n">pi</span>
  1236. <span class="gt">Traceback (most recent call last):</span>
  1237. <span class="w"> </span><span class="c">...</span>
  1238. <span class="gr">TypeError</span>: <span class="n">No &#39;__dict__&#39; attribute on &#39;CP&#39; instance to cache &#39;pi&#39; property.</span>
  1239. </pre></div>
  1240. </div>
  1241. <p>It is not possible to create an exact drop-in pure Python version of
  1242. <code class="docutils literal notranslate"><span class="pre">__slots__</span></code> because it requires direct access to C structures and control
  1243. over object memory allocation. However, we can build a mostly faithful
  1244. simulation where the actual C structure for slots is emulated by a private
  1245. <code class="docutils literal notranslate"><span class="pre">_slotvalues</span></code> list. Reads and writes to that private structure are managed
  1246. by member descriptors:</p>
  1247. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">null</span> <span class="o">=</span> <span class="nb">object</span><span class="p">()</span>
  1248. <span class="k">class</span> <span class="nc">Member</span><span class="p">:</span>
  1249. <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">name</span><span class="p">,</span> <span class="n">clsname</span><span class="p">,</span> <span class="n">offset</span><span class="p">):</span>
  1250. <span class="s1">&#39;Emulate PyMemberDef in Include/structmember.h&#39;</span>
  1251. <span class="c1"># Also see descr_new() in Objects/descrobject.c</span>
  1252. <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
  1253. <span class="bp">self</span><span class="o">.</span><span class="n">clsname</span> <span class="o">=</span> <span class="n">clsname</span>
  1254. <span class="bp">self</span><span class="o">.</span><span class="n">offset</span> <span class="o">=</span> <span class="n">offset</span>
  1255. <span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  1256. <span class="s1">&#39;Emulate member_get() in Objects/descrobject.c&#39;</span>
  1257. <span class="c1"># Also see PyMember_GetOne() in Python/structmember.c</span>
  1258. <span class="k">if</span> <span class="n">obj</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
  1259. <span class="k">return</span> <span class="bp">self</span>
  1260. <span class="n">value</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">_slotvalues</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">offset</span><span class="p">]</span>
  1261. <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="n">null</span><span class="p">:</span>
  1262. <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
  1263. <span class="k">return</span> <span class="n">value</span>
  1264. <span class="k">def</span> <span class="fm">__set__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
  1265. <span class="s1">&#39;Emulate member_set() in Objects/descrobject.c&#39;</span>
  1266. <span class="n">obj</span><span class="o">.</span><span class="n">_slotvalues</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">offset</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
  1267. <span class="k">def</span> <span class="fm">__delete__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
  1268. <span class="s1">&#39;Emulate member_delete() in Objects/descrobject.c&#39;</span>
  1269. <span class="n">value</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">_slotvalues</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">offset</span><span class="p">]</span>
  1270. <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="n">null</span><span class="p">:</span>
  1271. <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
  1272. <span class="n">obj</span><span class="o">.</span><span class="n">_slotvalues</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">offset</span><span class="p">]</span> <span class="o">=</span> <span class="n">null</span>
  1273. <span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  1274. <span class="s1">&#39;Emulate member_repr() in Objects/descrobject.c&#39;</span>
  1275. <span class="k">return</span> <span class="sa">f</span><span class="s1">&#39;&lt;Member </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">!r}</span><span class="s1"> of </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">clsname</span><span class="si">!r}</span><span class="s1">&gt;&#39;</span>
  1276. </pre></div>
  1277. </div>
  1278. <p>The <code class="xref py py-meth docutils literal notranslate"><span class="pre">type.__new__()</span></code> method takes care of adding member objects to class
  1279. variables:</p>
  1280. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Type</span><span class="p">(</span><span class="nb">type</span><span class="p">):</span>
  1281. <span class="s1">&#39;Simulate how the type metaclass adds member objects for slots&#39;</span>
  1282. <span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="n">mcls</span><span class="p">,</span> <span class="n">clsname</span><span class="p">,</span> <span class="n">bases</span><span class="p">,</span> <span class="n">mapping</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
  1283. <span class="s1">&#39;Emulate type_new() in Objects/typeobject.c&#39;</span>
  1284. <span class="c1"># type_new() calls PyTypeReady() which calls add_methods()</span>
  1285. <span class="n">slot_names</span> <span class="o">=</span> <span class="n">mapping</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;slot_names&#39;</span><span class="p">,</span> <span class="p">[])</span>
  1286. <span class="k">for</span> <span class="n">offset</span><span class="p">,</span> <span class="n">name</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">slot_names</span><span class="p">):</span>
  1287. <span class="n">mapping</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">Member</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">clsname</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
  1288. <span class="k">return</span> <span class="nb">type</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="n">mcls</span><span class="p">,</span> <span class="n">clsname</span><span class="p">,</span> <span class="n">bases</span><span class="p">,</span> <span class="n">mapping</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
  1289. </pre></div>
  1290. </div>
  1291. <p>The <a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">object.__new__()</span></code></a> method takes care of creating instances that have
  1292. slots instead of an instance dictionary. Here is a rough simulation in pure
  1293. Python:</p>
  1294. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Object</span><span class="p">:</span>
  1295. <span class="s1">&#39;Simulate how object.__new__() allocates memory for __slots__&#39;</span>
  1296. <span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</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">kwargs</span><span class="p">):</span>
  1297. <span class="s1">&#39;Emulate object_new() in Objects/typeobject.c&#39;</span>
  1298. <span class="n">inst</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span>
  1299. <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="s1">&#39;slot_names&#39;</span><span class="p">):</span>
  1300. <span class="n">empty_slots</span> <span class="o">=</span> <span class="p">[</span><span class="n">null</span><span class="p">]</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="n">slot_names</span><span class="p">)</span>
  1301. <span class="nb">object</span><span class="o">.</span><span class="fm">__setattr__</span><span class="p">(</span><span class="n">inst</span><span class="p">,</span> <span class="s1">&#39;_slotvalues&#39;</span><span class="p">,</span> <span class="n">empty_slots</span><span class="p">)</span>
  1302. <span class="k">return</span> <span class="n">inst</span>
  1303. <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">value</span><span class="p">):</span>
  1304. <span class="s1">&#39;Emulate _PyObject_GenericSetAttrWithDict() Objects/object.c&#39;</span>
  1305. <span class="bp">cls</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
  1306. <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="s1">&#39;slot_names&#39;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">slot_names</span><span class="p">:</span>
  1307. <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
  1308. <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">!r}</span><span class="s1"> object has no attribute </span><span class="si">{</span><span class="n">name</span><span class="si">!r}</span><span class="s1">&#39;</span>
  1309. <span class="p">)</span>
  1310. <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__setattr__</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
  1311. <span class="k">def</span> <span class="fm">__delattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
  1312. <span class="s1">&#39;Emulate _PyObject_GenericSetAttrWithDict() Objects/object.c&#39;</span>
  1313. <span class="bp">cls</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
  1314. <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="s1">&#39;slot_names&#39;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">slot_names</span><span class="p">:</span>
  1315. <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
  1316. <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">!r}</span><span class="s1"> object has no attribute </span><span class="si">{</span><span class="n">name</span><span class="si">!r}</span><span class="s1">&#39;</span>
  1317. <span class="p">)</span>
  1318. <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__delattr__</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
  1319. </pre></div>
  1320. </div>
  1321. <p>To use the simulation in a real class, just inherit from <code class="xref py py-class docutils literal notranslate"><span class="pre">Object</span></code> and
  1322. set the <a class="reference internal" href="../glossary.html#term-metaclass"><span class="xref std std-term">metaclass</span></a> to <code class="xref py py-class docutils literal notranslate"><span class="pre">Type</span></code>:</p>
  1323. <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">H</span><span class="p">(</span><span class="n">Object</span><span class="p">,</span> <span class="n">metaclass</span><span class="o">=</span><span class="n">Type</span><span class="p">):</span>
  1324. <span class="s1">&#39;Instance variables stored in slots&#39;</span>
  1325. <span class="n">slot_names</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;x&#39;</span><span class="p">,</span> <span class="s1">&#39;y&#39;</span><span class="p">]</span>
  1326. <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">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
  1327. <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">x</span>
  1328. <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">y</span>
  1329. </pre></div>
  1330. </div>
  1331. <p>At this point, the metaclass has loaded member objects for <em>x</em> and <em>y</em>:</p>
  1332. <div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">pprint</span> <span class="kn">import</span> <span class="n">pp</span>
  1333. <span class="gp">&gt;&gt;&gt; </span><span class="n">pp</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="nb">vars</span><span class="p">(</span><span class="n">H</span><span class="p">)))</span>
  1334. <span class="go">{&#39;__module__&#39;: &#39;__main__&#39;,</span>
  1335. <span class="go"> &#39;__doc__&#39;: &#39;Instance variables stored in slots&#39;,</span>
  1336. <span class="go"> &#39;slot_names&#39;: [&#39;x&#39;, &#39;y&#39;],</span>
  1337. <span class="go"> &#39;__init__&#39;: &lt;function H.__init__ at 0x7fb5d302f9d0&gt;,</span>
  1338. <span class="go"> &#39;x&#39;: &lt;Member &#39;x&#39; of &#39;H&#39;&gt;,</span>
  1339. <span class="go"> &#39;y&#39;: &lt;Member &#39;y&#39; of &#39;H&#39;&gt;}</span>
  1340. </pre></div>
  1341. </div>
  1342. <p>When instances are created, they have a <code class="docutils literal notranslate"><span class="pre">slot_values</span></code> list where the
  1343. attributes are stored:</p>
  1344. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">h</span> <span class="o">=</span> <span class="n">H</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span>
  1345. <span class="gp">&gt;&gt;&gt; </span><span class="nb">vars</span><span class="p">(</span><span class="n">h</span><span class="p">)</span>
  1346. <span class="go">{&#39;_slotvalues&#39;: [10, 20]}</span>
  1347. <span class="gp">&gt;&gt;&gt; </span><span class="n">h</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="mi">55</span>
  1348. <span class="gp">&gt;&gt;&gt; </span><span class="nb">vars</span><span class="p">(</span><span class="n">h</span><span class="p">)</span>
  1349. <span class="go">{&#39;_slotvalues&#39;: [55, 20]}</span>
  1350. </pre></div>
  1351. </div>
  1352. <p>Misspelled or unassigned attributes will raise an exception:</p>
  1353. <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">h</span><span class="o">.</span><span class="n">xz</span>
  1354. <span class="gt">Traceback (most recent call last):</span>
  1355. <span class="w"> </span><span class="o">...</span>
  1356. <span class="gr">AttributeError</span>: <span class="n">&#39;H&#39; object has no attribute &#39;xz&#39;</span>
  1357. </pre></div>
  1358. </div>
  1359. </section>
  1360. </section>
  1361. </section>
  1362. <div class="clearer"></div>
  1363. </div>
  1364. </div>
  1365. </div>
  1366. <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
  1367. <div class="sphinxsidebarwrapper">
  1368. <div>
  1369. <h3><a href="../contents.html">Table of Contents</a></h3>
  1370. <ul>
  1371. <li><a class="reference internal" href="#">Descriptor Guide</a><ul>
  1372. <li><a class="reference internal" href="#primer">Primer</a><ul>
  1373. <li><a class="reference internal" href="#simple-example-a-descriptor-that-returns-a-constant">Simple example: A descriptor that returns a constant</a></li>
  1374. <li><a class="reference internal" href="#dynamic-lookups">Dynamic lookups</a></li>
  1375. <li><a class="reference internal" href="#managed-attributes">Managed attributes</a></li>
  1376. <li><a class="reference internal" href="#customized-names">Customized names</a></li>
  1377. <li><a class="reference internal" href="#closing-thoughts">Closing thoughts</a></li>
  1378. </ul>
  1379. </li>
  1380. <li><a class="reference internal" href="#complete-practical-example">Complete Practical Example</a><ul>
  1381. <li><a class="reference internal" href="#validator-class">Validator class</a></li>
  1382. <li><a class="reference internal" href="#custom-validators">Custom validators</a></li>
  1383. <li><a class="reference internal" href="#practical-application">Practical application</a></li>
  1384. </ul>
  1385. </li>
  1386. <li><a class="reference internal" href="#technical-tutorial">Technical Tutorial</a><ul>
  1387. <li><a class="reference internal" href="#abstract">Abstract</a></li>
  1388. <li><a class="reference internal" href="#definition-and-introduction">Definition and introduction</a></li>
  1389. <li><a class="reference internal" href="#descriptor-protocol">Descriptor protocol</a></li>
  1390. <li><a class="reference internal" href="#overview-of-descriptor-invocation">Overview of descriptor invocation</a></li>
  1391. <li><a class="reference internal" href="#invocation-from-an-instance">Invocation from an instance</a></li>
  1392. <li><a class="reference internal" href="#invocation-from-a-class">Invocation from a class</a></li>
  1393. <li><a class="reference internal" href="#invocation-from-super">Invocation from super</a></li>
  1394. <li><a class="reference internal" href="#summary-of-invocation-logic">Summary of invocation logic</a></li>
  1395. <li><a class="reference internal" href="#automatic-name-notification">Automatic name notification</a></li>
  1396. <li><a class="reference internal" href="#orm-example">ORM example</a></li>
  1397. </ul>
  1398. </li>
  1399. <li><a class="reference internal" href="#pure-python-equivalents">Pure Python Equivalents</a><ul>
  1400. <li><a class="reference internal" href="#properties">Properties</a></li>
  1401. <li><a class="reference internal" href="#functions-and-methods">Functions and methods</a></li>
  1402. <li><a class="reference internal" href="#kinds-of-methods">Kinds of methods</a></li>
  1403. <li><a class="reference internal" href="#static-methods">Static methods</a></li>
  1404. <li><a class="reference internal" href="#class-methods">Class methods</a></li>
  1405. <li><a class="reference internal" href="#member-objects-and-slots">Member objects and __slots__</a></li>
  1406. </ul>
  1407. </li>
  1408. </ul>
  1409. </li>
  1410. </ul>
  1411. </div>
  1412. <div>
  1413. <h4>Previous topic</h4>
  1414. <p class="topless"><a href="curses.html"
  1415. title="previous chapter">Curses Programming with Python</a></p>
  1416. </div>
  1417. <div>
  1418. <h4>Next topic</h4>
  1419. <p class="topless"><a href="gdb_helpers.html"
  1420. title="next chapter">Debugging C API extensions and CPython Internals with GDB</a></p>
  1421. </div>
  1422. <div role="note" aria-label="source link">
  1423. <h3>This Page</h3>
  1424. <ul class="this-page-menu">
  1425. <li><a href="../bugs.html">Report a Bug</a></li>
  1426. <li>
  1427. <a href="https://github.com/python/cpython/blob/main/Doc/howto/descriptor.rst"
  1428. rel="nofollow">Show Source
  1429. </a>
  1430. </li>
  1431. </ul>
  1432. </div>
  1433. </div>
  1434. <div id="sidebarbutton" title="Collapse sidebar">
  1435. <span>«</span>
  1436. </div>
  1437. </div>
  1438. <div class="clearer"></div>
  1439. </div>
  1440. <div class="related" role="navigation" aria-label="related navigation">
  1441. <h3>Navigation</h3>
  1442. <ul>
  1443. <li class="right" style="margin-right: 10px">
  1444. <a href="../genindex.html" title="General Index"
  1445. >index</a></li>
  1446. <li class="right" >
  1447. <a href="../py-modindex.html" title="Python Module Index"
  1448. >modules</a> |</li>
  1449. <li class="right" >
  1450. <a href="gdb_helpers.html" title="Debugging C API extensions and CPython Internals with GDB"
  1451. >next</a> |</li>
  1452. <li class="right" >
  1453. <a href="curses.html" title="Curses Programming with Python"
  1454. >previous</a> |</li>
  1455. <li><img src="../_static/py.svg" alt="Python logo" style="vertical-align: middle; margin-top: -1px"/></li>
  1456. <li><a href="https://www.python.org/">Python</a> &#187;</li>
  1457. <li class="switchers">
  1458. <div class="language_switcher_placeholder"></div>
  1459. <div class="version_switcher_placeholder"></div>
  1460. </li>
  1461. <li>
  1462. </li>
  1463. <li id="cpython-language-and-version">
  1464. <a href="../index.html">3.12.3 Documentation</a> &#187;
  1465. </li>
  1466. <li class="nav-item nav-item-1"><a href="index.html" >Python HOWTOs</a> &#187;</li>
  1467. <li class="nav-item nav-item-this"><a href="">Descriptor Guide</a></li>
  1468. <li class="right">
  1469. <div class="inline-search" role="search">
  1470. <form class="inline-search" action="../search.html" method="get">
  1471. <input placeholder="Quick search" aria-label="Quick search" type="search" name="q" id="search-box" />
  1472. <input type="submit" value="Go" />
  1473. </form>
  1474. </div>
  1475. |
  1476. </li>
  1477. <li class="right">
  1478. <label class="theme-selector-label">
  1479. Theme
  1480. <select class="theme-selector" oninput="activateTheme(this.value)">
  1481. <option value="auto" selected>Auto</option>
  1482. <option value="light">Light</option>
  1483. <option value="dark">Dark</option>
  1484. </select>
  1485. </label> |</li>
  1486. </ul>
  1487. </div>
  1488. <div class="footer">
  1489. &copy;
  1490. <a href="../copyright.html">
  1491. Copyright
  1492. </a>
  1493. 2001-2024, Python Software Foundation.
  1494. <br />
  1495. This page is licensed under the Python Software Foundation License Version 2.
  1496. <br />
  1497. Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
  1498. <br />
  1499. See <a href="/license.html">History and License</a> for more information.<br />
  1500. <br />
  1501. The Python Software Foundation is a non-profit corporation.
  1502. <a href="https://www.python.org/psf/donations/">Please donate.</a>
  1503. <br />
  1504. <br />
  1505. Last updated on Apr 09, 2024 (13:47 UTC).
  1506. <a href="/bugs.html">Found a bug</a>?
  1507. <br />
  1508. Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 7.2.6.
  1509. </div>
  1510. </body>
  1511. </html>
上海开阖软件有限公司 沪ICP备12045867号-1