- Notifications
You must be signed in to change notification settings - Fork 54
/
Copy pathSpecial_Methods.html
489 lines (441 loc) · 43.6 KB
/
Special_Methods.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
<!DOCTYPE html>
<htmlclass="writer-html5" lang="en" >
<head>
<metacharset="utf-8" /><metacontent="Topic: Controlling behavior with special methods, Difficulty: Medium, Category: Section" name="description" />
<metacontent="dunder method, special method, operator overload, repr, getitem, custom syntax, __init__" name="keywords" />
<metaname="viewport" content="width=device-width, initial-scale=1.0" />
<title>Special Methods — Python Like You Mean It</title>
<linkrel="stylesheet" href="../_static/pygments.css" type="text/css" />
<linkrel="stylesheet" href="../_static/css/theme.css" type="text/css" />
<linkrel="stylesheet" href="../_static/my_theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="../_static/js/html5shiv.min.js"></script>
<![endif]-->
<scriptdata-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<scriptsrc="../_static/jquery.js"></script>
<scriptsrc="../_static/underscore.js"></script>
<scriptsrc="../_static/doctools.js"></script>
<scriptasync="async" src="https://www.googletagmanager.com/gtag/js?id=UA-115029372-1"></script>
<scriptsrc="../_static/gtag.js"></script>
<scriptcrossorigin="anonymous" integrity="sha256-Ae2Vz/4ePdIu6ZyI/5ZGsYnb+m0JlOmKPjt6XZ9JJkA=" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"></script>
<script>window.MathJax={"tex": {"inlineMath": [["$","$"],["\\(","\\)"]],"processEscapes": true},"options": {"ignoreHtmlClass": "tex2jax_ignore|mathjax_ignore|document","processHtmlClass": "tex2jax_process|mathjax_process|math|output_area"}}</script>
<scriptdefer="defer" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<scriptsrc="../_static/js/theme.js"></script>
<linkrel="index" title="Index" href="../genindex.html" />
<linkrel="search" title="Search" href="../search.html" />
<linkrel="next" title="Inheritance" href="Inheritance.html" />
<linkrel="prev" title="Applications of Object Oriented Programming" href="Applications_of_OOP.html" />
</head>
<bodyclass="wy-body-for-nav">
<divclass="wy-grid-for-nav">
<navdata-toggle="wy-nav-shift" class="wy-nav-side">
<divclass="wy-side-scroll">
<divclass="wy-side-nav-search" >
<ahref="../index.html" class="icon icon-home"> Python Like You Mean It
</a>
<divclass="version">
1.4
</div>
<divrole="search">
<formid="rtd-search-form" class="wy-form" action="../search.html" method="get">
<inputtype="text" name="q" placeholder="Search docs" />
<inputtype="hidden" name="check_keywords" value="yes" />
<inputtype="hidden" name="area" value="default" />
</form>
</div>
</div><divclass="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<pclass="caption" role="heading"><spanclass="caption-text">Table of Contents:</span></p>
<ulclass="current">
<liclass="toctree-l1"><aclass="reference internal" href="../intro.html">Python Like You Mean It</a></li>
<liclass="toctree-l1"><aclass="reference internal" href="../module_1.html">Module 1: Getting Started with Python</a></li>
<liclass="toctree-l1"><aclass="reference internal" href="../module_2.html">Module 2: The Essentials of Python</a></li>
<liclass="toctree-l1"><aclass="reference internal" href="../module_2_problems.html">Module 2: Problems</a></li>
<liclass="toctree-l1"><aclass="reference internal" href="../module_3.html">Module 3: The Essentials of NumPy</a></li>
<liclass="toctree-l1"><aclass="reference internal" href="../module_3_problems.html">Module 3: Problems</a></li>
<liclass="toctree-l1 current"><aclass="reference internal" href="../module_4.html">Module 4: Object Oriented Programming</a><ulclass="current">
<liclass="toctree-l2"><aclass="reference internal" href="Introduction_to_OOP.html">Introduction to Object Oriented Programming</a></li>
<liclass="toctree-l2"><aclass="reference internal" href="ClassDefinition.html">Defining a New Class of Object</a></li>
<liclass="toctree-l2"><aclass="reference internal" href="ClassInstances.html">Instances of a Class</a></li>
<liclass="toctree-l2"><aclass="reference internal" href="Brief_Review.html">A Brief Summary of Terms and Concepts</a></li>
<liclass="toctree-l2"><aclass="reference internal" href="Methods.html">Methods</a></li>
<liclass="toctree-l2"><aclass="reference internal" href="Applications_of_OOP.html">Applications of Object Oriented Programming</a></li>
<liclass="toctree-l2 current"><aclass="current reference internal" href="#">Special Methods</a><ul>
<liclass="toctree-l3"><aclass="reference internal" href="#String-Representations-of-Objects">String-Representations of Objects</a></li>
<liclass="toctree-l3"><aclass="reference internal" href="#Interfacing-with-Mathematical-Operators">Interfacing with Mathematical Operators</a></li>
<liclass="toctree-l3"><aclass="reference internal" href="#Creating-a-Container-Like-Class">Creating a Container-Like Class</a></li>
<liclass="toctree-l3"><aclass="reference internal" href="#Links-to-Official-Documentation">Links to Official Documentation</a></li>
</ul>
</li>
<liclass="toctree-l2"><aclass="reference internal" href="Inheritance.html">Inheritance</a></li>
</ul>
</li>
<liclass="toctree-l1"><aclass="reference internal" href="../module_5.html">Module 5: Odds and Ends</a></li>
<liclass="toctree-l1"><aclass="reference internal" href="../changes.html">Changelog</a></li>
</ul>
</div>
</div>
</nav>
<sectiondata-toggle="wy-nav-shift" class="wy-nav-content-wrap"><navclass="wy-nav-top" aria-label="Mobile navigation menu" >
<idata-toggle="wy-nav-top" class="fa fa-bars"></i>
<ahref="../index.html">Python Like You Mean It</a>
</nav>
<divclass="wy-nav-content">
<divclass="rst-content">
<divrole="navigation" aria-label="Page navigation">
<ulclass="wy-breadcrumbs">
<li><ahref="../index.html" class="icon icon-home"></a> »</li>
<li><ahref="../module_4.html">Module 4: Object Oriented Programming</a> »</li>
<li>Special Methods</li>
<liclass="wy-breadcrumbs-aside">
<ahref="../_sources/Module4_OOP/Special_Methods.md.txt" rel="nofollow"> View page source</a>
</li>
</ul>
<hr/>
</div>
<divrole="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<divitemprop="articleBody">
<style>
/* CSS overrides for sphinx_rtd_theme */
/* 24px margin */
.nbinput.nblast.container,
.nboutput.nblast.container {
margin-bottom:19px; /* padding has already 5px */
}
/* ... except between code cells! */
.nblast.container+ .nbinput.container {
margin-top:-19px;
}
.admonition>p:before {
margin-right:4px; /* make room for the exclamation icon */
}
/* Fix math alignment, see https://github.com/rtfd/sphinx_rtd_theme/pull/686 */
.math {
text-align: unset;
}
</style>
<divclass="section" id="Special-Methods">
<h1>Special Methods<aclass="headerlink" href="#Special-Methods" title="Permalink to this headline"></a></h1>
<p>In this section, we will learn about a variety of instance methods that are reserved by Python, which affect an object’s high level behavior and its interactions with operators. These are known as special methods. <codeclass="docutils literal notranslate"><spanclass="pre">__init__</span></code> is an example of a special method; recall that it controls the process of creating instances of a class. Similarly, we will see that <codeclass="docutils literal notranslate"><spanclass="pre">__add__</span></code> controls the behavior of an object when it is operated on by the <codeclass="docutils literal notranslate"><spanclass="pre">+</span></code> symbol, for example. In general, the names of special
methods take the form of <codeclass="docutils literal notranslate"><spanclass="pre">__<name>__</span></code>, where the two underscores preceed and succeed the name. Accordingly, special methods can also be referred to as “dunder” (double-underscore) methods. Learning to leverage special methods will enable us to design elegant and powerful classes of objects.</p>
<p>These methods give us complete control over the various high-level interfaces that we use to interact with objects. Let’s make a simple class with nonsensical behavior to demonstrate our ability to shape how our class behaves:</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># Demonstrating (mis)use of special methods</span>
<spanclass="k">class</span><spanclass="nc">SillyClass</span><spanclass="p">:</span>
<spanclass="k">def</span><spanclass="fm">__getitem__</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="n">key</span><spanclass="p">):</span>
<spanclass="sd">""" Determines behavior of `self[key]` """</span>
<spanclass="k">return</span><spanclass="p">[</span><spanclass="kc">True</span><spanclass="p">,</span><spanclass="kc">False</span><spanclass="p">,</span><spanclass="kc">True</span><spanclass="p">,</span><spanclass="kc">False</span><spanclass="p">]</span>
<spanclass="k">def</span><spanclass="fm">__pow__</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="n">other</span><spanclass="p">):</span>
<spanclass="sd">""" Determines behavior of `self ** other` """</span>
<spanclass="k">return</span><spanclass="s2">"Python Like You Mean It"</span>
</pre></div>
</div>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="gp">>>> </span><spanclass="n">silly</span><spanclass="o">=</span><spanclass="n">SillyClass</span><spanclass="p">()</span>
<spanclass="gp">>>> </span><spanclass="n">silly</span><spanclass="p">[</span><spanclass="kc">None</span><spanclass="p">]</span>
<spanclass="go">[True, False, True, False]</span>
<spanclass="gp">>>> </span><spanclass="n">silly</span><spanclass="o">**</span><spanclass="mi">2</span>
<spanclass="go">'Python Like You Mean It'</span>
</pre></div>
</div>
<p>This section is not meant to be a comprehensive treatment of special methods, which would require us to reach beyond our desired level of sophistication. The <aclass="reference external" href="https://docs.python.org/3/reference/datamodel.html#special-method-names">official Python documentation</a> provides a rigorous but somewhat inaccessible treatment of special methods. <aclass="reference external" href="http://www.diveintopython3.net/special-method-names.html">Dive into Python 3</a> has an excellent appendix on special methods. It is strongly recommended
that readers consult this resource.</p>
<divclass="section" id="String-Representations-of-Objects">
<h2>String-Representations of Objects<aclass="headerlink" href="#String-Representations-of-Objects" title="Permalink to this headline"></a></h2>
<p>The following methods determines how an object should be represented as a string in various contexts. For example, this text consistently utilizes the fact that passing an object to the Python console will prompt the console to print out a representation of that object as a string. That is,</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="gp">>>> </span><spanclass="n">x</span><spanclass="o">=</span><spanclass="nb">list</span><spanclass="p">((</span><spanclass="s2">"a"</span><spanclass="p">,</span><spanclass="mi">1</span><spanclass="p">,</span><spanclass="kc">True</span><spanclass="p">))</span>
<spanclass="gp">>>> </span><spanclass="n">x</span>
<spanclass="go">['a', 1, True]</span>
</pre></div>
</div>
<p>Under the hood, the special method <codeclass="docutils literal notranslate"><spanclass="pre">x.__repr__</span></code> is being called to obtain this string representation whenever an object is displayed in a console/notebook like this. The method returns the string <codeclass="docutils literal notranslate"><spanclass="pre">"['a',</span><spanclass="pre">1,</span><spanclass="pre">True]"</span></code>, which is then printed out to the console. This is an extremely useful for creating classes whose objects can be inspected conveniently in a Python console or in a Jupyter notebook. Similarly <codeclass="docutils literal notranslate"><spanclass="pre">__str__</span></code> returns the string that will be produced when <codeclass="docutils literal notranslate"><spanclass="pre">str</span></code> is called on the
object.</p>
<tableclass="docutils align-default">
<colgroup>
<colstyle="width: 33%" />
<colstyle="width: 33%" />
<colstyle="width: 33%" />
</colgroup>
<thead>
<trclass="row-odd"><thclass="head"><p>Method</p></th>
<thclass="head"><p>Signature</p></th>
<thclass="head"><p>Explanation</p></th>
</tr>
</thead>
<tbody>
<trclass="row-even"><td><p>Returns string for a printable representation of object</p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">__repr__(self)</span></code></p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">repr(x)</span></code> invokes <codeclass="docutils literal notranslate"><spanclass="pre">x.__repr__()</span></code>, this is also invoked when an object is returned by a console</p></td>
</tr>
<trclass="row-odd"><td><p>Returns string representation of an object</p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">__str__(self)</span></code></p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">str(x)</span></code> invokes <codeclass="docutils literal notranslate"><spanclass="pre">x.__str__()</span></code></p></td>
</tr>
</tbody>
</table>
<p>A well-implemented <codeclass="docutils literal notranslate"><spanclass="pre">__repr__</span></code> method can greatly improve the convenience of working with a class. For example, let’s add this method to our <codeclass="docutils literal notranslate"><spanclass="pre">ShoppingList</span></code> class that we wrote in the preceding section; the <codeclass="docutils literal notranslate"><spanclass="pre">__repr__</span></code> will create a string with our shopping items on a bulleted list with purchased items crossed out:</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="k">def</span><spanclass="nf">strike</span><spanclass="p">(</span><spanclass="n">text</span><spanclass="p">):</span>
<spanclass="sd">""" Renders string with strike-through characters through it.</span>
<spanclass="sd"> `strike('hello world')` -> '̶h̶e̶l̶l̶o̶ ̶w̶o̶r̶l̶d'</span>
<spanclass="sd"> Notes</span>
<spanclass="sd"> -----</span>
<spanclass="sd"> \u0336 is a special strike-through unicode character; it</span>
<spanclass="sd"> is not unique to Python."""</span>
<spanclass="k">return</span><spanclass="s1">''</span><spanclass="o">.</span><spanclass="n">join</span><spanclass="p">(</span><spanclass="s1">'</span><spanclass="se">\u0336</span><spanclass="si">{}</span><spanclass="s1">'</span><spanclass="o">.</span><spanclass="n">format</span><spanclass="p">(</span><spanclass="n">c</span><spanclass="p">)</span><spanclass="k">for</span><spanclass="n">c</span><spanclass="ow">in</span><spanclass="n">text</span><spanclass="p">)</span>
<spanclass="k">class</span><spanclass="nc">ShoppingList</span><spanclass="p">:</span>
<spanclass="k">def</span><spanclass="fm">__init__</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="n">items</span><spanclass="p">):</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_needed</span><spanclass="o">=</span><spanclass="nb">set</span><spanclass="p">(</span><spanclass="n">items</span><spanclass="p">)</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_purchased</span><spanclass="o">=</span><spanclass="nb">set</span><spanclass="p">()</span>
<spanclass="k">def</span><spanclass="fm">__repr__</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">):</span>
<spanclass="sd">""" Returns formatted shopping list as a string with</span>
<spanclass="sd"> purchased items being crossed out.</span>
<spanclass="sd"> Returns</span>
<spanclass="sd"> -------</span>
<spanclass="sd"> str"""</span>
<spanclass="k">if</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_needed</span><spanclass="ow">or</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_purchased</span><spanclass="p">:</span>
<spanclass="n">remaining_items</span><spanclass="o">=</span><spanclass="p">[</span><spanclass="nb">str</span><spanclass="p">(</span><spanclass="n">i</span><spanclass="p">)</span><spanclass="k">for</span><spanclass="n">i</span><spanclass="ow">in</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_needed</span><spanclass="p">]</span>
<spanclass="n">purchased_items</span><spanclass="o">=</span><spanclass="p">[</span><spanclass="n">strike</span><spanclass="p">(</span><spanclass="nb">str</span><spanclass="p">(</span><spanclass="n">i</span><spanclass="p">))</span><spanclass="k">for</span><spanclass="n">i</span><spanclass="ow">in</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_purchased</span><spanclass="p">]</span>
<spanclass="c1"># You wont find the • character on your keyboard. I simply</span>
<spanclass="c1"># googled "unicode bullet point" and copied/pasted it here.</span>
<spanclass="k">return</span><spanclass="s2">"• "</span><spanclass="o">+</span><spanclass="s2">"</span><spanclass="se">\n</span><spanclass="s2">• "</span><spanclass="o">.</span><spanclass="n">join</span><spanclass="p">(</span><spanclass="n">remaining_items</span><spanclass="o">+</span><spanclass="n">purchased_items</span><spanclass="p">)</span>
<spanclass="k">def</span><spanclass="nf">add_new_items</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="n">items</span><spanclass="p">):</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_needed</span><spanclass="o">.</span><spanclass="n">update</span><spanclass="p">(</span><spanclass="n">items</span><spanclass="p">)</span>
<spanclass="k">def</span><spanclass="nf">mark_purchased_items</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="n">items</span><spanclass="p">):</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_purchased</span><spanclass="o">.</span><spanclass="n">update</span><spanclass="p">(</span><spanclass="nb">set</span><spanclass="p">(</span><spanclass="n">items</span><spanclass="p">)</span><spanclass="o">&</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_needed</span><spanclass="p">)</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_needed</span><spanclass="o">.</span><spanclass="n">difference_update</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_purchased</span><spanclass="p">)</span>
</pre></div>
</div>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span># demonstrating `ShoppingList.__repr__`
>>> l = ShoppingList(["grapes", "beets", "apples", "milk", "melon", "coffee"])
>>> l.mark_purchased_items(["grapes", "beets", "milk"])
>>> l
• melon
• apples
• coffee
• ̶g̶r̶a̶p̶e̶s
• ̶m̶i̶l̶k
• ̶b̶e̶e̶t̶s
</pre></div>
</div>
<p>See that this simple method makes it much easier for us to inspect the state of our shopping list when we are working in a console/notebook environment.</p>
</div>
<divclass="section" id="Interfacing-with-Mathematical-Operators">
<h2>Interfacing with Mathematical Operators<aclass="headerlink" href="#Interfacing-with-Mathematical-Operators" title="Permalink to this headline"></a></h2>
<p>The following special methods control how an object interacts with <codeclass="docutils literal notranslate"><spanclass="pre">+</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">*</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">**</span></code>, and other mathematical operators. A full listing of all the special methods used to emulate numeric types can be found <aclass="reference external" href="https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types">here</a></p>
<tableclass="docutils align-default">
<colgroup>
<colstyle="width: 13%" />
<colstyle="width: 38%" />
<colstyle="width: 50%" />
</colgroup>
<thead>
<trclass="row-odd"><thclass="head"><p>Method</p></th>
<thclass="head"><p>Signature</p></th>
<thclass="head"><p>Explanation</p></th>
</tr>
</thead>
<tbody>
<trclass="row-even"><td><p>Add</p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">__add__(self,</span><spanclass="pre">other)</span></code></p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">x</span><spanclass="pre">+</span><spanclass="pre">y</span></code> invokes <codeclass="docutils literal notranslate"><spanclass="pre">x.__add__(y)</span></code></p></td>
</tr>
<trclass="row-odd"><td><p>Subtract</p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">__sub__(self,</span><spanclass="pre">other)</span></code></p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">x</span><spanclass="pre">-</span><spanclass="pre">y</span></code> invokes <codeclass="docutils literal notranslate"><spanclass="pre">x.__sub__(y)</span></code></p></td>
</tr>
<trclass="row-even"><td><p>Multiply</p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">__mul__(self,</span><spanclass="pre">other)</span></code></p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">x</span><spanclass="pre">*</span><spanclass="pre">y</span></code> invokes <codeclass="docutils literal notranslate"><spanclass="pre">x.__mul__(y)</span></code></p></td>
</tr>
<trclass="row-odd"><td><p>Divide</p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">__truediv__(self,</span><spanclass="pre">other)</span></code></p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">x</span><spanclass="pre">/</span><spanclass="pre">y</span></code> invokes <codeclass="docutils literal notranslate"><spanclass="pre">x.__truediv__(y)</span></code></p></td>
</tr>
<trclass="row-even"><td><p>Power</p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">__pow__(self,</span><spanclass="pre">other)</span></code></p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">x</span><spanclass="pre">**</span><spanclass="pre">y</span></code> invokes <codeclass="docutils literal notranslate"><spanclass="pre">x.__pow__(y)</span></code></p></td>
</tr>
</tbody>
</table>
<p>You may be wondering why division has the peculiar name <codeclass="docutils literal notranslate"><spanclass="pre">__truediv__</span></code>, whereas the other operators have more sensible names. This is an artifact of the transition from Python 2 to Python 3; <aclass="reference external" href="http://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Basic_Objects.html#Number-Types">the default integer-division was replaced by float-division</a>, and thus <codeclass="docutils literal notranslate"><spanclass="pre">__div__</span></code> was replaced by <codeclass="docutils literal notranslate"><spanclass="pre">__truediv__</span></code> for the sake of 2-3 compatibility.</p>
<p>Let’s give <codeclass="docutils literal notranslate"><spanclass="pre">ShoppingList</span></code> an <codeclass="docutils literal notranslate"><spanclass="pre">__add__</span></code> method so that we can merge shopping lists using the <codeclass="docutils literal notranslate"><spanclass="pre">+</span></code> operator. Rather than redefine the entire <codeclass="docutils literal notranslate"><spanclass="pre">ShoppingList</span></code> class, we can simply define this as a function and use <codeclass="docutils literal notranslate"><spanclass="pre">setattr</span></code> to set it as a method to our existing class.</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="k">def</span><spanclass="fm">__add__</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="n">other</span><spanclass="p">):</span>
<spanclass="sd">""" Add the unpurchased and purchased items from another shopping</span>
<spanclass="sd"> list to the present one.</span>
<spanclass="sd"> Parameters</span>
<spanclass="sd"> ----------</span>
<spanclass="sd"> other : ShoppingList</span>
<spanclass="sd"> The shopping list whose items we will add to the present one.</span>
<spanclass="sd"> Returns</span>
<spanclass="sd"> -------</span>
<spanclass="sd"> ShoppingList</span>
<spanclass="sd"> The present shopping list, with items added to it."""</span>
<spanclass="n">new_list</span><spanclass="o">=</span><spanclass="n">ShoppingList</span><spanclass="p">([])</span>
<spanclass="c1"># populate new_list with items from `self` and `other`</span>
<spanclass="k">for</span><spanclass="n">l</span><spanclass="ow">in</span><spanclass="p">[</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="n">other</span><spanclass="p">]:</span>
<spanclass="n">new_list</span><spanclass="o">.</span><spanclass="n">add_new_items</span><spanclass="p">(</span><spanclass="n">l</span><spanclass="o">.</span><spanclass="n">_needed</span><spanclass="p">)</span>
<spanclass="c1"># add purchased items to list, then mark as purchased</span>
<spanclass="n">new_list</span><spanclass="o">.</span><spanclass="n">add_new_items</span><spanclass="p">(</span><spanclass="n">l</span><spanclass="o">.</span><spanclass="n">_purchased</span><spanclass="p">)</span>
<spanclass="n">new_list</span><spanclass="o">.</span><spanclass="n">mark_purchased_items</span><spanclass="p">(</span><spanclass="n">l</span><spanclass="o">.</span><spanclass="n">_purchased</span><spanclass="p">)</span>
<spanclass="k">return</span><spanclass="n">new_list</span>
</pre></div>
</div>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># set `__add__` as a method of `ShoppingList`</span>
<spanclass="o">>>></span><spanclass="nb">setattr</span><spanclass="p">(</span><spanclass="n">ShoppingList</span><spanclass="p">,</span><spanclass="s2">"__add__"</span><spanclass="p">,</span><spanclass="fm">__add__</span><spanclass="p">)</span>
</pre></div>
</div>
<p>Now let’s create a few shopping lists and combine them:</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="gp">>>> </span><spanclass="n">food</span><spanclass="o">=</span><spanclass="n">ShoppingList</span><spanclass="p">([</span><spanclass="s2">"milk"</span><spanclass="p">,</span><spanclass="s2">"flour"</span><spanclass="p">,</span><spanclass="s2">"salt"</span><spanclass="p">,</span><spanclass="s2">"eggs"</span><spanclass="p">])</span>
<spanclass="gp">>>> </span><spanclass="n">food</span><spanclass="o">.</span><spanclass="n">mark_purchased_items</span><spanclass="p">([</span><spanclass="s2">"flour"</span><spanclass="p">,</span><spanclass="s2">"salt"</span><spanclass="p">])</span>
<spanclass="gp">>>> </span><spanclass="n">office_supplies</span><spanclass="o">=</span><spanclass="n">ShoppingList</span><spanclass="p">([</span><spanclass="s2">"staples"</span><spanclass="p">,</span><spanclass="s2">"pens"</span><spanclass="p">,</span><spanclass="s2">"pencils"</span><spanclass="p">])</span>
<spanclass="gp">>>> </span><spanclass="n">office_supplies</span><spanclass="o">.</span><spanclass="n">mark_purchased_items</span><spanclass="p">([</span><spanclass="s2">"pencils"</span><spanclass="p">])</span>
<spanclass="gp">>>> </span><spanclass="n">clothes</span><spanclass="o">=</span><spanclass="n">ShoppingList</span><spanclass="p">([</span><spanclass="s2">"t-shirts"</span><spanclass="p">,</span><spanclass="s2">"socks"</span><spanclass="p">])</span>
<spanclass="go"># combine all three shopping lists</span>
<spanclass="gp">>>> </span><spanclass="n">food</span><spanclass="o">+</span><spanclass="n">office_supplies</span><spanclass="o">+</span><spanclass="n">clothes</span>
<spanclass="go">• t-shirts</span>
<spanclass="go">• eggs</span>
<spanclass="go">• pens</span>
<spanclass="go">• milk</span>
<spanclass="go">• staples</span>
<spanclass="go">• socks</span>
<spanclass="go">• ̶f̶l̶o̶u̶r</span>
<spanclass="go">• ̶s̶a̶l̶t</span>
<spanclass="go">• ̶p̶e̶n̶c̶i̶l̶s</span>
</pre></div>
</div>
<p>Overloading the <codeclass="docutils literal notranslate"><spanclass="pre">+</span></code> operator provides us with a sleek interface for merging multiple shopping lists in a sleek, readable way. <codeclass="docutils literal notranslate"><spanclass="pre">food</span><spanclass="pre">+</span><spanclass="pre">office_supplies</span><spanclass="pre">+</span><spanclass="pre">clothes</span></code> is equivalent to calling <codeclass="docutils literal notranslate"><spanclass="pre">(food.__add__(office_supplies)).__add__(clothes)</span></code>. It is obvious that the former expression is far superior.</p>
</div>
<divclass="section" id="Creating-a-Container-Like-Class">
<h2>Creating a Container-Like Class<aclass="headerlink" href="#Creating-a-Container-Like-Class" title="Permalink to this headline"></a></h2>
<p>The following special methods allow us to give our class a container interface, like that of a dictionary, set, or list. An exhaustive listing and discussion of these methods can be found <aclass="reference external" href="https://docs.python.org/3/reference/datamodel.html#emulating-container-types">here</a></p>
<tableclass="docutils align-default">
<colgroup>
<colstyle="width: 33%" />
<colstyle="width: 33%" />
<colstyle="width: 33%" />
</colgroup>
<thead>
<trclass="row-odd"><thclass="head"><p>Method</p></th>
<thclass="head"><p>Signature</p></th>
<thclass="head"><p>Explanation</p></th>
</tr>
</thead>
<tbody>
<trclass="row-even"><td><p>Length</p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">__len__(self)</span></code></p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">len(x)</span></code> invokes <codeclass="docutils literal notranslate"><spanclass="pre">x.__len__()</span></code></p></td>
</tr>
<trclass="row-odd"><td><p>Get Item</p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">__getitem__(self,</span><spanclass="pre">key)</span></code></p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">x[key]</span></code> invokes <codeclass="docutils literal notranslate"><spanclass="pre">x.__getitem__(key)</span></code></p></td>
</tr>
<trclass="row-even"><td><p>Set Item</p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">__setitem__(self,</span><spanclass="pre">key,</span><spanclass="pre">item)</span></code></p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">x[key]</span><spanclass="pre">=</span><spanclass="pre">item</span></code> invokes <codeclass="docutils literal notranslate"><spanclass="pre">x.__setitem__(key,</span><spanclass="pre">item)</span></code></p></td>
</tr>
<trclass="row-odd"><td><p>Contains</p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">__contains__(self,</span><spanclass="pre">item)</span></code></p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">item</span><spanclass="pre">in</span><spanclass="pre">x</span></code> invokes <codeclass="docutils literal notranslate"><spanclass="pre">x.__contains__(item)</span></code></p></td>
</tr>
<trclass="row-even"><td><p>Iterator</p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">__iter__(self)</span></code></p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">iter(x)</span></code> invokes <codeclass="docutils literal notranslate"><spanclass="pre">x.__iter__()</span></code></p></td>
</tr>
<trclass="row-odd"><td><p>Next</p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">__next__(self)</span></code></p></td>
<td><p><codeclass="docutils literal notranslate"><spanclass="pre">next(x)</span></code> invokes <codeclass="docutils literal notranslate"><spanclass="pre">x.__next__()</span></code></p></td>
</tr>
</tbody>
</table>
<p>To get a feel for these methods, let’s create class that implements most aspects of a list’s interface. We will store a list as an attribute of our class to keep track of the contents, but will implement special methods that “echo” the interface of the list.</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="k">class</span><spanclass="nc">MyList</span><spanclass="p">:</span>
<spanclass="k">def</span><spanclass="fm">__init__</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="o">*</span><spanclass="n">args</span><spanclass="p">):</span>
<spanclass="k">if</span><spanclass="nb">len</span><spanclass="p">(</span><spanclass="n">args</span><spanclass="p">)</span><spanclass="o">==</span><spanclass="mi">1</span><spanclass="ow">and</span><spanclass="nb">hasattr</span><spanclass="p">(</span><spanclass="n">args</span><spanclass="p">[</span><spanclass="mi">0</span><spanclass="p">],</span><spanclass="s1">'__iter__'</span><spanclass="p">):</span>
<spanclass="c1"># handles `MyList([1, 2, 3])</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_data</span><spanclass="o">=</span><spanclass="nb">list</span><spanclass="p">(</span><spanclass="n">args</span><spanclass="p">[</span><spanclass="mi">0</span><spanclass="p">])</span>
<spanclass="k">else</span><spanclass="p">:</span>
<spanclass="c1"># handles `MyList(1, 2, 3)`</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_data</span><spanclass="o">=</span><spanclass="nb">list</span><spanclass="p">(</span><spanclass="n">args</span><spanclass="p">)</span>
<spanclass="k">def</span><spanclass="fm">__getitem__</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="n">index</span><spanclass="p">):</span>
<spanclass="n">out</span><spanclass="o">=</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_data</span><spanclass="p">[</span><spanclass="n">index</span><spanclass="p">]</span>
<spanclass="c1"># slicing should return a `MyList` instance</span>
<spanclass="c1"># otherwise, the individual element should be returned as-is</span>
<spanclass="k">return</span><spanclass="n">MyList</span><spanclass="p">(</span><spanclass="n">out</span><spanclass="p">)</span><spanclass="k">if</span><spanclass="nb">isinstance</span><spanclass="p">(</span><spanclass="n">index</span><spanclass="p">,</span><spanclass="nb">slice</span><spanclass="p">)</span><spanclass="k">else</span><spanclass="n">out</span>
<spanclass="k">def</span><spanclass="fm">__setitem__</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="n">key</span><spanclass="p">,</span><spanclass="n">value</span><spanclass="p">):</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_data</span><spanclass="p">[</span><spanclass="n">key</span><spanclass="p">]</span><spanclass="o">=</span><spanclass="n">value</span>
<spanclass="k">def</span><spanclass="fm">__len__</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">):</span>
<spanclass="k">return</span><spanclass="nb">len</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_data</span><spanclass="p">)</span>
<spanclass="k">def</span><spanclass="fm">__repr__</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">):</span>
<spanclass="sd">""" Use the character | as the delimiter for our list"""</span>
<spanclass="c1"># `self._data.__repr__()` returns '[ ... ]',</span>
<spanclass="c1"># thus we can slice to get the contents of the string</span>
<spanclass="c1"># and exclude the square-brackets, and add our own</span>
<spanclass="c1"># delimiters in their place</span>
<spanclass="k">return</span><spanclass="s2">"|"</span><spanclass="o">+</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_data</span><spanclass="o">.</span><spanclass="fm">__repr__</span><spanclass="p">()[</span><spanclass="mi">1</span><spanclass="p">:</span><spanclass="o">-</span><spanclass="mi">1</span><spanclass="p">]</span><spanclass="o">+</span><spanclass="s2">"|"</span>
<spanclass="k">def</span><spanclass="fm">__contains__</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="n">item</span><spanclass="p">):</span>
<spanclass="k">return</span><spanclass="n">item</span><spanclass="ow">in</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_data</span>
<spanclass="k">def</span><spanclass="nf">append</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="n">item</span><spanclass="p">):</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_data</span><spanclass="o">.</span><spanclass="n">append</span><spanclass="p">(</span><spanclass="n">item</span><spanclass="p">)</span>
</pre></div>
</div>
<p>Let’s appreciate the rich behavior that we get out of this simple class:</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># MyList can accept any iterable as its</span>
<spanclass="c1"># first (and only) input argument</span>
<spanclass="o">>>></span><spanclass="n">x</span><spanclass="o">=</span><spanclass="n">MyList</span><spanclass="p">(</span><spanclass="s2">"hello"</span><spanclass="p">)</span>
<spanclass="o">>>></span><spanclass="n">x</span>
<spanclass="o">|</span><spanclass="s1">'h'</span><spanclass="p">,</span><spanclass="s1">'e'</span><spanclass="p">,</span><spanclass="s1">'l'</span><spanclass="p">,</span><spanclass="s1">'l'</span><spanclass="p">,</span><spanclass="s1">'o'</span><spanclass="o">|</span>
<spanclass="c1"># MyList accepts an arbitrary number of arguments</span>
<spanclass="o">>>></span><spanclass="n">x</span><spanclass="o">=</span><spanclass="n">MyList</span><spanclass="p">(</span><spanclass="mi">1</span><spanclass="p">,</span><spanclass="mi">2</span><spanclass="p">,</span><spanclass="mi">3</span><spanclass="p">,</span><spanclass="mi">4</span><spanclass="p">,</span><spanclass="mi">5</span><spanclass="p">)</span>
<spanclass="o">>>></span><spanclass="n">x</span>
<spanclass="o">|</span><spanclass="mi">1</span><spanclass="p">,</span><spanclass="mi">2</span><spanclass="p">,</span><spanclass="mi">3</span><spanclass="p">,</span><spanclass="mi">4</span><spanclass="p">,</span><spanclass="mi">5</span><spanclass="o">|</span>
<spanclass="o">>>></span><spanclass="nb">len</span><spanclass="p">(</span><spanclass="n">x</span><spanclass="p">)</span>
<spanclass="mi">5</span>
<spanclass="c1"># getting an item</span>
<spanclass="o">>>></span><spanclass="n">x</span><spanclass="p">[</span><spanclass="mi">0</span><spanclass="p">]</span>
<spanclass="mi">1</span>
<spanclass="c1"># slicing returns a MyList instance</span>
<spanclass="o">>>></span><spanclass="n">x</span><spanclass="p">[</span><spanclass="mi">2</span><spanclass="p">:</span><spanclass="mi">4</span><spanclass="p">]</span>
<spanclass="o">|</span><spanclass="mi">3</span><spanclass="p">,</span><spanclass="mi">4</span><spanclass="o">|</span>
<spanclass="c1"># setting an item</span>
<spanclass="o">>>></span><spanclass="n">x</span><spanclass="p">[</span><spanclass="mi">0</span><spanclass="p">]</span><spanclass="o">=</span><spanclass="o">-</span><spanclass="mi">1</span>
<spanclass="o">>>></span><spanclass="n">x</span>
<spanclass="o">|-</span><spanclass="mi">1</span><spanclass="p">,</span><spanclass="mi">2</span><spanclass="p">,</span><spanclass="mi">3</span><spanclass="p">,</span><spanclass="mi">4</span><spanclass="p">,</span><spanclass="mi">5</span><spanclass="o">|</span>
<spanclass="c1"># checking membership</span>
<spanclass="o">>>></span><spanclass="mi">10</span><spanclass="ow">in</span><spanclass="n">x</span>
<spanclass="kc">False</span>
<spanclass="o">>>></span><spanclass="n">MyList</span><spanclass="p">()</span>
<spanclass="o">||</span>
</pre></div>
</div>
</div>
<divclass="section" id="Links-to-Official-Documentation">
<h2>Links to Official Documentation<aclass="headerlink" href="#Links-to-Official-Documentation" title="Permalink to this headline"></a></h2>
<ulclass="simple">
<li><p><aclass="reference external" href="https://docs.python.org/3/reference/datamodel.html#special-method-names">Special Methods</a></p></li>
<li><p><aclass="reference external" href="https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types">Emulating Numeric Types</a></p></li>
<li><p><aclass="reference external" href="https://docs.python.org/3/reference/datamodel.html#emulating-container-types">Emulating Container Types</a></p></li>
</ul>
</div>
</div>
</div>
</div>
<footer><divclass="rst-footer-buttons" role="navigation" aria-label="Footer">
<ahref="Applications_of_OOP.html" class="btn btn-neutral float-left" title="Applications of Object Oriented Programming" accesskey="p" rel="prev"><spanclass="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
<ahref="Inheritance.html" class="btn btn-neutral float-right" title="Inheritance" accesskey="n" rel="next">Next <spanclass="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
</div>
<hr/>
<divrole="contentinfo">
<p>© Copyright 2021, Ryan Soklaski.</p>
</div>
Built with <ahref="https://www.sphinx-doc.org/">Sphinx</a> using a
<ahref="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <ahref="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function(){
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>