forked from csev/py4e
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path14-objects.php
More file actions
793 lines (762 loc) · 31.6 KB
/
14-objects.php
File metadata and controls
793 lines (762 loc) · 31.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
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
<?php if ( file_exists("../booktop.php") ) {
require_once "../booktop.php";
ob_start();
}?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>-</title>
<style>
html {
color: #1a1a1a;
background-color: #fdfdfd;
}
body {
margin: 0 auto;
max-width: 36em;
padding-left: 50px;
padding-right: 50px;
padding-top: 50px;
padding-bottom: 50px;
hyphens: auto;
overflow-wrap: break-word;
text-rendering: optimizeLegibility;
font-kerning: normal;
}
@media (max-width: 600px) {
body {
font-size: 0.9em;
padding: 12px;
}
h1 {
font-size: 1.8em;
}
}
@media print {
html {
background-color: white;
}
body {
background-color: transparent;
color: black;
font-size: 12pt;
}
p, h2, h3 {
orphans: 3;
widows: 3;
}
h2, h3, h4 {
page-break-after: avoid;
}
}
p {
margin: 1em 0;
}
a {
color: #1a1a1a;
}
a:visited {
color: #1a1a1a;
}
img {
max-width: 100%;
}
svg {
height: auto;
max-width: 100%;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 1.4em;
}
h5, h6 {
font-size: 1em;
font-style: italic;
}
h6 {
font-weight: normal;
}
ol, ul {
padding-left: 1.7em;
margin-top: 1em;
}
li > ol, li > ul {
margin-top: 0;
}
blockquote {
margin: 1em 0 1em 1.7em;
padding-left: 1em;
border-left: 2px solid #e6e6e6;
color: #606060;
}
code {
font-family: Menlo, Monaco, Consolas, 'Lucida Console', monospace;
font-size: 85%;
margin: 0;
hyphens: manual;
}
pre {
margin: 1em 0;
overflow: auto;
}
pre code {
padding: 0;
overflow: visible;
overflow-wrap: normal;
}
.sourceCode {
background-color: transparent;
overflow: visible;
}
hr {
border: none;
border-top: 1px solid #1a1a1a;
height: 1px;
margin: 1em 0;
}
table {
margin: 1em 0;
border-collapse: collapse;
width: 100%;
overflow-x: auto;
display: block;
font-variant-numeric: lining-nums tabular-nums;
}
table caption {
margin-bottom: 0.75em;
}
tbody {
margin-top: 0.5em;
border-top: 1px solid #1a1a1a;
border-bottom: 1px solid #1a1a1a;
}
th {
border-top: 1px solid #1a1a1a;
padding: 0.25em 0.5em 0.25em 0.5em;
}
td {
padding: 0.125em 0.5em 0.25em 0.5em;
}
header {
margin-bottom: 4em;
text-align: center;
}
#TOC li {
list-style: none;
}
#TOC ul {
padding-left: 1.3em;
}
#TOC > ul {
padding-left: 0;
}
#TOC a:not(:hover) {
text-decoration: none;
}
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
</style>
</head>
<body>
<h1 id="object-oriented-programming">Object-oriented programming</h1>
<h2 id="managing-larger-programs">Managing larger programs</h2>
<p></p>
<p>At the beginning of this book, we came up with four basic programming
patterns which we use to construct programs:</p>
<ul>
<li>Sequential code</li>
<li>Conditional code (if statements)</li>
<li>Repetitive code (loops)</li>
<li>Store and reuse (functions)</li>
</ul>
<p>In later chapters, we explored simple variables as well as collection
data structures like lists, tuples, and dictionaries.</p>
<p>As we build programs, we design data structures and write code to
manipulate those data structures. There are many ways to write programs
and by now, you probably have written some programs that are “not so
elegant” and other programs that are “more elegant”. Even though your
programs may be small, you are starting to see how there is a bit of art
and aesthetic to writing code.</p>
<p>As programs get to be millions of lines long, it becomes increasingly
important to write code that is easy to understand. If you are working
on a million-line program, you can never keep the entire program in your
mind at the same time. We need ways to break large programs into
multiple smaller pieces so that we have less to look at when solving a
problem, fix a bug, or add a new feature.</p>
<p>In a way, object oriented programming is a way to arrange your code
so that you can zoom into 50 lines of the code and understand it while
ignoring the other 999,950 lines of code for the moment.</p>
<h2 id="getting-started">Getting started</h2>
<p>Like many aspects of programming, it is necessary to learn the
concepts of object oriented programming before you can use them
effectively. You should approach this chapter as a way to learn some
terms and concepts and work through a few simple examples to lay a
foundation for future learning.</p>
<p>The key outcome of this chapter is to have a basic understanding of
how objects are constructed and how they function and most importantly
how we make use of the capabilities of objects that are provided to us
by Python and Python libraries.</p>
<h2 id="using-objects">Using objects</h2>
<p>As it turns out, we have been using objects all along in this book.
Python provides us with many built-in objects. Here is some simple code
where the first few lines should feel very simple and natural to
you.</p>
<p></p>
<pre class="python"><code>stuff = list()
stuff.append('python')
stuff.append('chuck')
stuff.sort()
print (stuff[0])
print (stuff.__getitem__(0))
print (list.__getitem__(stuff,0))
# Code: https://www.py4e.com/code3/objects.py</code></pre>
<p>Instead of focusing on what these lines accomplish, let’s look at
what is really happening from the point of view of object-oriented
programming. Don’t worry if the following paragraphs don’t make any
sense the first time you read them because we have not yet defined all
of these terms.</p>
<p>The first line <em>constructs</em> an object of type
<code>list</code>, the second and third lines <em>call</em> the
<code>append()</code> <em>method</em>, the fourth line calls the
<code>sort()</code> method, and the fifth line <em>retrieves</em> the
item at position 0.</p>
<p>The sixth line calls the <code>__getitem__()</code> method in the
<code>stuff</code> list with a parameter of zero.</p>
<pre class="python"><code>print (stuff.__getitem__(0))</code></pre>
<p>The seventh line is an even more verbose way of retrieving the 0th
item in the list.</p>
<pre class="python"><code>print (list.__getitem__(stuff,0))</code></pre>
<p>In this code, we call the <code>__getitem__</code> method in the
<code>list</code> class and <em>pass</em> the list and the item we want
retrieved from the list as parameters.</p>
<p>The last three lines of the program are equivalent, but it is more
convenient to simply use the square bracket syntax to look up an item at
a particular position in a list.</p>
<p>We can take a look at the capabilities of an object by looking at the
output of the <code>dir()</code> function:</p>
<pre><code>>>> stuff = list()
>>> dir(stuff)
['__add__', '__class__', '__contains__', '__delattr__',
'__delitem__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__getitem__',
'__gt__', '__hash__', '__iadd__', '__imul__', '__init__',
'__iter__', '__le__', '__len__', '__lt__', '__mul__',
'__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__reversed__', '__rmul__', '__setattr__',
'__setitem__', '__sizeof__', '__str__', '__subclasshook__',
'append', 'clear', 'copy', 'count', 'extend', 'index',
'insert', 'pop', 'remove', 'reverse', 'sort']
>>></code></pre>
<p>The rest of this chapter will define all of the above terms so make
sure to come back after you finish the chapter and re-read the above
paragraphs to check your understanding.</p>
<h2 id="starting-with-programs">Starting with programs</h2>
<p>A program in its most basic form takes some input, does some
processing, and produces some output. Our elevator conversion program
demonstrates a very short but complete program showing all three of
these steps.</p>
<pre class="python"><code>usf = input('Enter the US Floor Number: ')
wf = int(usf) - 1
print('Non-US Floor Number is',wf)
# Code: https://www.py4e.com/code3/elev.py</code></pre>
<p>If we think a bit more about this program, there is the “outside
world” and the program. The input and output aspects are where the
program interacts with the outside world. Within the program we have
code and data to accomplish the task the program is designed to
solve.</p>
<figure>
<img src="../images/program.svg" alt="A Program" style="height: 1.20in;"/>
<figcaption>
A Program
</figcaption>
</figure>
<p>One way to think about object-oriented programming is that it
separates our program into multiple “zones.” Each zone contains some
code and data (like a program) and has well defined interactions with
the outside world and the other zones within the program.</p>
<p>If we look back at the link extraction application where we used the
BeautifulSoup library, we can see a program that is constructed by
connecting different objects together to accomplish a task:</p>
<p> </p>
<pre class="python"><code># To run this, download the BeautifulSoup zip file
# http://www.py4e.com/code3/bs4.zip
# or pip install beautifulsoup4 to ensure you have the latest version
# and unzip it in the same directory as this file
import urllib.request, urllib.parse, urllib.error
from bs4 import BeautifulSoup
import ssl # defauts to certicate verification and most secure protocol (now TLS)
# Ignore SSL/TLS certificate errors
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
url = input('Enter - ')
html = urllib.request.urlopen(url, context=ctx).read()
soup = BeautifulSoup(html, 'html.parser')
# Retrieve all of the anchor tags
tags = soup('a')
for tag in tags:
print(tag.get('href', None))
# Code: https://www.py4e.com/code3/urllinks.py</code></pre>
<p>We read the URL into a string and then pass that into
<code>urllib</code> to retrieve the data from the web. The
<code>urllib</code> library uses the <code>socket</code> library to make
the actual network connection to retrieve the data. We take the string
that <code>urllib</code> returns and hand it to BeautifulSoup for
parsing. BeautifulSoup makes use of the object
<code>html.parser</code><a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> and returns an object. We call the
<code>tags()</code> method on the returned object that returns a
dictionary of tag objects. We loop through the tags and call the
<code>get()</code> method for each tag to print out the
<code>href</code> attribute.</p>
<p>We can draw a picture of this program and how the objects work
together.</p>
<figure>
<img src="../images/program-oo.svg" alt="A Program as Network of Objects" style="height: 1.50in;"/>
<figcaption>
A Program as Network of Objects
</figcaption>
</figure>
<p>The key here is not to understand perfectly how this program works
but to see how we build a network of interacting objects and orchestrate
the movement of information between the objects to create a program. It
is also important to note that when you looked at that program several
chapters back, you could fully understand what was going on in the
program without even realizing that the program was “orchestrating the
movement of data between objects.” It was just lines of code that got
the job done.</p>
<h2 id="subdividing-a-problem">Subdividing a problem</h2>
<p>One of the advantages of the object-oriented approach is that it can
hide complexity. For example, while we need to know how to use the
<code>urllib</code> and BeautifulSoup code, we do not need to know how
those libraries work internally. This allows us to focus on the part of
the problem we need to solve and ignore the other parts of the
program.</p>
<figure>
<img src="../images/program-oo-code.svg" alt="Ignoring Detail When Using an Object" style="height: 1.50in;"/>
<figcaption>
Ignoring Detail When Using an Object
</figcaption>
</figure>
<p>This ability to focus exclusively on the part of a program that we
care about and ignore the rest is also helpful to the developers of the
objects that we use. For example, the programmers developing
BeautifulSoup do not need to know or care about how we retrieve our HTML
page, what parts we want to read, or what we plan to do with the data we
extract from the web page.</p>
<figure>
<img src="../images/program-oo-bs4.svg" alt="Ignoring Detail When Building an Object" style="height: 1.50in;"/>
<figcaption>
Ignoring Detail When Building an Object
</figcaption>
</figure>
<h2 id="our-first-python-object">Our first Python object</h2>
<p>At a basic level, an object is simply some code plus data structures
that are smaller than a whole program. Defining a function allows us to
store a bit of code and give it a name and then later invoke that code
using the name of the function.</p>
<p>An object can contain a number of functions (which we call
<em>methods</em>) as well as data that is used by those functions. We
call data items that are part of the object <em>attributes</em>.</p>
<p></p>
<p>We use the <code>class</code> keyword to define the data and code
that will make up each of the objects. The class keyword includes the
name of the class and begins an indented block of code where we include
the attributes (data) and methods (code).</p>
<pre class="python"><code>class PartyAnimal:
def __init__(self):
self.x = 0
def party(self) :
self.x = self.x + 1
print("So far",self.x)
an = PartyAnimal()
an.party()
an.party()
an.party()
# Code: https://www.py4e.com/code3/party2.py</code></pre>
<p>Each method looks like a function, starting with the <code>def</code>
keyword and consisting of an indented block of code.</p>
<p>The first method is a specially-named method called
<code>__init()__</code>. This method is called to do any initial setup
of the data we want to store in the object. In this class we allocate
the <code>x</code> attribute using dot notation and initialize it to
zero.</p>
<pre class="python"><code> self.x = 0</code></pre>
<p>The other method named <code>party</code>. The methods all have a
special first parameter that we name by convention <code>self</code>.
The first parameter gives us access to the object instance so we can set
attributes and call methods using dot notation.</p>
<p>Just as the <code>def</code> keyword does not cause function code to
be executed, the <code>class</code> keyword does not create an object.
Instead, the <code>class</code> keyword defines a template indicating
what data and code will be contained in each object of type
<code>PartyAnimal</code>. The class is like a cookie cutter and the
objects created using the class are the cookies<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>.
You don’t put frosting on the cookie cutter; you put frosting on the
cookies, and you can put different frosting on each cookie.</p>
<figure>
<img src="../photos/cookie_cutter_flickr_Didriks.png" alt="A Class and Two Objects" style="height: 2.0in;"/>
<figcaption>
A Class and Two Objects
</figcaption>
</figure>
<p>If we continue through this sample program, we see the first
executable line of code:</p>
<pre class="python"><code>an = PartyAnimal()</code></pre>
<p> </p>
<p>This is where we instruct Python to construct (i.e., create) an
<em>object</em> or <em>instance</em> of the class
<code>PartyAnimal</code>. It looks like a function call to the class
itself. Python constructs the object with the right data and methods and
returns the object which is then assigned to the variable
<code>an</code>. In a way this is quite similar to the following line
which we have been using all along:</p>
<pre class="python"><code>counts = dict()</code></pre>
<p>Here we instruct Python to construct an object using the
<code>dict</code> template (already present in Python), return the
instance of dictionary, and assign it to the variable
<code>counts</code>.</p>
<p>When the <code>PartyAnimal</code> class is used to construct an
object, the variable <code>an</code> is used to point to that object. We
use <code>an</code> to access the code and data for that particular
instance of the <code>PartyAnimal</code> class.</p>
<p>Each Partyanimal object/instance contains within it a variable
<code>x</code> and a method/function named <code>party</code>. We call
the <code>party</code> method in this line:</p>
<pre class="python"><code>an.party()</code></pre>
<p>When the <code>party</code> method is called, the first parameter
(which we call by convention <code>self</code>) points to the particular
instance of the PartyAnimal object that <code>party</code> is called
from. Within the <code>party</code> method, we see the line:</p>
<pre class="python"><code>self.x = self.x + 1</code></pre>
<p>This syntax using the <em>dot</em> operator is saying ‘the x within
self.’ Each time <code>party()</code> is called, the internal
<code>x</code> value is incremented by 1 and the value is printed
out.</p>
<p>The following line is another way to call the <code>party</code>
method within the <code>an</code> object:</p>
<pre class="python"><code>PartyAnimal.party(an)</code></pre>
<p>In this variation, we access the code from within the class and
explicitly pass the object pointer <code>an</code> as the first
parameter (i.e., <code>self</code> within the method). You can think of
<code>an.party()</code> as shorthand for the above line.</p>
<p>When the program executes, it produces the following output:</p>
<pre><code>So far 1
So far 2
So far 3
So far 4</code></pre>
<p>The object is constructed, and the <code>party</code> method is
called four times, both incrementing and printing the value for
<code>x</code> within the <code>an</code> object.</p>
<h2 id="classes-as-types">Classes as types</h2>
<p> </p>
<p>As we have seen, in Python all variables have a type. We can use the
built-in <code>dir</code> function to examine the capabilities of a
variable. We can also use <code>type</code> and <code>dir</code> with
the classes that we create.</p>
<pre class="python"><code>class PartyAnimal:
def __init__(self):
self.x = 0
def party(self) :
self.x = self.x + 1
print("So far",self.x)
an = PartyAnimal()
print ("Type", type(an))
print ("Dir ", dir(an))
print ("Type", type(an.x))
print ("Type", type(an.party))
# Code: https://www.py4e.com/code3/party3.py</code></pre>
<p>When this program executes, it produces the following output:</p>
<pre><code>Type <class '__main__.PartyAnimal'>
Dir ['__class__', '__delattr__', ...
'__sizeof__', '__str__', '__subclasshook__',
'__weakref__', 'party', 'x']
Type <class 'int'>
Type <class 'method'></code></pre>
<p>You can see that using the <code>class</code> keyword, we have
created a new type. From the <code>dir</code> output, you can see both
the <code>x</code> integer attribute and the <code>party</code> method
are available in the object.</p>
<h2 id="object-lifecycle">Object lifecycle</h2>
<p> </p>
<p>In the previous examples, we define a class (template), use that
class to create an instance of that class (object), and then use the
instance. When the program finishes, all of the variables are discarded.
Usually, we don’t think much about the creation and destruction of
variables, but often as our objects become more complex, we need to take
some action within the object to set things up as the object is
constructed and possibly clean things up as the object is discarded.</p>
<p>If we want our object to be aware of these moments of construction
and destruction, we add specially named methods to our object:</p>
<pre class="python"><code>class PartyAnimal:
def __init__(self):
self.x = 0
print('I am constructed')
def party(self) :
self.x = self.x + 1
print('So far',self.x)
def __del__(self):
print('I am destructed', self.x)
an = PartyAnimal()
an.party()
an.party()
an = 42
print('an contains',an)
# Code: https://www.py4e.com/code3/party4.py</code></pre>
<p>When this program executes, it produces the following output:</p>
<pre><code>I am constructed
So far 1
So far 2
I am destructed 2
an contains 42</code></pre>
<p>As Python constructs our object, it calls our <code>__init__</code>
method to give us a chance to set up some default or initial values for
the object. When Python encounters the line:</p>
<pre><code>an = 42</code></pre>
<p>It actually “throws our object away” so it can reuse the
<code>an</code> variable to store the value <code>42</code>. Just at the
moment when our <code>an</code> object is being “destroyed” our
destructor code (<code>__del__</code>) is called. We cannot stop our
variable from being destroyed, but we can do any necessary cleanup right
before our object no longer exists.</p>
<p>When developing objects, it is quite common to add a constructor to
an object to set up initial values for the object. It is relatively rare
to need a destructor for an object.</p>
<h2 id="multiple-instances">Multiple instances</h2>
<p>So far, we have defined a class, constructed a single object, used
that object, and then thrown the object away. However, the real power in
object-oriented programming happens when we construct multiple instances
of our class.</p>
<p>When we construct multiple objects from our class, we might want to
set up different initial values for each of the objects. We can pass
data to the constructors to give each object a different initial
value:</p>
<pre class="python"><code>class PartyAnimal:
def __init__(self, nam):
self.x = 0
self.name = nam
print(self.name,'constructed')
def party(self) :
self.x = self.x + 1
print(self.name,'party count',self.x)
s = PartyAnimal('Sally')
s.party()
j = PartyAnimal('Jim')
j.party()
s.party()
# Code: https://www.py4e.com/code3/party5.py</code></pre>
<p>The constructor has both a <code>self</code> parameter that points to
the object instance and additional parameters that are passed into the
constructor as the object is constructed:</p>
<pre><code>s = PartyAnimal('Sally')</code></pre>
<p>Within the constructor, the second line copies the parameter
(<code>nam</code>) that is passed into the <code>name</code> attribute
within the object instance.</p>
<pre><code>self.name = nam</code></pre>
<p>The output of the program shows that each of the objects
(<code>s</code> and <code>j</code>) contain their own independent copies
of <code>x</code> and <code>nam</code>:</p>
<pre><code>Sally constructed
Sally party count 1
Jim constructed
Jim party count 1
Sally party count 2</code></pre>
<h2 id="inheritance">Inheritance</h2>
<p> Another powerful feature of object-oriented programming is the
ability to create a new class by extending an existing class. When
extending a class, we call the original class the <em>parent class</em>
and the new class the <em>child class</em>.</p>
<p>For this example, we move our <code>PartyAnimal</code> class into its
own file. Then, we can ‘import’ the <code>PartyAnimal</code> class in a
new file and extend it, as follows:</p>
<pre class="python"><code>from party import PartyAnimal
class CricketFan(PartyAnimal):
def __init__(self, nam) :
super().__init__(nam)
self.points = 0
def six(self):
self.points = self.points + 6
self.party()
print(self.name,"points",self.points)
s = PartyAnimal("Sally")
s.party()
j = CricketFan("Jim")
j.party()
j.six()
print(dir(j))
# Code: https://www.py4e.com/code3/party6.py</code></pre>
<p>When we define the <code>CricketFan</code> class, we indicate that we
are extending the <code>PartyAnimal</code> class. This means that all of
the variables (<code>x</code>) and methods (<code>party</code>) from the
<code>PartyAnimal</code> class are <em>inherited</em> by the
<code>CricketFan</code> class. For example, within the <code>six</code>
method in the <code>CricketFan</code> class, we call the
<code>party</code> method from the <code>PartyAnimal</code> class.</p>
<p>We use a special syntax in the <code>__init__()</code> method in the
<code>CricketFan</code> class to ensure that we call the
<code>__init()__</code> method in the <code>PartyAnimal</code> so that
whatever setup that <code>PartyAnimal</code> needs is done in addition
to the setup needed for the <code>CriocketFan</code> extensions.</p>
<pre class="python"><code> def __init__(self, nam) :
super().__init__(nam)
self.points = 0</code></pre>
<p> The <code>super()</code> syntax is telling Python to call the
<code>__init__</code> method in the class that we are extending.
<code>PartyAnimal</code> is the super (or parent) class and
<code>CricketFan</code> is the sub (or child) class.</p>
<p>As the program executes, we create <code>s</code> and <code>j</code>
as independent instances of <code>PartyAnimal</code> and
<code>CricketFan</code>. The <code>j</code> object has additional
capabilities beyond the <code>s</code> object.</p>
<pre><code>Sally constructed
Sally party count 1
Jim constructed
Jim party count 1
Jim party count 2
Jim points 6
['__class__', '__delattr__', ... '__weakref__',
'name', 'party', 'points', 'six', 'x']</code></pre>
<p>In the <code>dir</code> output for the <code>j</code> object
(instance of the <code>CricketFan</code> class), we see that it has the
attributes and methods of the parent class, as well as the attributes
and methods that were added when the class was extended to create the
<code>CricketFan</code> class.</p>
<h2 id="summary">Summary</h2>
<p>This is a very quick introduction to object-oriented programming that
focuses mainly on terminology and the syntax of defining and using
objects. Let’s quickly review the code that we looked at in the
beginning of the chapter. At this point you should fully understand what
is going on.</p>
<pre class="python"><code>stuff = list()
stuff.append('python')
stuff.append('chuck')
stuff.sort()
print (stuff[0])
print (stuff.__getitem__(0))
print (list.__getitem__(stuff,0))
# Code: https://www.py4e.com/code3/objects.py</code></pre>
<p>The first line constructs a <code>list</code> <em>object</em>. When
Python creates the <code>list</code> object, it calls the
<em>constructor</em> method (named <code>__init__</code>) to set up the
internal data attributes that will be used to store the list data. We
have not passed any parameters to the <em>constructor</em>. When the
constructor returns, we use the variable <code>stuff</code> to point to
the returned instance of the <code>list</code> class.</p>
<p>The second and third lines call the <code>append</code> method with
one parameter to add a new item at the end of the list by updating the
attributes within <code>stuff</code>. Then in the fourth line, we call
the <code>sort</code> method with no parameters to sort the data within
the <code>stuff</code> object.</p>
<p>We then print out the first item in the list using the square
brackets which are a shortcut to calling the <code>__getitem__</code>
method within the <code>stuff</code>. This is equivalent to calling the
<code>__getitem__</code> method in the <code>list</code> <em>class</em>
and passing the <code>stuff</code> object as the first parameter and the
position we are looking for as the second parameter.</p>
<p>At the end of the program, the <code>stuff</code> object is discarded
but not before calling the <em>destructor</em> (named
<code>__del__</code>) so that the object can clean up any loose ends as
necessary.</p>
<p>Those are the basics of object-oriented programming. There are many
additional details as to how to best use object-oriented approaches when
developing large applications and libraries that are beyond the scope of
this chapter.<a href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a></p>
<h2 id="glossary">Glossary</h2>
<dl>
<dt>attribute</dt>
<dd>
A variable that is part of a class.
</dd>
<dt>class</dt>
<dd>
A template that can be used to construct an object. Defines the
attributes and methods that will make up the object.
</dd>
<dt>child class</dt>
<dd>
A new class created when a parent class is extended. The child class
inherits all of the attributes and methods of the parent class.
</dd>
<dt>constructor</dt>
<dd>
An optional specially named method (<code>__init__</code>) that is
called at the moment when a class is being used to construct an object.
Usually this is used to set up initial values for the object.
</dd>
<dt>destructor</dt>
<dd>
An optional specially named method (<code>__del__</code>) that is called
at the moment just before an object is destroyed. Destructors are rarely
used.
</dd>
<dt>inheritance</dt>
<dd>
When we create a new class (child) by extending an existing class
(parent). The child class has all the attributes and methods of the
parent class plus additional attributes and methods defined by the child
class.
</dd>
<dt>method</dt>
<dd>
A function that is contained within a class and the objects that are
constructed from the class. Some object-oriented patterns use ‘message’
instead of ‘method’ to describe this concept.
</dd>
<dt>object</dt>
<dd>
A constructed instance of a class. An object contains all of the
attributes and methods that were defined by the class. Some
object-oriented documentation uses the term ‘instance’ interchangeably
with ‘object’.
</dd>
<dt>parent class</dt>
<dd>
The class which is being extended to create a new child class. The
parent class contributes all of its methods and attributes to the new
child class.
</dd>
</dl>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>https://docs.python.org/3/library/html.parser.html<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Cookie image copyright CC-BY
https://www.flickr.com/photos/dinnerseries/23570475099<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>If you are curious about where the <code>list</code>
class is defined, take a look at (hopefully the URL won’t change)
https://github.com/python/cpython/blob/master/Objects/listobject.c - the
list class is written in a language called “C”. If you take a look at
that source code and find it curious you might want to explore C
programming with an eye towards building objects at
https://www.cc4e.com/.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
</body>
</html>
<?php if ( file_exists("../bookfoot.php") ) {
$HTML_FILE = basename(__FILE__);
$HTML = ob_get_contents();
ob_end_clean();
require_once "../bookfoot.php";
}?>