-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy path3_objects.html
More file actions
980 lines (916 loc) · 108 KB
/
3_objects.html
File metadata and controls
980 lines (916 loc) · 108 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
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
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
<!DOCTYPE html>
<html lang="en" data-content_root="./">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>3. Objects and abstraction — Object-oriented Programming documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="_static/fenics.css?v=8c7d05f9" />
<link rel="stylesheet" type="text/css" href="_static/proof.css" />
<link rel="stylesheet" type="text/css" href="_static/graphviz.css?v=fd3f3429" />
<script src="_static/documentation_options.js?v=5929fcd5"></script>
<script src="_static/doctools.js?v=9a2dae69"></script>
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="_static/proof.js"></script>
<script async="async" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="4. A matter of style" href="4_style.html" />
<link rel="prev" title="2. Programs in files" href="2_programs_in_files.html" />
<!--[if lte IE 6]>
<link rel="stylesheet" href="_static/ie6.css" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-0EFVH5C4DC"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-0EFVH5C4DC');
</script>
<link rel="stylesheet" href="_static/featured.css">
<link rel="shortcut icon" href="_static/icon.ico" />
</head><body>
<div class="wrapper">
<a href="index.html"><img src="_static/banner.png" width="900px" alt="FInAT Project Banner" /></a>
<div id="access">
<div class="menu">
<ul>
<li class="page_item"><a href="index.html" title="Book">Book</a></li>
<li class="page_item"><a href="videos.html" title="Videos">Videos</a></li>
<li class="page_item"><a href="exercises.html"
title="Exercises">Exercises</a></li>
<li class="page_item"><a href="installation.html" title="Installation">Installation</a></li>
</ul>
</div><!-- .menu -->
</div><!-- #access -->
</div><!-- #wrapper -->
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="objects-and-abstraction">
<span id="objects"></span><h1><span class="section-number">3. </span>Objects and abstraction<a class="headerlink" href="#objects-and-abstraction" title="Link to this heading">¶</a></h1>
<p>In this chapter we will take a first look at the representation of
abstract mathematical objects and operations as data objects in a
computer program. We will learn about what it means for objects to have
a <a class="reference internal" href="#term-type"><span class="xref std std-term">type</span></a>, and how to create new types using the <a class="reference external" href="https://docs.python.org/3/reference/compound_stmts.html#class" title="(in Python v3.14)"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">class</span></code></a> keyword.</p>
<section id="abstraction-in-action">
<h2><span class="section-number">3.1. </span>Abstraction in action<a class="headerlink" href="#abstraction-in-action" title="Link to this heading">¶</a></h2>
<p>Consider this line of Python code:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">print</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
</pre></div>
</div>
<p>What does it do? Well, assuming that <code class="xref py py-obj docutils literal notranslate"><span class="pre">a</span></code> and <code class="xref py py-obj docutils literal notranslate"><span class="pre">b</span></code> are suitably defined, it
prints their sum. This, however, begs the questions: what is “suitably
defined”, and what is “sum”? For example:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="n">a</span> <span class="o">=</span> <span class="mi">1</span>
<span class="gp">In [2]: </span><span class="n">b</span> <span class="o">=</span> <span class="mi">2</span>
<span class="gp">In [3]: </span><span class="nb">print</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
<span class="go">3</span>
</pre></div>
</div>
<p>You’re unlikely to be surprised that Python can add <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#typesnumeric" title="(in Python v3.14)"><span class="xref std std-ref">integers</span></a>. On the other hand it turns out we can also add strings:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="n">a</span> <span class="o">=</span> <span class="s1">'fr'</span>
<span class="gp">In [2]: </span><span class="n">b</span> <span class="o">=</span> <span class="s1">'og'</span>
<span class="gp">In [3]: </span><span class="nb">print</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
<span class="go">'frog'</span>
</pre></div>
</div>
<p>So the meaning of <code class="xref py py-obj docutils literal notranslate"><span class="pre">+</span></code> depends on what is being added. What happens if
we add an integer to a <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#textseq" title="(in Python v3.14)"><span class="xref std std-ref">string</span></a>?</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="n">a</span> <span class="o">=</span> <span class="mi">1</span>
<span class="gp">In [2]: </span><span class="n">b</span> <span class="o">=</span> <span class="s1">'og'</span>
<span class="gp">In [3]: </span><span class="nb">print</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
<span class="gt">--------------------------------------------------------------------------</span>
<span class="ne">TypeError</span><span class="g g-Whitespace"> </span>Traceback (most recent call last)
<span class="n">Cell</span> <span class="n">In</span> <span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">line</span> <span class="mi">1</span>
<span class="ne">----> </span><span class="mi">1</span> <span class="nb">print</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
<span class="ne">TypeError</span>: unsupported operand type(s) for +: 'int' and 'str'
</pre></div>
</div>
<p>In this error, Python is complaining that <code class="xref py py-obj docutils literal notranslate"><span class="pre">+</span></code> does not make sense if
the items being added (the <a class="reference internal" href="#term-operands"><span class="xref std std-term">operands</span></a>) are an integer and a
string. This makes our understanding of “suitably defined” more
concrete: clearly some pairs of objects can be added and others
can’t. However, we should be careful about the conclusions we draw. We
might be tempted to believe that we can add two values if they are of
the same type. However, if we try this with a pair of <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#types-set" title="(in Python v3.14)"><span class="xref std std-ref">sets</span></a> then we’re
also in trouble:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="n">a</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">}</span>
<span class="gp">In [2]: </span><span class="n">b</span> <span class="o">=</span> <span class="p">{</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">}</span>
<span class="gp">In [3]: </span><span class="nb">print</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
<span class="gt">--------------------------------------------------------------------------</span>
<span class="ne">TypeError</span><span class="g g-Whitespace"> </span>Traceback (most recent call last)
<span class="n">Cell</span> <span class="n">In</span> <span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">line</span> <span class="mi">1</span>
<span class="ne">----> </span><span class="mi">1</span> <span class="nb">print</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
<span class="ne">TypeError</span>: unsupported operand type(s) for +: 'set' and 'set'
</pre></div>
</div>
<p>Conversely we might suspect that two values can be added only if they are of the same
type. However it is perfectly legal to add an integer and a <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#typesnumeric" title="(in Python v3.14)"><span class="xref std std-ref">floating
point value</span></a>:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="n">a</span> <span class="o">=</span> <span class="mi">1</span>
<span class="gp">In [2]: </span><span class="n">b</span> <span class="o">=</span> <span class="mf">2.5</span>
<span class="gp">In [3]: </span><span class="nb">print</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
<span class="go">3.5</span>
</pre></div>
</div>
<p>In Python, the operator <code class="xref py py-obj docutils literal notranslate"><span class="pre">+</span></code> encodes an abstraction for addition. This means
that <code class="xref py py-obj docutils literal notranslate"><span class="pre">+</span></code> stands for the addition operation, whatever that may mean for
a particular pair of operands. For the purposes of the abstraction,
everything which is specific to the particular operands is
ignored. This includes, for example,
the mechanism by which the addition is calculated and the value of the
result. This enables a programmer to think about the relatively simple
mathematical operation of addition, rather than the potentially
complex or messy way it might be implemented for particular data.</p>
<div class="proof proof-type-definition" id="id4">
<div class="proof-title">
<span class="proof-type">Definition 3.1</span>
</div><div class="proof-content">
<p>An <em>abstraction</em> is a mathematical object with a limited set of
defined properties. For the purposes of the abstraction, any other
properties that an object may have are disregarded.</p>
</div></div><p>An abstraction is a purely mathematical concept, but it is one which
maps to one or more concrete realisations in code. Sometimes the
abstract mathematical concept and its concrete realisation match so
perfectly that it is difficult to distinguish the two. In those
circumstances, we usually conflate the terminology for the abstraction
and the code object. “Type” is one such example, and we turn to that
now.</p>
</section>
<section id="types">
<h2><span class="section-number">3.2. </span>Types<a class="headerlink" href="#types" title="Link to this heading">¶</a></h2>
<p>In the previous section, we observed that addition may or may not be
defined, depending on what the types of its operands are. In doing so,
we skirted the question of what it means for an object to have
type.</p>
<div class="proof proof-type-definition" id="id5">
<div class="proof-title">
<span class="proof-type">Definition 3.2</span>
</div><div class="proof-content">
<p>A <em>type</em> or <em>class</em> is an abstraction defined by a set of possible values, and
a set of operators valid for objects of that type.</p>
</div></div><p>Every object in Python has a type. This is true for primitive numeric
types, such as <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a>, <a class="reference external" href="https://docs.python.org/3/library/functions.html#float" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">float</span></code></a>, and <a class="reference external" href="https://docs.python.org/3/library/functions.html#complex" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">complex</span></code></a>; for sequences such as
string (<a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#str" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></a>), <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#tuple" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">tuple</span></code></a>, and <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#list" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">list</span></code></a>; and also for more complex types
such as <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#set" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">set</span></code></a> and dictionary (<a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#dict" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">dict</span></code></a>). Indeed, the
Python concept of type goes much further, as we discover if we call
<a class="reference external" href="https://docs.python.org/3/library/functions.html#type" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">type</span></code></a> on various objects:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="nb">type</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="gh">Out[1]: </span><span class="go">int</span>
<span class="gp">In [2]: </span><span class="nb">type</span><span class="p">(</span><span class="nb">abs</span><span class="p">)</span>
<span class="gh">Out[2]: </span><span class="go">builtin_function_or_method</span>
</pre></div>
</div>
<p>So <code class="xref py py-obj docutils literal notranslate"><span class="pre">1</span></code> is an object of type <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a>, which means that it comes with all of
Python’s operations for integer arithmetic. <a class="reference external" href="https://docs.python.org/3/library/functions.html#abs" title="(in Python v3.14)"><code class="xref py py-func docutils literal notranslate"><span class="pre">abs()</span></code></a>, on the other hand, is
a <a class="reference external" href="https://docs.python.org/3/library/functions.html" title="(in Python v3.14)"><span class="xref std std-doc">built-in function</span></a>, so its defining
operation is that it can be called on one or more suitable arguments (for
example <code class="xref py py-obj docutils literal notranslate"><span class="pre">abs(1)</span></code>). If every object has a type, what about types themselves?
What is the type of <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.14)"><code class="xref py py-obj docutils literal notranslate"><span class="pre">int</span></code></a>?</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="nb">type</span><span class="p">(</span><span class="nb">int</span><span class="p">)</span>
<span class="gh">Out[1]: </span><span class="go">type</span>
</pre></div>
</div>
<p>We see that <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> is the type of integer objects, and is itself an
object with type <a class="reference external" href="https://docs.python.org/3/library/functions.html#type" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">type</span></code></a>. That rather invites the question of what
is the type of <a class="reference external" href="https://docs.python.org/3/library/functions.html#type" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">type</span></code></a>?</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="nb">type</span><span class="p">(</span><span class="nb">type</span><span class="p">)</span>
<span class="gh">Out[1]: </span><span class="go">type</span>
</pre></div>
</div>
<p>This actually makes perfect sense, because <a class="reference external" href="https://docs.python.org/3/library/functions.html#type" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">type</span></code></a> is simply the
type of types.</p>
<p>We will return to types in much more detail later. At this stage, the
take-home message is that essentially everything you will encounter in
Python is an object, and every object has a type.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>In Python, the term
“class” is essentially synonymous with “type”, so “what is the class
of <code class="xref py py-obj docutils literal notranslate"><span class="pre">foo</span></code>” is the same as saying “what is the type of <code class="xref py py-obj docutils literal notranslate"><span class="pre">foo</span></code>”. However
the two terms are not synonyms when used in code. <a class="reference external" href="https://docs.python.org/3/library/functions.html#type" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">type</span></code></a> can be
used to determine the type of an object, while <a class="reference external" href="https://docs.python.org/3/reference/compound_stmts.html#class" title="(in Python v3.14)"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">class</span></code></a> is
used to define new types.</p>
</div>
</section>
<section id="defining-new-types">
<h2><span class="section-number">3.3. </span>Defining new types<a class="headerlink" href="#defining-new-types" title="Link to this heading">¶</a></h2>
<details>
<summary>
Video: a first class</summary><div class="video_wrapper" style="">
<iframe allowfullscreen="true" src="https://player.vimeo.com/video/488143930" style="border: 0; height: 345px; width: 560px">
</iframe></div><p>Imperial students can also <a class="reference external" href="https://imperial.cloud.panopto.eu/Panopto/Pages/Viewer.aspx?id=b70b944d-612c-4e57-9538-af8d01031342">watch this video on Panopto</a></p>
</details><p>Python has a rich set of <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html" title="(in Python v3.14)"><span class="xref std std-doc">built-in types</span></a>. These form powerful building blocks for the
language, but one very soon finds mathematical abstractions which do
not have implementations among the built-in types of the Python
interpreter. For example, the built-in types do not include a matrix
or multidimensional array type. The ability to make new data types
which provide concrete implementations of further mathematical
abstractions is central to effectively exploiting abstraction in
programming.</p>
<p>As an example, lets suppose that we want to work with real polynomials in
one variable. That is to say, functions of the form:</p>
<div class="math notranslate nohighlight">
\[f(x) = \sum_{n=0}^d c_n x^n \quad \textrm{for some } d\in
\mathbb{N}, c_n \in \mathbb{R}\]</div>
<p>The set of all polynomials is a well-defined (though infinite) set of
different values, with a number of well-defined properties. For
example, we can add and multiply polynomials, resulting in a new
polynomial. We can also evaluate a polynomial for a particular value
of <span class="math notranslate nohighlight">\(x\)</span>, which would result in a real value.</p>
<p>This is the mathematical abstraction of a polynomial. How would we
represent this abstraction in Python code? A polynomial is
characterised by its set of coefficients, so we could in principle
represent a polynomial as a <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#tuple" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">tuple</span></code></a> of coefficient
values. However, the addition of tuples is <a class="reference internal" href="#term-concatenation"><span class="xref std std-term">concatenation</span></a>, and
multiplication of two tuples isn’t even defined, so this would be a
very poor representation of the mathematics: a polynomial represented
as a tuple of coefficients would not behave the way a mathematician
would expect. Instead, what we need to do is make a new type whose
operations match the mathematical properties of a polynomial.</p>
<section id="classes-and-constructors">
<h3><span class="section-number">3.3.1. </span>Classes and constructors<a class="headerlink" href="#classes-and-constructors" title="Link to this heading">¶</a></h3>
<p>The Python keyword for declaring a new type is
<a class="reference external" href="https://docs.python.org/3/reference/compound_stmts.html#class" title="(in Python v3.14)"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">class</span></code></a>. Just like a function declaration, this creates a new
indented block. In this case, the block contains all of the function
declarations which define the operations on this new type. Let’s make
a very simple implementation:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Polynomial</span><span class="p">:</span>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">coefs</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">coefficients</span> <span class="o">=</span> <span class="n">coefs</span>
</pre></div>
</div>
<p>We’ll interpret the <span class="math notranslate nohighlight">\(i\)</span>-th coefficient as the coefficient of <span class="math notranslate nohighlight">\(x^i\)</span>.
This will simplify the program logic, but take care because mathematicians
usually write coefficients from largest power of <span class="math notranslate nohighlight">\(x\)</span> to smallest, and this
is the opposite of that. Executing this code in a Python interpreter would enable us to create
a simple polynomial, and inspect its coefficients:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [7]: </span><span class="n">f</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="gp">In [8]: </span><span class="n">f</span><span class="o">.</span><span class="n">coefficients</span>
<span class="gh">Out[8]: </span><span class="go">(0, 1, 2)</span>
</pre></div>
</div>
<p>The three lines of Python defining the <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> class contain
several important concepts and Python details that it is important to
understand.</p>
<p>The <a class="reference external" href="https://docs.python.org/3/reference/compound_stmts.html#class" title="(in Python v3.14)"><span class="xref std std-ref">class definition</span></a> statement opens a new block, so
just like a <a class="reference external" href="https://docs.python.org/3/reference/compound_stmts.html#function" title="(in Python v3.14)"><span class="xref std std-ref">function definition</span></a>, it starts with
the keyword followed by the name of the class we are defining, and
ends with a colon. User-defined classes in Python (i.e. classes not
built into the language) usually have CapWords names. This means
that all the words in the name are capitalised and run together without spaces. For
example, if we decided to make a separate class for complex-valued
polynomials, we might call it <code class="xref py py-class docutils literal notranslate"><span class="pre">ComplexPolynomial</span></code>.</p>
<p>Inside the class definition, i.e. indented inside the block, is a
function called <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__init__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a>. Functions defined inside a class
definition are called <a class="reference internal" href="#term-method"><span class="xref std std-term">methods</span></a>. The <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__init__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> method has a
rather distinctive form of name, starting and ending with two
underscores. Names of this format are used in the Python language for
objects which have special meaning in the Python language. The
<a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__init__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> method of a class has special meaning in Python as
the <a class="reference internal" href="#term-constructor"><span class="xref std std-term">constructor</span></a> of a class. When we write:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [7]: </span><span class="n">f</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
</pre></div>
</div>
<p>This is called <a class="reference internal" href="#term-instantiate"><span class="xref std std-term">instantiating</span></a> an object of type
<code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code>. The following steps occur:</p>
<ol class="arabic simple">
<li><p>Python creates an object of type <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code>.</p></li>
<li><p>The <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__init__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> <a class="reference internal" href="#term-special-method"><span class="xref std std-term">special method</span></a> of <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code>
is called. The new <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> object is passed as the
first parameter (<code class="xref py py-obj docutils literal notranslate"><span class="pre">self</span></code>), and the <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#tuple" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">tuple</span></code></a> <code class="xref py py-obj docutils literal notranslate"><span class="pre">(0,</span> <span class="pre">1,</span> <span class="pre">2)</span></code> is passed
as the second parameter (<code class="xref py py-obj docutils literal notranslate"><span class="pre">coefs</span></code>).</p></li>
<li><p>The name <code class="xref py py-obj docutils literal notranslate"><span class="pre">f</span></code> in the surrounding <a class="reference internal" href="2_programs_in_files.html#term-scope"><span class="xref std std-term">scope</span></a> is associated with the
<code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code>.</p></li>
</ol>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Notice that <code class="xref py py-meth docutils literal notranslate"><span class="pre">Polynomial.__init__()</span></code> doesn’t return anything. The role
of the <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__init__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> method is to set up the object, <code class="xref py py-obj docutils literal notranslate"><span class="pre">self</span></code>; it
is not to return a value. <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__init__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> never returns a value.</p>
</div>
</section>
<section id="attributes">
<h3><span class="section-number">3.3.2. </span>Attributes<a class="headerlink" href="#attributes" title="Link to this heading">¶</a></h3>
<p>Let’s now look at what happened inside the <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__init__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> method. We
have just one line:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="bp">self</span><span class="o">.</span><span class="n">coefficients</span> <span class="o">=</span> <span class="n">coefs</span>
</pre></div>
</div>
<p>Remember that <code class="xref py py-obj docutils literal notranslate"><span class="pre">self</span></code> is the object we are setting up, and <code class="xref py py-obj docutils literal notranslate"><span class="pre">coefs</span></code> is the
other parameter to <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__init__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a>. This line of code creates a new
name inside this <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> object, called
<code class="xref py py-obj docutils literal notranslate"><span class="pre">coefficients</span></code>, and associates this new name with the object passed as
the argument to the <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> constructor. Names such as
this are called <a class="reference internal" href="#term-attribute"><span class="xref std std-term">attributes</span></a>. We create an attribute
just by assigning to it, and we can then read back the attribute using
the same syntax, which is what we did here:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [8]: </span><span class="n">f</span><span class="o">.</span><span class="n">coefficients</span>
<span class="gh">Out[8]: </span><span class="go">(0, 1, 2)</span>
</pre></div>
</div>
<p>Attributes can be given any name which is allowed for a Python name in general -
which is to say sequences of letters, numbers and underscores starting with a
letter or an underscore. Special significance attaches to names starting with an
underscore, so these should be avoided in your own names unless you intend to
create a private attribute.</p>
</section>
<section id="methods">
<h3><span class="section-number">3.3.3. </span>Methods<a class="headerlink" href="#methods" title="Link to this heading">¶</a></h3>
<details>
<summary>
Video: defining methods</summary><div class="video_wrapper" style="">
<iframe allowfullscreen="true" src="https://player.vimeo.com/video/488273256" style="border: 0; height: 345px; width: 560px">
</iframe></div><p>Imperial students can also <a class="reference external" href="https://imperial.cloud.panopto.eu/Panopto/Pages/Viewer.aspx?id=b3a56e5f-2ed4-4417-aaf8-ae1c00da6017">watch this video on Panopto</a></p>
</details><p>We have already met the <a class="reference internal" href="#term-special-method"><span class="xref std std-term">special method</span></a> <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__init__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a>,
which defines the class constructor. A much more typical case is an
ordinary method, without a special underscore name. For example,
suppose we wish to be able to access the degree of a polynomial, then
we might add a <code class="xref py py-meth docutils literal notranslate"><span class="pre">degree()</span></code> method to our class:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Polynomial</span><span class="p">:</span>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">coefs</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">coefficients</span> <span class="o">=</span> <span class="n">coefs</span>
<span class="k">def</span><span class="w"> </span><span class="nf">degree</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">coefficients</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span>
</pre></div>
</div>
<p>Observe that the new method is indented inside the <a class="reference external" href="https://docs.python.org/3/reference/compound_stmts.html#class" title="(in Python v3.14)"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">class</span></code></a>
block at the same level as the <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__init__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> method. Observe also
that it too takes <code class="xref py py-obj docutils literal notranslate"><span class="pre">self</span></code> as its first parameter. A key difference from
the <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__init__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> method is that <code class="xref py py-meth docutils literal notranslate"><span class="pre">degree()</span></code> now returns a
value, as most functions do. We can now use our new method to recover
the degree of our polynomial.</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="n">f</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="gp">In [2]: </span><span class="n">f</span><span class="o">.</span><span class="n">degree</span><span class="p">()</span>
<span class="gh">Out[2]: </span><span class="go">2</span>
</pre></div>
</div>
<p>To clarify the role of the <code class="xref py py-obj docutils literal notranslate"><span class="pre">self</span></code> parameter it helps to understand
that <code class="xref py py-obj docutils literal notranslate"><span class="pre">f.degree()</span></code> is just a short way of writing
<code class="xref py py-obj docutils literal notranslate"><span class="pre">Polynomial.degree(f)</span></code>. Like attributes, methods can have any allowed Python
name. Attributes and methods on an object form part of the same
<a class="reference internal" href="2_programs_in_files.html#term-namespace"><span class="xref std std-term">namespace</span></a>, so you can’t have an attribute and a method with the same
name. If you try, then the name will be overwritten with whichever was defined
later, and the attribute or method defined first will no longer be accessible
under that name. This is unlikely to be what you wanted.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>The object itself is always passed as the first argument to a <a class="reference internal" href="#term-method"><span class="xref std std-term">method</span></a>.
Technically, it is possible to name the first parameter any legal Python
name, but there is a <strong>very</strong> strong convention that the first parameter to
any <a class="reference internal" href="#term-instance-method"><span class="xref std std-term">instance method</span></a> is called <code class="xref py py-obj docutils literal notranslate"><span class="pre">self</span></code>. <strong>Never, ever</strong> name this
parameter anything other than <code class="xref py py-obj docutils literal notranslate"><span class="pre">self</span></code>, or you will confuse every Python
programmer who reads your code!</p>
</div>
</section>
<section id="string-representations-of-objects">
<h3><span class="section-number">3.3.4. </span>String representations of objects<a class="headerlink" href="#string-representations-of-objects" title="Link to this heading">¶</a></h3>
<details>
<summary>
Video: printing classes</summary><div class="video_wrapper" style="">
<iframe allowfullscreen="true" src="https://player.vimeo.com/video/488275072" style="border: 0; height: 345px; width: 560px">
</iframe></div><p>Imperial students can also <a class="reference external" href="https://imperial.cloud.panopto.eu/Panopto/Pages/Viewer.aspx?id=4fe0252a-619d-4959-99f0-ae1c00da657d">watch this video on Panopto</a></p>
</details><p>Remember that a key reason for defining new classes is to enable users
to reason about the resulting objects at a higher mathematical level. An
important aid to the user in doing this is to be able to look at the
object. What happens if we print a <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code>?</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="n">f</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="gp">In [2]: </span><span class="nb">print</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
<span class="go"><Polynomial object at 0x104960dd0></span>
</pre></div>
</div>
<p>This is less than useful. By default, Python just prints the class of
the object and the memory address at which this particular object is
stored. This is, however, not so surprising if we think about the
situation in a little more depth. How was Python supposed to know what
sort of string representation makes sense for this object? We will
have to tell it.</p>
<p>The way we do so is using another <a class="reference internal" href="#term-special-method"><span class="xref std std-term">special method</span></a>. The special
method name for the human readable string representation of an object is
<a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__str__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__str__()</span></code></a>. It takes no arguments other than the object itself.
<a class="reference internal" href="#polynomial-str"><span class="std std-numref">Listing 3.1</span></a> provides one possible implementation of this method.</p>
<div class="literal-block-wrapper docutils container" id="polynomial-str">
<div class="code-block-caption"><span class="caption-number">Listing 3.1 </span><span class="caption-text">An implementation of the string representation of a
<code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code>. This takes into account the usual conventions for
writing polynomials, including writing the highest degree terms first, and
omitting zero terms and unit coefficients.</span><a class="headerlink" href="#polynomial-str" title="Link to this code">¶</a></div>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="k">def</span><span class="w"> </span><span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="linenos"> 2</span>
<span class="linenos"> 3</span> <span class="n">coefs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">coefficients</span>
<span class="linenos"> 4</span> <span class="n">terms</span> <span class="o">=</span> <span class="p">[]</span>
<span class="linenos"> 5</span>
<span class="linenos"> 6</span> <span class="c1"># Degree 0 and 1 terms conventionally have different representation.</span>
<span class="linenos"> 7</span> <span class="k">if</span> <span class="n">coefs</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
<span class="linenos"> 8</span> <span class="n">terms</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">coefs</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span>
<span class="linenos"> 9</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">degree</span><span class="p">()</span> <span class="o">></span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">coefs</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
<span class="linenos">10</span> <span class="n">terms</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">coefs</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2">x"</span><span class="p">)</span>
<span class="linenos">11</span>
<span class="linenos">12</span> <span class="c1"># Remaining terms look like cx^d, though factors of 1 are dropped.</span>
<span class="linenos">13</span> <span class="n">terms</span> <span class="o">+=</span> <span class="p">[</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="s1">''</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="n">c</span><span class="si">}</span><span class="s2">x^</span><span class="si">{</span><span class="n">d</span><span class="si">}</span><span class="s2">"</span>
<span class="linenos">14</span> <span class="k">for</span> <span class="n">d</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">coefs</span><span class="p">[</span><span class="mi">2</span><span class="p">:],</span> <span class="n">start</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> <span class="k">if</span> <span class="n">c</span><span class="p">]</span>
<span class="linenos">15</span>
<span class="linenos">16</span> <span class="c1"># Sum polynomial terms from high to low exponent.</span>
<span class="linenos">17</span> <span class="k">return</span> <span class="s2">" + "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="n">terms</span><span class="p">))</span> <span class="ow">or</span> <span class="s2">"0"</span>
</pre></div>
</div>
</div>
<p>This somewhat longer piece of code results from the fact that the
linear and constant terms in a polynomial are usually represented
slightly differently from the higher-order terms. Having added this
new method to our class, we can now observe the result:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [2]: </span><span class="n">f</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
<span class="gp">In [3]: </span><span class="nb">print</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
<span class="go">5x^4 + x^3 + 2x + 1</span>
</pre></div>
</div>
<p>In fact, Python provides not one, but two <a class="reference internal" href="#term-special-method"><span class="xref std std-term">special
methods</span></a> which convert an object to a
string. <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__str__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__str__()</span></code></a> is called by <a class="reference external" href="https://docs.python.org/3/library/functions.html#print" title="(in Python v3.14)"><code class="xref py py-func docutils literal notranslate"><span class="pre">print()</span></code></a> and also by
<a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#str" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></a>. Its role is to provide the string representation which
is best understood by humans. In mathematical code, this will usually
be the mathematical notation for the object. In contrast, the
<a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__repr__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__repr__()</span></code></a> method is called by <a class="reference external" href="https://docs.python.org/3/library/functions.html#repr" title="(in Python v3.14)"><code class="xref py py-func docutils literal notranslate"><span class="pre">repr()</span></code></a> and also provides
the default string representation printed out by the Python command
line. By convention, <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__repr__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__repr__()</span></code></a> should return a string which a
user might type in order to recreate the object. For example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</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="vm">__name__</span> <span class="o">+</span> <span class="s2">"("</span> <span class="o">+</span> <span class="nb">repr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">coefficients</span><span class="p">)</span> <span class="o">+</span> <span class="s2">")"</span>
</pre></div>
</div>
<p><code class="xref py py-obj docutils literal notranslate"><span class="pre">type(self).__name__</span></code> simply evaluates to the class name, in this case
<code class="xref py py-obj docutils literal notranslate"><span class="pre">Polynomial</span></code>. This is better than hard-coding the class name because, as we will
see in <a class="reference internal" href="7_inheritance.html#inheritance"><span class="std std-numref">Chapter 7</span></a>, this implementation of
<a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__repr__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__repr__()</span></code></a> might well end up being inherited by a class with a
different name. Notice that in order to help ensure consistency of
representations we call <a class="reference external" href="https://docs.python.org/3/library/functions.html#repr" title="(in Python v3.14)"><code class="xref py py-func docutils literal notranslate"><span class="pre">repr()</span></code></a> on the coefficients in this case, whereas
in the <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__str__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__str__()</span></code></a> method we called <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#str" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></a>.</p>
<p>We can now observe the difference in the result:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [2]: </span><span class="n">f</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
<span class="gp">In [3]: </span><span class="n">f</span>
<span class="gh">Out[3]: </span><span class="go">Polynomial((1, 2, 0, 4, 5))</span>
</pre></div>
</div>
<p>When using <a class="reference external" href="https://docs.python.org/3/tutorial/inputoutput.html#tut-f-strings" title="(in Python v3.14)"><span class="xref std std-ref">f-strings</span></a>, the <a class="reference external" href="https://docs.python.org/3/library/functions.html#repr" title="(in Python v3.14)"><code class="xref py py-func docutils literal notranslate"><span class="pre">repr()</span></code></a> of a an
object can be inserted instead of the <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#str" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></a> by using the <code class="docutils literal notranslate"><span class="pre">!r</span></code> modifier.
For example, we could just as well have written the method above as:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</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="vm">__name__</span><span class="si">}</span><span class="s2">(</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">coefficients</span><span class="si">!r}</span><span class="s2">)"</span>
</pre></div>
</div>
</section>
<section id="object-equality">
<span id="id1"></span><h3><span class="section-number">3.3.5. </span>Object equality<a class="headerlink" href="#object-equality" title="Link to this heading">¶</a></h3>
<details>
<summary>
Video: object equality and test driven development</summary><div class="video_wrapper" style="">
<iframe allowfullscreen="true" src="https://player.vimeo.com/video/488981397" style="border: 0; height: 345px; width: 560px">
</iframe></div><p>Imperial students can also <a class="reference external" href="https://imperial.cloud.panopto.eu/Panopto/Pages/Viewer.aspx?id=17aa405c-bf70-4007-b365-ae1c00da7976">watch this video on Panopto</a></p>
</details><p>When are two objects equal? For built-in types Python has equality rules which
broadly match the mathematical identities that you might expect. For example,
two numbers of different types are equal if their numerical value is equal:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="mi">2</span> <span class="o">==</span> <span class="mf">2.0</span>
<span class="gh">Out[1]: </span><span class="go">True</span>
<span class="gp">In [2]: </span><span class="mf">2.0</span> <span class="o">==</span> <span class="mi">2</span><span class="o">+</span><span class="mi">0</span><span class="n">j</span>
<span class="gh">Out[2]: </span><span class="go">True</span>
</pre></div>
</div>
<p>Similarly, intrinsic sequence types are equal when their contents are equal:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [3]: </span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">"f"</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span><span class="mf">0.</span><span class="p">,</span> <span class="mi">1</span><span class="o">+</span><span class="mi">0</span><span class="n">j</span><span class="p">,</span> <span class="s1">'f'</span><span class="p">)</span>
<span class="gh">Out[3]: </span><span class="go">True</span>
<span class="gp">In [4]: </span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">"f"</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span><span class="mf">0.</span><span class="p">,</span> <span class="mi">1</span><span class="o">+</span><span class="mi">0</span><span class="n">j</span><span class="p">,</span> <span class="s1">'g'</span><span class="p">)</span>
<span class="gh">Out[4]: </span><span class="go">False</span>
<span class="gp">In [5]: </span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">"f"</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span><span class="mf">0.</span><span class="p">,</span> <span class="mi">1</span><span class="o">+</span><span class="mi">0</span><span class="n">j</span><span class="p">)</span>
<span class="gh">Out[5]: </span><span class="go">False</span>
</pre></div>
</div>
<p>This mathematically pleasing state of affairs doesn’t, however, automatically
carry over to new classes. We might expect that two identically defined
polynomials might compare equal:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [6]: </span><span class="kn">from</span><span class="w"> </span><span class="nn">example_code.polynomial</span><span class="w"> </span><span class="kn">import</span> <span class="n">Polynomial</span>
<span class="gp">In [7]: </span><span class="n">a</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
<span class="gp">In [8]: </span><span class="n">b</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
<span class="gp">In [9]: </span><span class="n">a</span> <span class="o">==</span> <span class="n">b</span>
<span class="gh">Out[9]: </span><span class="go">False</span>
</pre></div>
</div>
<p>The reason for this is obvious when one thinks about it: Python has no way to
know when two instances of a new class should be considered equal. Instead, it
falls back to comparing the unique identity of every object. This is accessible
using the built-in function <a class="reference external" href="https://docs.python.org/3/library/functions.html#id" title="(in Python v3.14)"><code class="xref py py-func docutils literal notranslate"><span class="pre">id()</span></code></a>:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [10]: </span><span class="nb">id</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="gh">Out[10]: </span><span class="go">4487083344</span>
<span class="gp">In [11]: </span><span class="nb">id</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
<span class="gh">Out[11]: </span><span class="go">4488256096</span>
</pre></div>
</div>
<p>This is a perfectly well-defined equality operator, but not a very
mathematically useful one. Fortunately, Python allows us to define a more useful
equality operator using the <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__eq__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__eq__()</span></code></a> <a class="reference internal" href="#term-special-method"><span class="xref std std-term">special method</span></a>. This
takes the current object and the object it is being compared to, and returns
<a class="reference external" href="https://docs.python.org/3/library/constants.html#True" title="(in Python v3.14)"><code class="xref py py-data docutils literal notranslate"><span class="pre">True</span></code></a> or <a class="reference external" href="https://docs.python.org/3/library/constants.html#False" title="(in Python v3.14)"><code class="xref py py-data docutils literal notranslate"><span class="pre">False</span></code></a> depending on whether the objects should be
considered equal. When we write <code class="xref py py-obj docutils literal notranslate"><span class="pre">a</span> <span class="pre">==</span> <span class="pre">b</span></code> in Python, what actually happens is
<code class="xref py py-obj docutils literal notranslate"><span class="pre">a.__eq__(b)</span></code>.</p>
<p>A basic implementation of <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__eq__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__eq__()</span></code></a> that checks that the other
object is a <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> with the same
coefficients is:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">Polynomial</span><span class="p">)</span> <span class="ow">and</span> \
<span class="bp">self</span><span class="o">.</span><span class="n">coefficients</span> <span class="o">==</span> <span class="n">other</span><span class="o">.</span><span class="n">coefficients</span>
</pre></div>
</div>
<p>Equipped with this method, <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code>
equality now behaves as we might expect.</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="kn">from</span><span class="w"> </span><span class="nn">example_code.polynomial</span><span class="w"> </span><span class="kn">import</span> <span class="n">Polynomial</span>
<span class="gp">In [2]: </span><span class="n">a</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
<span class="gp">In [3]: </span><span class="n">b</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
<span class="gp">In [4]: </span><span class="n">a</span> <span class="o">==</span> <span class="n">b</span>
<span class="gh">Out[4]: </span><span class="go">True</span>
</pre></div>
</div>
</section>
<section id="defining-arithmetic-options-on-objects">
<span id="object-arithmetic"></span><h3><span class="section-number">3.3.6. </span>Defining arithmetic options on objects<a class="headerlink" href="#defining-arithmetic-options-on-objects" title="Link to this heading">¶</a></h3>
<details>
<summary>
Video: polynomial addition.</summary><div class="video_wrapper" style="">
<iframe allowfullscreen="true" src="https://player.vimeo.com/video/489009900" style="border: 0; height: 345px; width: 560px">
</iframe></div><p>Imperial students can also <a class="reference external" href="https://imperial.cloud.panopto.eu/Panopto/Pages/Viewer.aspx?id=d9a38b7e-d182-46f6-90fc-ae1c00da8682">watch this video on Panopto</a></p>
</details><p>It’s all very well to be able to compare our polynomial objects, but
we won’t really have captured the mathematical abstraction involved
unless we have at least some mathematical operations. We have already
observed that objects of some classes can be added. Is this true for
<code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code>s?</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [2]: </span><span class="n">a</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
<span class="gp">In [3]: </span><span class="n">b</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">1</span><span class="p">,))</span>
<span class="gp">In [4]: </span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
<span class="gt">--------------------------------------------------------------------------</span>
<span class="ne">TypeError</span><span class="g g-Whitespace"> </span>Traceback (most recent call last)
<span class="n">Cell</span> <span class="n">In</span> <span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="n">line</span> <span class="mi">1</span>
<span class="ne">----> </span><span class="mi">1</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
<span class="ne">TypeError</span>: unsupported operand type(s) for +: 'Polynomial' and 'Polynomial'
</pre></div>
</div>
<p>Once again, this is not so surprising since we haven’t
defined what addition of polynomials should mean. The <a class="reference internal" href="#term-special-method"><span class="xref std std-term">special
method</span></a> which defines addition is <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__add__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__add__()</span></code></a>. It takes the
object itself and another object and returns their sum. That is,
when you write <code class="xref py py-obj docutils literal notranslate"><span class="pre">a</span> <span class="pre">+</span> <span class="pre">b</span></code> in Python, then what actually happens is
<code class="xref py py-obj docutils literal notranslate"><span class="pre">a.__add__(b)</span></code>.</p>
<p>Before we define our addition method, we first need to consider what
other objects it might make sense to add to a polynomial. Obviously, we
should be able to add two polynomials, but it also makes sense to add
a number to a polynomial. In either case, the result will be a new
polynomial, with coefficients equal to the sum of those of the
summands.</p>
<p>We also need to do something in the case where a user attempts to add to a
polynomial a value for which the operation makes no sense. For example, a user
might accidentally attempt to add a string to a polynomial. In this case, the
Python language specification requires that we return the special value
<a class="reference external" href="https://docs.python.org/3/library/constants.html#NotImplemented" title="(in Python v3.14)"><code class="xref py py-obj docutils literal notranslate"><span class="pre">NotImplemented</span></code></a>. Differentiating between the types of operands requires
two more Python features we have not yet met. One of these is the built in
function <a class="reference external" href="https://docs.python.org/3/library/functions.html#isinstance" title="(in Python v3.14)"><code class="xref py py-func docutils literal notranslate"><span class="pre">isinstance()</span></code></a>, which tests whether an object is an instance of a
class. The other is the class <a class="reference external" href="https://docs.python.org/3/library/numbers.html#numbers.Number" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">Number</span></code></a>, which we import from
the built-in <a class="reference external" href="https://docs.python.org/3/library/numbers.html#module-numbers" title="(in Python v3.14)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">numbers</span></code></a> module. All Python numbers are instances of
<a class="reference external" href="https://docs.python.org/3/library/numbers.html#numbers.Number" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">Number</span></code></a> so this provides a mechanism for checking whether the
other operand is a number. We will consider <a class="reference external" href="https://docs.python.org/3/library/functions.html#isinstance" title="(in Python v3.14)"><code class="xref py py-func docutils literal notranslate"><span class="pre">isinstance()</span></code></a> and
<a class="reference external" href="https://docs.python.org/3/library/numbers.html#numbers.Number" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">Number</span></code></a> in more detail when we look at <a class="reference internal" href="7_inheritance.html#inheritance"><span class="std std-ref">inheritance</span></a> and <a class="reference internal" href="10_further_object-oriented_features.html#abstract-base-classes"><span class="std std-ref">abstract base classes</span></a>.</p>
<p>Putting all this together, <a class="reference internal" href="#polynomial-add"><span class="std std-numref">Listing 3.2</span></a> defines polynomial addition.</p>
<div class="literal-block-wrapper docutils container" id="polynomial-add">
<div class="code-block-caption"><span class="caption-number">Listing 3.2 </span><span class="caption-text">An implementation of addition for <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code>.</span><a class="headerlink" href="#polynomial-add" title="Link to this code">¶</a></div>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="linenos"> 1</span><span class="k">def</span><span class="w"> </span><span class="fm">__add__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="linenos"> 2</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">Number</span><span class="p">):</span>
<span class="linenos"> 3</span> <span class="k">return</span> <span class="n">Polynomial</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">coefficients</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">other</span><span class="p">,)</span>
<span class="linenos"> 4</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">coefficients</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span>
<span class="linenos"> 5</span>
<span class="linenos"> 6</span> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">Polynomial</span><span class="p">):</span>
<span class="linenos"> 7</span> <span class="c1"># Work out how many coefficient places the two polynomials have in</span>
<span class="linenos"> 8</span> <span class="c1"># common.</span>
<span class="linenos"> 9</span> <span class="n">common</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">degree</span><span class="p">(),</span> <span class="n">other</span><span class="o">.</span><span class="n">degree</span><span class="p">())</span> <span class="o">+</span> <span class="mi">1</span>
<span class="linenos">10</span> <span class="c1"># Sum the common coefficient positions.</span>
<span class="linenos">11</span> <span class="n">coefs</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span> <span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">coefficients</span><span class="p">[:</span><span class="n">common</span><span class="p">],</span>
<span class="linenos">12</span> <span class="n">other</span><span class="o">.</span><span class="n">coefficients</span><span class="p">[:</span><span class="n">common</span><span class="p">]))</span>
<span class="linenos">13</span>
<span class="linenos">14</span> <span class="c1"># Append the high degree coefficients from the higher degree</span>
<span class="linenos">15</span> <span class="c1"># summand.</span>
<span class="linenos">16</span> <span class="n">coefs</span> <span class="o">+=</span> <span class="bp">self</span><span class="o">.</span><span class="n">coefficients</span><span class="p">[</span><span class="n">common</span><span class="p">:]</span> <span class="o">+</span> <span class="n">other</span><span class="o">.</span><span class="n">coefficients</span><span class="p">[</span><span class="n">common</span><span class="p">:]</span>
<span class="linenos">17</span>
<span class="linenos">18</span> <span class="k">return</span> <span class="n">Polynomial</span><span class="p">(</span><span class="n">coefs</span><span class="p">)</span>
<span class="linenos">19</span>
<span class="linenos">20</span> <span class="k">else</span><span class="p">:</span>
<span class="linenos">21</span> <span class="k">return</span> <span class="bp">NotImplemented</span>
</pre></div>
</div>
</div>
<p>Notice that we create a new <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> object for the result
each time: the sum of two polynomials is a different polynomial, it
doesn’t modify either polynomial in place.</p>
<p>Let’s try our new addition functionality in action:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [2]: </span><span class="n">a</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
<span class="gp">In [3]: </span><span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="go">x^3 + 2x + 1</span>
<span class="gp">In [4]: </span><span class="n">b</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
<span class="gp">In [5]: </span><span class="nb">print</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
<span class="go">x</span>
<span class="gp">In [6]: </span><span class="nb">print</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
<span class="go">x^3 + 3x + 1</span>
<span class="gp">In [7]: </span><span class="nb">print</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
<span class="go">x^3 + 2x + 2</span>
<span class="gp">In [8]: </span><span class="nb">print</span><span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">a</span><span class="p">)</span>
<span class="gt">--------------------------------------------------------------------------</span>
<span class="ne">TypeError</span><span class="g g-Whitespace"> </span>Traceback (most recent call last)
<span class="n">Cell</span> <span class="n">In</span> <span class="p">[</span><span class="mi">8</span><span class="p">],</span> <span class="n">line</span> <span class="mi">1</span>
<span class="ne">----> </span><span class="mi">1</span> <span class="nb">print</span><span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">a</span><span class="p">)</span>
<span class="ne">TypeError</span>: unsupported operand type(s) for +: 'int' and 'Polynomial'
</pre></div>
</div>
<p>So, everything proceeds as expected until we try to add a
<code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> to an integer. What happened? Remember that
<code class="xref py py-obj docutils literal notranslate"><span class="pre">1</span> <span class="pre">+</span> <span class="pre">a</span></code> causes Python to call <code class="xref py py-obj docutils literal notranslate"><span class="pre">int.__add__(1,</span> <span class="pre">a)</span></code>. What does that do?:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [9]: </span><span class="nb">int</span><span class="o">.</span><span class="fm">__add__</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span>
<span class="gh">Out[9]: </span><span class="go">NotImplemented</span>
</pre></div>
</div>
<p>Naturally, Python’s inbuilt <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> type knows nothing about our
new <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> class, so when we ask it to do the addition,
it returns <a class="reference external" href="https://docs.python.org/3/library/constants.html#NotImplemented" title="(in Python v3.14)"><code class="xref py py-obj docutils literal notranslate"><span class="pre">NotImplemented</span></code></a>. We could, however, tell
<code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> how to be added to an <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a>, and Python
provides a mechanism for this. If the <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__add__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__add__()</span></code></a> of the left hand
operand of <code class="xref py py-obj docutils literal notranslate"><span class="pre">+</span></code> returns <a class="reference external" href="https://docs.python.org/3/library/constants.html#NotImplemented" title="(in Python v3.14)"><code class="xref py py-obj docutils literal notranslate"><span class="pre">NotImplemented</span></code></a>, then Python tries the
reverse addition method, called <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__radd__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__radd__()</span></code></a>, on the right hand
operand. Because we know that polynomial addition is commutative,
we can define this very easily:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="fm">__radd__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span> <span class="o">+</span> <span class="n">other</span>
</pre></div>
</div>
<p>With our newly enhanced <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> class, we can revisit the
previously problematic operation:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [2]: </span><span class="n">a</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
<span class="gp">In [3]: </span><span class="nb">print</span><span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">a</span><span class="p">)</span>
<span class="go">x^3 + 2x + 2</span>
</pre></div>
</div>
<p>Of course, addition is not the only arithmetic operator one might wish
to overload. A fully featured polynomial class will, at the very
minimum, need subtraction, multiplication (by a scalar or another
polynomial) and exponentiation by an integer power. The combination of
these, and particularly exponentiation, would allow the user to define
new polynomials in a particularly natural way, using Python’s
intrinsic operators:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="n">x</span> <span class="o">=</span> <span class="n">Polynomial</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
<span class="gp">In [2]: </span><span class="nb">print</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="go">x</span>
<span class="gp">In [3]: </span><span class="n">p</span> <span class="o">=</span> <span class="n">x</span><span class="o">**</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">2</span>
<span class="gp">In [4]: </span><span class="n">p</span>
<span class="go">Polynomial((2, 2, 0, 1))</span>
</pre></div>
</div>
<p>The <a class="reference internal" href="#term-special-method"><span class="xref std std-term">special method</span></a> names for further arithmetic operators are
given <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#numeric-types" title="(in Python v3.14)"><span class="xref std std-ref">in the Python documentation</span></a>. The
implementation of multiplication, exponentiation, and subtraction for
the <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> class is left as an exercise.</p>
</section>
<section id="creating-objects-that-act-like-functions">
<h3><span class="section-number">3.3.7. </span>Creating objects that act like functions<a class="headerlink" href="#creating-objects-that-act-like-functions" title="Link to this heading">¶</a></h3>
<p>From a mathematical perspective, a real polynomial is a function. That is
to say, if:</p>
<div class="math notranslate nohighlight">
\[f = x^2 + 2x + 1\]</div>
<p>then for any real <span class="math notranslate nohighlight">\(x\)</span>, <span class="math notranslate nohighlight">\(f(x)\)</span> is defined and is a real
number. We already know from the example of <a class="reference external" href="https://docs.python.org/3/library/functions.html#abs" title="(in Python v3.14)"><code class="xref py py-func docutils literal notranslate"><span class="pre">abs()</span></code></a>, above, that
Python functions are objects. However, our challenge is the converse of
this: we have <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> objects which we would like to be
able to call like functions. The solution to our challenge is that
calling a function is an operation on an object similar to addition,
and Python provides another <a class="reference internal" href="#term-special-method"><span class="xref std std-term">special method</span></a> name for
this. <code class="xref py py-obj docutils literal notranslate"><span class="pre">f(x)</span></code> is mapped to <code class="xref py py-obj docutils literal notranslate"><span class="pre">f.__call__(x)</span></code>, so any Python object with a
<a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__call__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__call__()</span></code></a> method behaves like a function, and any class
defining a <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__call__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__call__()</span></code></a> method in effect defines a new type of
function.</p>
</section>
</section>
<section id="encapsulation">
<h2><span class="section-number">3.4. </span>Encapsulation<a class="headerlink" href="#encapsulation" title="Link to this heading">¶</a></h2>
<p>The property that objects have of bundling up data and methods in a
more-or-less opaque object with which other code can interact without
concerning itself with the internal details of the object is called
<a class="reference internal" href="#term-encapsulation"><span class="xref std std-term">encapsulation</span></a>. Encapsulation is one of the core concepts in
object-oriented programming. In particular, encapsulation is key to
creating single objects representing high level mathematical
abstractions whose concrete realisation in code may require many
pieces of data and a large number of complex functions.</p>
</section>
<section id="assignment-and-instantiation">
<span id="id2"></span><h2><span class="section-number">3.5. </span>Assignment and instantiation<a class="headerlink" href="#assignment-and-instantiation" title="Link to this heading">¶</a></h2>
<p>One common confusion among new Python programmers concerns the distinction
between making new objects, and assigning new names to existing objects. The
key point to remember is that assignment in Python does not by itself create
new objects, only new variable names. For example:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="n">a</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
<span class="gp">In [2]: </span><span class="n">b</span> <span class="o">=</span> <span class="n">a</span>
</pre></div>
</div>
<p>The right hand side of the first line <a class="reference internal" href="#term-instantiate"><span class="xref std std-term">instantiates</span></a> a new
set, and the assignment creates the name <code class="xref py py-obj docutils literal notranslate"><span class="pre">a</span></code> and associates it with the same
set. The second line is just an assignment: it associates the name <code class="xref py py-obj docutils literal notranslate"><span class="pre">b</span></code> with the
same set. We can see the effect of this if we add an item to <code class="xref py py-obj docutils literal notranslate"><span class="pre">b</span></code> and then look
at the contents of <code class="xref py py-obj docutils literal notranslate"><span class="pre">a</span></code>:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [3]: </span><span class="n">b</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="gp">In [4]: </span><span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="go">{1}</span>
</pre></div>
</div>
<p>The same distinction between instantiating objects and making new references to
them is the cause of a frequent mistake when trying to create a list of empty
objects:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [5]: </span><span class="n">c</span> <span class="o">=</span> <span class="p">[</span><span class="nb">set</span><span class="p">()]</span> <span class="o">*</span> <span class="mi">5</span>
<span class="gp">In [6]: </span><span class="nb">print</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="go">[set(), set(), set(), set(), set()]</span>
</pre></div>
</div>
<p>The programmer almost certainly intended to create a list containing five empty
sets. Instead, they have created a list containing five references to the same
set:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [7]: </span><span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="gp">In [8]: </span><span class="nb">print</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="go">[{2}, {2}, {2}, {2}, {2}]</span>
</pre></div>
</div>
<p>The right way to create a list of five empty sets is to use a list
comprehension. This will instantiate a different set for each entry in the
list:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [9]: </span><span class="n">d</span> <span class="o">=</span> <span class="p">[</span><span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">)]</span>
<span class="gp">In [10]: </span><span class="n">d</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="gp">In [11]: </span><span class="nb">print</span><span class="p">(</span><span class="n">d</span><span class="p">)</span>
<span class="go">[{2}, set(), set(), set(), set()]</span>
</pre></div>
</div>
</section>
<section id="glossary">
<h2><span class="section-number">3.6. </span>Glossary<a class="headerlink" href="#glossary" title="Link to this heading">¶</a></h2>
<blockquote>
<div><dl class="simple glossary">
<dt id="term-abstraction">abstraction<a class="headerlink" href="#term-abstraction" title="Link to this term">¶</a></dt><dd><p>A mathematical concept with a limited set of defined
properties. For the purposes of the abstraction, any other
properties that an object may have are disregarded.</p>
</dd>
<dt id="term-attribute">attribute<a class="headerlink" href="#term-attribute" title="Link to this term">¶</a></dt><dd><p>A value encapsulated in another object, such as a
<a class="reference internal" href="#term-class"><span class="xref std std-term">class</span></a>. Attributes are accessed using dot syntax, so if
<code class="xref py py-obj docutils literal notranslate"><span class="pre">b</span></code> is an attribute of <code class="xref py py-obj docutils literal notranslate"><span class="pre">a</span></code> then its value is accessed using the
syntax <code class="xref py py-obj docutils literal notranslate"><span class="pre">a.b</span></code>. <a class="reference internal" href="#term-method"><span class="xref std std-term">Methods</span></a> are a special case of attributes.</p>
</dd>
<dt id="term-class">class<a class="headerlink" href="#term-class" title="Link to this term">¶</a></dt><dt id="term-type">type<a class="headerlink" href="#term-type" title="Link to this term">¶</a></dt><dd><p>An abstraction defined by a set of possible values, and a set
of operators valid for objects of that type. <a class="reference external" href="https://docs.python.org/3/reference/compound_stmts.html#class" title="(in Python v3.14)"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">Class</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/functions.html#type" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">type</span></code></a> are essentially synonymous, though
the two words have different roles in Python code.</p>
</dd>
<dt id="term-concatenation">concatenation<a class="headerlink" href="#term-concatenation" title="Link to this term">¶</a></dt><dd><p>The combination of two <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#typesseq" title="(in Python v3.14)"><span class="xref std std-ref">sequences</span></a> by creating a new sequence containing
all of the items in the first sequence, followed by all of the items in
the second sequence. For example <code class="xref py py-obj docutils literal notranslate"><span class="pre">(1,</span> <span class="pre">2)</span> <span class="pre">+</span> <span class="pre">(3,</span> <span class="pre">4)</span></code> is <code class="xref py py-obj docutils literal notranslate"><span class="pre">(1,</span> <span class="pre">2,</span> <span class="pre">3,</span> <span class="pre">4)</span></code>.</p>
</dd>
<dt id="term-constructor">constructor<a class="headerlink" href="#term-constructor" title="Link to this term">¶</a></dt><dd><p>The <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__init__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> method of a <a class="reference internal" href="#term-class"><span class="xref std std-term">class</span></a>. The constructor
is passed the new object as its first argument (<code class="xref py py-obj docutils literal notranslate"><span class="pre">self</span></code>) and is
responsible for setting up the object. The constructor modifies
<code class="xref py py-obj docutils literal notranslate"><span class="pre">self</span></code> in place: constructors never return a value.</p>
</dd>
<dt id="term-data-attribute">data attribute<a class="headerlink" href="#term-data-attribute" title="Link to this term">¶</a></dt><dd><p>An <a class="reference internal" href="#term-attribute"><span class="xref std std-term">attribute</span></a> which is not a <a class="reference internal" href="#term-method"><span class="xref std std-term">method</span></a>. As the name
suggests, these are used to store data in an object.</p>
</dd>
<dt id="term-encapsulation">encapsulation<a class="headerlink" href="#term-encapsulation" title="Link to this term">¶</a></dt><dd><p>The bundling up of attributes and methods into an object which
can be dealt with as a single unit.</p>
</dd>
<dt id="term-infix-operator">infix operator<a class="headerlink" href="#term-infix-operator" title="Link to this term">¶</a></dt><dd><p>A mathematical operator whose symbol is written between its <a class="reference internal" href="#term-operands"><span class="xref std std-term">operands</span></a>.
Examples include addition, subtraction, division and multiplication.</p>
</dd>
<dt id="term-instance">instance<a class="headerlink" href="#term-instance" title="Link to this term">¶</a></dt><dd><p>An object of a particular class. <code class="xref py py-obj docutils literal notranslate"><span class="pre">a</span></code> is an instance of
<code class="xref py py-class docutils literal notranslate"><span class="pre">MyClass</span></code> means that <code class="xref py py-obj docutils literal notranslate"><span class="pre">a</span></code> has class <code class="xref py py-obj docutils literal notranslate"><span class="pre">MyClass</span></code>. We will
return to this concept when we learn about <a class="reference internal" href="7_inheritance.html#inheritance"><span class="std std-ref">inheritance</span></a>.</p>
</dd>
<dt id="term-instantiate">instantiate<a class="headerlink" href="#term-instantiate" title="Link to this term">¶</a></dt><dd><p>To create an <a class="reference internal" href="#term-instance"><span class="xref std std-term">instance</span></a> of a <a class="reference internal" href="#term-class"><span class="xref std std-term">class</span></a> by
calling its <a class="reference internal" href="#term-constructor"><span class="xref std std-term">constructor</span></a>.</p>
</dd>
<dt id="term-method">method<a class="headerlink" href="#term-method" title="Link to this term">¶</a></dt><dt id="term-instance-method">instance method<a class="headerlink" href="#term-instance-method" title="Link to this term">¶</a></dt><dd><p>A function defined within a <a class="reference internal" href="#term-class"><span class="xref std std-term">class</span></a>. If <code class="xref py py-obj docutils literal notranslate"><span class="pre">a</span></code> is an
instance of <code class="xref py py-class docutils literal notranslate"><span class="pre">MyClass</span></code>, and <code class="xref py py-class docutils literal notranslate"><span class="pre">MyClass</span></code> has a <code class="xref py py-meth docutils literal notranslate"><span class="pre">foo()</span></code> method then
<code class="xref py py-obj docutils literal notranslate"><span class="pre">a.foo()</span></code> is equivalent to <code class="xref py py-obj docutils literal notranslate"><span class="pre">MyClass.foo(a)</span></code>. The first parameter
of an instance method is always named <code class="xref py py-obj docutils literal notranslate"><span class="pre">self</span></code>.</p>
</dd>
<dt id="term-operands">operands<a class="headerlink" href="#term-operands" title="Link to this term">¶</a></dt><dd><p>The input values to an operator. For example the operands to <code class="xref py py-obj docutils literal notranslate"><span class="pre">+</span></code> are the
numbers being added (the summands), while the operands to exponentiation
are the base and exponent.</p>
</dd>
<dt id="term-pseudocode">pseudocode<a class="headerlink" href="#term-pseudocode" title="Link to this term">¶</a></dt><dd><p>A description of an algorithm given in the form of a computer
program but without conforming to the rules of a particular
programming language, and employing mathematical notation or
plain text to express the algorithm in a human-readable form.</p>
</dd>
<dt id="term-special-method">special method<a class="headerlink" href="#term-special-method" title="Link to this term">¶</a></dt><dt id="term-magic-method">magic method<a class="headerlink" href="#term-magic-method" title="Link to this term">¶</a></dt><dd><p>A method which has special meaning in the Python
language. Special method names are used to define operations on
a <a class="reference internal" href="#term-class"><span class="xref std std-term">class</span></a> such as arithmetic operators, indexing, or the
class <a class="reference internal" href="#term-constructor"><span class="xref std std-term">constructor</span></a>. Special methods have names starting and ending
with a double underscore (<code class="xref py py-obj docutils literal notranslate"><span class="pre">__</span></code>). See <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#specialnames" title="(in Python v3.14)"><span class="xref std std-ref">the Python documentation</span></a> for a technical description. Special methods
are sometimes informally called “magic methods”.</p>
</dd>
</dl>
</div></blockquote>
</section>
<section id="exercises">
<h2><span class="section-number">3.7. </span>Exercises<a class="headerlink" href="#exercises" title="Link to this heading">¶</a></h2>
<p>Using the information on the <a class="reference external" href="https://object-oriented-python.github.io/edition3/exercises.html">book website</a>
obtain the skeleton code for these exercises. The skeleton code contains a
<code class="xref py py-mod docutils literal notranslate"><span class="pre">polynomial</span></code> package with a version of the <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> class.</p>
<div class="proof proof-type-exercise" id="id6">
<div class="proof-title">
<span class="proof-type">Exercise 3.3</span>
</div><div class="proof-content">
<p>Turn the exercises repository into an installable Pip package. As with
last chapter’s exercise, Pytest can’t test this so you’ll need to push to
GitHub and check that the autograding tests pass there.</p>
</div></div><div class="proof proof-type-exercise" id="id7">
<div class="proof-title">
<span class="proof-type">Exercise 3.4</span>
</div><div class="proof-content">
<p>Implement the following operations on the <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> class.</p>
<ol class="arabic simple">
<li><p>Subtraction (<a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__sub__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__sub__()</span></code></a> and <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__rsub__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__rsub__()</span></code></a>).</p></li>
<li><p>Multiplication by another polynomial, and by a scalar
(<a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__mul__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__mul__()</span></code></a> and <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__rmul__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__rmul__()</span></code></a>).</p></li>
<li><p>Exponentiation by a positive integer power (<a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__pow__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__pow__()</span></code></a>). It
may be useful to know that all integers are instances of
<a class="reference external" href="https://docs.python.org/3/library/numbers.html#numbers.Integral" title="(in Python v3.14)"><code class="xref py py-class docutils literal notranslate"><span class="pre">numbers.Integral</span></code></a>.</p></li>
<li><p>Polynomial evaluation at a scalar value (<a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__call__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__call__()</span></code></a>).</p></li>
</ol>
<div class="admonition hint">
<p class="admonition-title">Hint</p>
<p>A limitation of the provided implementation of <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> is
that it doesn’t strip leading zeroes. This means that it doesn’t
correctly identify that, for example, <code class="xref py py-obj docutils literal notranslate"><span class="pre">Polynomial((1,</span> <span class="pre">0))</span> <span class="pre">==</span>
<span class="pre">Polynomial((1,))</span></code>. You may find it convenient to remove this limitation
by removing any leading zeroes in <code class="xref py py-obj docutils literal notranslate"><span class="pre">Polynomial.__init__()</span></code>. If you do
this, take care that printing the zero polynomial still works.</p>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Don’t forget to commit and push your changes, and make sure that the
tests pass on GitHub!</p>
</div>
</div></div><div class="proof proof-type-exercise" id="id8">
<div class="proof-title">
<span class="proof-type">Exercise 3.5</span>
</div><div class="proof-content">
<p>Define a <code class="xref py py-meth docutils literal notranslate"><span class="pre">dx()</span></code> method on the <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> class which returns a
new <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> which is the derivative of that
<code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code>. Also define a function <code class="xref py py-obj docutils literal notranslate"><span class="pre">derivative</span></code> in
<code class="file docutils literal notranslate"><span class="pre">polynomials.py</span></code> which takes a <code class="xref py py-class docutils literal notranslate"><span class="pre">Polynomial</span></code> and returns its
derivative. Rather than duplicating code, you should implement the function
by calling the method.</p>
</div></div><div class="proof proof-type-exercise" id="id9">
<div class="proof-title">
<span class="proof-type">Exercise 3.6</span>
</div><div class="proof-content">
<p>Inside the exercise repository, create a new <code class="xref py py-mod docutils literal notranslate"><span class="pre">shape</span></code>
package containing a <code class="xref py py-mod docutils literal notranslate"><span class="pre">circle</span></code> module.</p>
<ol class="arabic">
<li><p>Create a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circle</span></code> class
whose <a class="reference internal" href="#term-constructor"><span class="xref std std-term">constructor</span></a> takes two user parameters, <code class="xref py py-obj docutils literal notranslate"><span class="pre">centre</span></code> and <code class="xref py py-obj docutils literal notranslate"><span class="pre">radius</span></code>.
<code class="xref py py-obj docutils literal notranslate"><span class="pre">centre</span></code> should be a length 2 sequence containing the two-dimensional
coordinates of the centre, while <code class="xref py py-obj docutils literal notranslate"><span class="pre">radius</span></code> is the radius of the circle.</p></li>
<li><p>Add an <a class="reference internal" href="2_programs_in_files.html#modules"><span class="std std-ref">import</span></a> statement to <code class="file docutils literal notranslate"><span class="pre">shape/__init__.py</span></code> so
that the following code works:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">shape</span><span class="w"> </span><span class="kn">import</span> <span class="n">Circle</span>
</pre></div>
</div>
</li>
<li><p>Implement the <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__contains__" title="(in Python v3.14)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__contains__()</span></code></a> <a class="reference internal" href="#term-special-method"><span class="xref std std-term">special method</span></a> on the
<code class="xref py py-class docutils literal notranslate"><span class="pre">Circle</span></code> class so that it returns <a class="reference external" href="https://docs.python.org/3/library/constants.html#True" title="(in Python v3.14)"><code class="xref py py-obj docutils literal notranslate"><span class="pre">True</span></code></a> if a point (represented
by a length 2 sequence of coordinates) lies inside the circle. For
example, the following code should print <a class="reference external" href="https://docs.python.org/3/library/constants.html#True" title="(in Python v3.14)"><code class="xref py py-obj docutils literal notranslate"><span class="pre">True</span></code></a>.</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">shape</span><span class="w"> </span><span class="kn">import</span> <span class="n">Circle</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">Circle</span><span class="p">((</span><span class="mf">1.</span><span class="p">,</span> <span class="mf">0.</span><span class="p">),</span> <span class="mi">2</span><span class="p">)</span>
<span class="nb">print</span><span class="p">((</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">)</span> <span class="ow">in</span> <span class="n">c</span><span class="p">)</span>
</pre></div>
</div>
</li>
</ol>
</div></div><p class="rubric">Footnotes</p>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="exercise-page" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id3">1</a><span class="fn-bracket">]</span></span>
<p><a class="reference external" href="https://object-oriented-python.github.io/edition3/exercises.html">https://object-oriented-python.github.io/edition3/exercises.html</a></p>
</aside>
</aside>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer" role="contentinfo">
© Copyright 2019-2023, David A. Ham.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 7.4.7.
</div>
</body>
</html>