forked from UWPCE-PythonCert/ProgrammingInPython
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMultipleInheritance.html
More file actions
430 lines (410 loc) · 36.6 KB
/
MultipleInheritance.html
File metadata and controls
430 lines (410 loc) · 36.6 KB
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
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Multiple Inheritance — Programming in Python 7.0 documentation</title>
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="../_static/js/html5shiv.min.js"></script>
<![endif]-->
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="17. Introduction to Functional Programming" href="../topics/17-functional_programming/index.html" />
<link rel="prev" title="16. Multiple Inheritance" href="../topics/16-multiple_inheritance/index.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" style="background: #4b2e83" >
<a href="../index.html">
<img src="../_static/UWPCE_logo_full.png" class="logo" alt="Logo"/>
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Topics in the Program</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../topics/01-setting_up/index.html">1. Setting up your Environment</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/02-basic_python/index.html">2. Basic Python</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/03-recursion_booleans/index.html">3. Booleans and Recursion</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/04-sequences_iteration/index.html">4. Sequences and Iteration</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/05-text_handling/index.html">5. Basic Text Handling</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/06-exceptions/index.html">6. Exception Handling</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/07-unit_testing/index.html">7. Unit Testing</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/08-dicts_sets/index.html">8. Dictionaries and Sets</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/09-files/index.html">9. File Handling</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/10-modules_packages/index.html">10. Modules and Packages</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/11-argument_passing/index.html">11. Advanced Argument Passing</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/12-comprehensions/index.html">12. Comprehensions</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/13-intro_oo/index.html">13. Intro to Object Oriented Programing</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/14-magic_methods/index.html">14. Properties and Magic Methods</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/15-subclassing/index.html">15. Subclassing and Inheritance</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="../topics/16-multiple_inheritance/index.html">16. Multiple Inheritance</a><ul class="current">
<li class="toctree-l2 current"><a class="current reference internal" href="#">Multiple Inheritance</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../topics/17-functional_programming/index.html">17. Introduction to Functional Programming</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/18-advanced_testing/index.html">18. Advanced Testing</a></li>
<li class="toctree-l1"><a class="reference internal" href="../topics/99-extras/index.html">19. Extra Topics</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" style="background: #4b2e83" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../index.html">Programming in Python</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content style-external-links">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../index.html" class="icon icon-home"></a> »</li>
<li><a href="../topics/16-multiple_inheritance/index.html"><span class="section-number">16. </span>Multiple Inheritance</a> »</li>
<li>Multiple Inheritance</li>
<li class="wy-breadcrumbs-aside">
<a href="../_sources/modules/MultipleInheritance.rst.txt" rel="nofollow"> View page source</a>
</li>
</ul><div class="rst-breadcrumbs-buttons" role="navigation" aria-label="Sequential page navigation">
<a href="../topics/16-multiple_inheritance/index.html" class="btn btn-neutral float-left" title="16. Multiple Inheritance" accesskey="p"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
<a href="../topics/17-functional_programming/index.html" class="btn btn-neutral float-right" title="17. Introduction to Functional Programming" accesskey="n">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
</div>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<div class="section" id="multiple-inheritance">
<span id="id1"></span><h1>Multiple Inheritance<a class="headerlink" href="#multiple-inheritance" title="Permalink to this headline"></a></h1>
<div class="section" id="inheriting-from-more-than-one-class">
<h2>Inheriting from more than one class.<a class="headerlink" href="#inheriting-from-more-than-one-class" title="Permalink to this headline"></a></h2>
<div class="section" id="the-mechanics-of-multiple-inheritance">
<h3>The mechanics of multiple inheritance<a class="headerlink" href="#the-mechanics-of-multiple-inheritance" title="Permalink to this headline"></a></h3>
<p>Simply provide more than one parent:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Combined</span><span class="p">(</span><span class="n">Parent1</span><span class="p">,</span> <span class="n">Parent2</span><span class="p">,</span> <span class="n">Parent3</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">something</span><span class="p">,</span> <span class="n">something</span> <span class="k">else</span><span class="p">):</span>
<span class="c1"># some custom initialization here.</span>
<span class="n">Parent1</span><span class="o">.</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="p">)</span>
<span class="n">Parent2</span><span class="o">.</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="p">)</span>
<span class="n">Parent3</span><span class="o">.</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="p">)</span>
<span class="c1"># possibly more custom initialization</span>
</pre></div>
</div>
<p>Calls to the parent class <code class="docutils literal notranslate"><span class="pre">__init__</span></code> are optional and case dependent. (and maybe you can use <code class="docutils literal notranslate"><span class="pre">super()</span></code>…stay tuned)</p>
<p>The Combined class now has ALL the attributes and methods of the multiple parent classes. You can bring a lot of functionality into a class that way.</p>
</div>
<div class="section" id="purpose">
<h3>Purpose<a class="headerlink" href="#purpose" title="Permalink to this headline"></a></h3>
<p>What was the purpose behind inheritance?</p>
<p><em>Code reuse</em></p>
<p>What is the purpose behind multiple inheritance?</p>
<p><em>Code reuse</em></p>
<p>What wasn’t the purpose of inheritance?</p>
<p><em>Building massive class hierarchies for their own sake</em></p>
<p>What isn’t the purpose of multiple inheritance?</p>
<p><em>Building massive class hierarchies for their own sake</em></p>
</div>
<div class="section" id="mix-ins">
<h3>Mix-ins<a class="headerlink" href="#mix-ins" title="Permalink to this headline"></a></h3>
<p>Why would you want to do this?</p>
<p>Hierarchies are not always simple:</p>
<ul class="simple">
<li><p>Animal</p>
<ul>
<li><p>Mammal</p>
<ul>
<li><p>give_birth()</p></li>
</ul>
</li>
<li><p>Bird</p>
<ul>
<li><p>lay_eggs()</p></li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Where do you put a Platypus or Spiny Anteater?</p>
<p><a class="reference external" href="http://www.ucmp.berkeley.edu/mammal/monotreme.html">Egg Laying Mammals</a></p>
<p>“mix-ins” can solve this problem. A mix-in is a class that can’t do anything by itself, but rather, provides functionality that can be mixed into other classes.</p>
<p>In the above contrived example, we could put “give_birth” (and associated methods) in a BirthGiver mixin, and lay_eggs in an EggLayer mixin, and then make our mammals, birds and platypi from them:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Platypus</span><span class="p">(</span><span class="n">Animal</span><span class="p">,</span> <span class="n">EggLayer</span><span class="p">):</span>
<span class="o">...</span>
<span class="k">class</span> <span class="nc">Cat</span><span class="p">(</span><span class="n">Animal</span><span class="p">,</span> <span class="n">BirthGiver</span><span class="p">):</span>
<span class="o">...</span>
<span class="k">class</span> <span class="nc">Duck</span><span class="p">(</span><span class="n">Animal</span><span class="p">,</span> <span class="n">EggLayer</span><span class="p">):</span>
<span class="o">...</span>
</pre></div>
</div>
<p>But this is pretty darn contrived … where do you use these for real?</p>
<p>Here is a nice discussion:</p>
<p><a class="reference external" href="https://andrewbrookins.com/technology/mixins-in-python-and-ruby-compared/">mixins in Python …</a></p>
<p>(Ignore the second part about Ruby…)</p>
<div class="section" id="real-world-example-the-wxpython-floatcanvas">
<h4>Real World Example: The wxPython FloatCanvas:<a class="headerlink" href="#real-world-example-the-wxpython-floatcanvas" title="Permalink to this headline"></a></h4>
<p><a class="reference external" href="https://github.com/wxWidgets/Phoenix/blob/master/wx/lib/floatcanvas/FCObjects.py">https://github.com/wxWidgets/Phoenix/blob/master/wx/lib/floatcanvas/FCObjects.py</a></p>
<p>I had read about mixins quite a while ago, and I thought they were pretty cool. But I couldn’t imagine where I might actually use them.</p>
<p>Then I set out to write FloatCanvas – a scalable, pan-able, object-persistent drawing canvas for the wxPython toolkit.</p>
<p>What I discovered is that the draw objects were not in a clean hierarchy – some objects had a line (like a poly line), some had just a fill (like a dot), some had a fill and outline (polygon), some were defined by a single point (a dot again), some by a bunch of points (polygon), etc….</p>
<p>In order to not write a lot of repeated code – remember, “classes are for code re-use”, I put all the individual bits of functionality into mixin classes, and then simply put them together in different ways.</p>
<p>Once the system was set up, all you needed to write was a <code class="docutils literal notranslate"><span class="pre">__init__</span></code> and a draw method to make a whole new graphic object.</p>
<p>Take a look at the code –quite a bit in the <code class="docutils literal notranslate"><span class="pre">DrawObject</span></code> base class, then a bunch of <code class="docutils literal notranslate"><span class="pre">*Mixin</span></code> classes that define specific functionality.</p>
<p>Now look at the real DrawObject classes, e.g. Line and Polygon. Not much code there:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Polygon</span><span class="p">(</span><span class="n">PointsObjectMixin</span><span class="p">,</span> <span class="n">LineAndFillMixin</span><span class="p">,</span> <span class="n">DrawObject</span><span class="p">):</span>
<span class="o">...</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">_Draw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
<span class="o">...</span>
</pre></div>
</div>
<p>and:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Line</span><span class="p">(</span><span class="n">PointsObjectMixin</span><span class="p">,</span> <span class="n">LineOnlyMixin</span><span class="p">,</span> <span class="n">DrawObject</span><span class="p">):</span>
<span class="o">...</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">_Draw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
<span class="o">...</span>
</pre></div>
</div>
<p>There is some real code in the <code class="docutils literal notranslate"><span class="pre">__init__</span></code> and <code class="docutils literal notranslate"><span class="pre">_Draw</span></code> – but those are still the only two methods that need to be defined to make a fully functional drawobject.</p>
<p>FloatCanvas has a lot of complications with handling mouse events, and managing pens and brushes, and what have you, so a very trimmed down version, using the Python Imaging Library, is here to check out and modify:</p>
<p><a class="reference download internal" download="" href="../_downloads/923431060a2f16b7b6290be15c61e559/object_canvas.py"><code class="xref download docutils literal notranslate"><span class="pre">object_canvas.py</span></code></a></p>
<p>and</p>
<p><a class="reference download internal" download="" href="../_downloads/17291a22f70b7a2b8620b90132af747e/test_object_canvas.py"><code class="xref download docutils literal notranslate"><span class="pre">test_object_canvas.py</span></code></a></p>
<p>This code requires the Python Imaging Library to do the rendering. You can get it by installing the “pillow” package from PyPi:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">pip</span> <span class="n">install</span> <span class="n">pillow</span>
</pre></div>
</div>
<p>Can you add other types of <code class="docutils literal notranslate"><span class="pre">DrawObjects</span></code> ? Maybe a polygon or ??</p>
</div>
</div>
</div>
<div class="section" id="python-s-multiple-inheritance-model">
<h2>Python’s Multiple Inheritance Model<a class="headerlink" href="#python-s-multiple-inheritance-model" title="Permalink to this headline"></a></h2>
<p>Cooperative Multiple Inheritance</p>
<p>Emphasis on cooperative!</p>
<ul class="simple">
<li><p>Play by the rules and everybody benefits (parents, descendants).</p></li>
<li><p>Play by the rules and nobody gets hurt (yourself, mostly).</p></li>
<li><p>We’re all adults here.</p></li>
</ul>
<p>What could go wrong?</p>
<div class="section" id="the-diamond-problem">
<h3>The Diamond Problem<a class="headerlink" href="#the-diamond-problem" title="Permalink to this headline"></a></h3>
<p>In Python, everything is descended from ‘object’. Thus, the moment you invoke multiple inheritance you have the diamond problem.</p>
<p><a class="reference external" href="https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem">https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem</a></p>
<p>Here is a toy Python example:</p>
<p><a class="reference download internal" download="" href="../_downloads/edc82bdb8cb562b0b64c990a7e50fd15/diamond.py"><code class="xref download docutils literal notranslate"><span class="pre">diamond.py</span></code></a></p>
<p>Take a look at that code – run it, and notice that class <code class="docutils literal notranslate"><span class="pre">A</span></code>’s method gets run twice. Make sure you know why it is doing what it is doing.</p>
</div>
<div class="section" id="super">
<h3><code class="docutils literal notranslate"><span class="pre">super()</span></code><a class="headerlink" href="#super" title="Permalink to this headline"></a></h3>
<p><code class="docutils literal notranslate"><span class="pre">super()</span></code> can help.</p>
<p><code class="docutils literal notranslate"><span class="pre">super()</span></code>: use it to call a superclass method, rather than explicitly calling the unbound method on the superclass.</p>
<p>instead of:</p>
<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><span class="n">B</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="n">B</span><span class="o">.</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">argw</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="o">...</span>
</pre></div>
</div>
<p>You can do:</p>
<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><span class="n">B</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</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>
<span class="o">...</span>
</pre></div>
</div>
</div>
<div class="section" id="mro-method-resolution-order">
<h3>MRO: Method Resolution Order<a class="headerlink" href="#mro-method-resolution-order" title="Permalink to this headline"></a></h3>
<p>How does python decide which method to call, when multiple superclasses may have the <em>same</em> method ?</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Combined</span><span class="p">(</span><span class="n">Super1</span><span class="p">,</span> <span class="n">Super2</span><span class="p">,</span> <span class="n">Super3</span><span class="p">)</span>
</pre></div>
</div>
<p>Attributes are located bottom-to-top, left-to-right</p>
<ul class="simple">
<li><p>Is it an instance attribute ?</p></li>
<li><p>Is it a class attribute ?</p></li>
<li><p>Is it a superclass attribute ?</p>
<ul>
<li><p>Is it an attribute of the left-most superclass?</p></li>
<li><p>Is it an attribute of the next superclass?</p></li>
<li><p>and so on up the hierarchy…</p></li>
</ul>
</li>
<li><p>Is it a super-superclass attribute ?</p></li>
<li><p>… also left to right …</p></li>
</ul>
<p><a class="reference external" href="http://python-history.blogspot.com/2010/06/method-resolution-order.html">http://python-history.blogspot.com/2010/06/method-resolution-order.html</a></p>
</div>
<div class="section" id="super-s-superpowers">
<h3>Super’s Superpowers<a class="headerlink" href="#super-s-superpowers" title="Permalink to this headline"></a></h3>
<p>The above system is clear when the hierarchy is simple – but when you have the “diamond problem” – or even more compexity, we need somethign smarter. Enter <code class="docutils literal notranslate"><span class="pre">super()</span></code>.</p>
<p><code class="docutils literal notranslate"><span class="pre">super</span></code> works out – dynamically at runtime – which classes are in the delegation order.</p>
<p>Do not be afraid. And be very afraid.</p>
</div>
<div class="section" id="what-does-super-do">
<h3>What does super() do?<a class="headerlink" href="#what-does-super-do" title="Permalink to this headline"></a></h3>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ChildB</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">mro</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="o">.</span><span class="n">mro</span><span class="p">()</span>
<span class="k">for</span> <span class="n">next_class</span> <span class="ow">in</span> <span class="n">mro</span><span class="p">[</span><span class="n">mro</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">ChildB</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">:]:</span> <span class="c1"># slice to end</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">next_class</span><span class="p">,</span> <span class="s1">'__init__'</span><span class="p">):</span>
<span class="n">next_class</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="k">break</span>
</pre></div>
</div>
<p><a class="reference external" href="http://stackoverflow.com/questions/576169/understanding-python-super-with-init-methods">http://stackoverflow.com/questions/576169/understanding-python-super-with-init-methods</a></p>
<p><code class="docutils literal notranslate"><span class="pre">super</span></code> returns a “proxy object” that delegates method calls.</p>
<p>It’s not returning the object itself – but you can call methods on it as though it were a class object.</p>
<p>It runs through the method resolution order (MRO) to find the method
you call.</p>
<p>Key point: the MRO is determined <em>at run time</em></p>
<p><a class="reference external" href="https://docs.python.org/3.6/library/functions.html#super">https://docs.python.org/3.6/library/functions.html#super</a></p>
<p>But it’s not as simple as finding and calling the first superclass method it finds: <code class="docutils literal notranslate"><span class="pre">super()</span></code> will call all the sibling superclass methods:</p>
<p>Here is an example of a class that inherits from three superclasses:</p>
<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><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">A</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
</pre></div>
</div>
<p>Since you have called __init__ on the <code class="docutils literal notranslate"><span class="pre">super()</span></code> object, this is essentially the same as calling all three super class <code class="docutils literal notranslate"><span class="pre">__init__</span></code> methods:</p>
<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><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">A</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">C</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
<span class="n">B</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
<span class="n">A</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
</pre></div>
</div>
<p>Keep in mind that <code class="docutils literal notranslate"><span class="pre">super()</span></code> can be used for any method, not just <code class="docutils literal notranslate"><span class="pre">__init__</span></code> – while you usually <em>do</em> want to initiallize all the superclasses, you may not want to call the same method on every superclass if it’s a more specialized method.</p>
<p>But if you do, it’s kind of handy.</p>
</div>
</div>
<div class="section" id="using-super">
<h2>Using <code class="docutils literal notranslate"><span class="pre">super()</span></code><a class="headerlink" href="#using-super" title="Permalink to this headline"></a></h2>
<div class="section" id="the-rules">
<h3>The rules:<a class="headerlink" href="#the-rules" title="Permalink to this headline"></a></h3>
<p>Raymond Hettinger’s rules for <code class="docutils literal notranslate"><span class="pre">super()</span></code></p>
<ol class="arabic simple">
<li><p>The method being called by super() needs to exist</p></li>
<li><p>The caller and callee need to have a matching argument signature</p></li>
<li><p>Every occurrence of the method needs to use super()</p></li>
</ol>
<ol class="arabic simple">
<li><p>Is pretty obvious :-)</p></li>
<li><p>We’ll get into in a moment</p></li>
<li><p>This is a tricky one – you just need to remember it. What it means is that, for instance, if you are using super() to call <code class="docutils literal notranslate"><span class="pre">__init__</span></code> in the superclass(es), then all the superclasses <code class="docutils literal notranslate"><span class="pre">__init__</span></code> methods must ALSO call it:</p></li>
</ol>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="o">...</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</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>
<span class="o">...</span>
</pre></div>
</div>
<p>Failure to do that will cause odd errors!</p>
<p>This is a bit weird – it means that if you have a method that may get called with a super call, it needs to use super itself, EVEN if it doesn’t need to call the superclass’ method!</p>
<p>See the example later for this…</p>
</div>
<div class="section" id="matching-argument-signature">
<h3>Matching Argument Signature<a class="headerlink" href="#matching-argument-signature" title="Permalink to this headline"></a></h3>
<p>Remember that super does not only delegate to your superclass, it delegates to any class in the MRO.</p>
<p>Therefore you must be prepared to call any other class’s method in the hierarchy and be prepared to be called from any other class’s method.</p>
<p>The general rule is to pass all arguments you received on to the super function.</p>
<p>That means that all the methods with the same name need to be able to accept the same arguments. In some cases, that’s straightforward – they are all the same. But sometimes it gets tricky.</p>
<p>Remember that if you write a function that takes:</p>
<p><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">fun(self,</span> <span class="pre">*args,</span> <span class="pre">**kwargs)</span></code></p>
<p>It can accept ANY arguments. But if you find yourself needing to do that – maybe super isn’t the right thing to use??</p>
<p>But a really common case, particularly for an <code class="docutils literal notranslate"><span class="pre">__init__</span></code>, is for it to take a bunch of keyword arguments. And a subclass may take one or two more, and then want to pass the rest on. So a common pattern is:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Subclass</span><span class="p">(</span><span class="n">Superclass</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">extra_arg1</span><span class="p">,</span> <span class="n">extra_arg2</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>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</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>
</pre></div>
</div>
<p>Now your subclass doesn’t really need to think about all the arguments the superclass can take.</p>
</div>
<div class="section" id="two-seminal-articles">
<h3>Two seminal articles<a class="headerlink" href="#two-seminal-articles" title="Permalink to this headline"></a></h3>
<p>“Super Considered Harmful” – James Knight</p>
<p><a class="reference external" href="https://fuhm.net/super-harmful/">https://fuhm.net/super-harmful/</a></p>
<p>“Super() considered super!” – Raymond Hettinger</p>
<p><a class="reference external" href="http://rhettinger.wordpress.com/2011/05/26/super-considered-super/">http://rhettinger.wordpress.com/2011/05/26/super-considered-super/</a></p>
<p><a class="reference external" href="https://youtu.be/EiOglTERPEo">https://youtu.be/EiOglTERPEo</a></p>
<p>Both perspectives worth your consideration. In fact, they aren’t that different…</p>
<p>Both actually say similar things:</p>
<ul class="simple">
<li><p>The method being called by super() needs to exist</p></li>
<li><p>Every occurrence of the method needs to use super():</p>
<ul>
<li><p>Use it consistently, and document that you use it, as it is part
of the external interface for your class, like it or not.</p></li>
</ul>
</li>
</ul>
<p>If you follow these rules, then it really can be <em>super</em></p>
</div>
<div class="section" id="example">
<h3>Example:<a class="headerlink" href="#example" title="Permalink to this headline"></a></h3>
<p>First, let’s look at the diamond problem again – this time using super:</p>
<p><a class="reference download internal" download="" href="../_downloads/6fc7890d9fea2c802c990aeac9070f85/diamond_super.py"><code class="xref download docutils literal notranslate"><span class="pre">diamond_super.py</span></code></a></p>
<p>in this case, we are using <code class="docutils literal notranslate"><span class="pre">super()</span></code>, rather than specifically calling the methods of the superclasses:</p>
<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><span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">do_your_stuff</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">do_your_stuff</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"doing D's stuff"</span><span class="p">)</span>
</pre></div>
</div>
<p>And when we run it, we see that calling <code class="docutils literal notranslate"><span class="pre">super().do_your_stuff()</span></code> once in D results in the method being called on all the superclasses, with no duplication:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">calling</span> <span class="n">D</span><span class="s1">'s method</span>
<span class="n">doing</span> <span class="n">A</span><span class="s1">'s stuff</span>
<span class="n">doing</span> <span class="n">C</span><span class="s1">'s stuff</span>
<span class="n">doing</span> <span class="sa">B</span><span class="s1">'s stuff</span>
<span class="n">doing</span> <span class="n">D</span><span class="s1">'s stuff</span>
</pre></div>
</div>
</div>
<div class="section" id="some-more-experiments-with-super">
<h3>Some more experiments with <code class="docutils literal notranslate"><span class="pre">super</span></code><a class="headerlink" href="#some-more-experiments-with-super" title="Permalink to this headline"></a></h3>
<p><code class="docutils literal notranslate"><span class="pre">super</span></code> takes a while to wrap your head around – try running the code in:</p>
<p><a class="reference download internal" download="" href="../_downloads/c0f1640b9673725156d0b85a27003d5a/super_test.py"><code class="xref download docutils literal notranslate"><span class="pre">super_test.py</span></code></a></p>
<p>See if you can follow all that!</p>
</div>
</div>
</div>
</div>
</div>
<footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
<a href="../topics/16-multiple_inheritance/index.html" class="btn btn-neutral float-left" title="16. Multiple Inheritance" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
<a href="../topics/17-functional_programming/index.html" class="btn btn-neutral float-right" title="17. Introduction to Functional Programming" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
</div>
<hr/>
<div role="contentinfo">
<p>© Copyright 2020, University of Washington, Natasha Aleksandrova, Christopher Barker, Brian Dorsey, Cris Ewing, Christy Heaton, Jon Jacky, Maria McKinley, Andy Miles, Rick Riehle, Joseph Schilz, Joseph Sheedy, Hosung Song. Creative Commons Attribution-ShareAlike 4.0 license.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>