This commit is contained in:
Hykilpikonna
2021-12-07 22:28:01 -05:00
commit 6fffdf686a
151 changed files with 37985 additions and 0 deletions
+103
View File
@@ -0,0 +1,103 @@
<!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>9.1 An Introduction to Abstraction</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
</style>
<link rel="stylesheet" href="../tufte.css" />
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<div style="display:none">
\(
\newcommand{\NOT}{\neg}
\newcommand{\AND}{\wedge}
\newcommand{\OR}{\vee}
\newcommand{\XOR}{\oplus}
\newcommand{\IMP}{\Rightarrow}
\newcommand{\IFF}{\Leftrightarrow}
\newcommand{\TRUE}{\text{True}\xspace}
\newcommand{\FALSE}{\text{False}\xspace}
\newcommand{\IN}{\,{\in}\,}
\newcommand{\NOTIN}{\,{\notin}\,}
\newcommand{\TO}{\rightarrow}
\newcommand{\DIV}{\mid}
\newcommand{\NDIV}{\nmid}
\newcommand{\MOD}[1]{\pmod{#1}}
\newcommand{\MODS}[1]{\ (\text{mod}\ #1)}
\newcommand{\N}{\mathbb N}
\newcommand{\Z}{\mathbb Z}
\newcommand{\Q}{\mathbb Q}
\newcommand{\R}{\mathbb R}
\newcommand{\C}{\mathbb C}
\newcommand{\cA}{\mathcal A}
\newcommand{\cB}{\mathcal B}
\newcommand{\cC}{\mathcal C}
\newcommand{\cD}{\mathcal D}
\newcommand{\cE}{\mathcal E}
\newcommand{\cF}{\mathcal F}
\newcommand{\cG}{\mathcal G}
\newcommand{\cH}{\mathcal H}
\newcommand{\cI}{\mathcal I}
\newcommand{\cJ}{\mathcal J}
\newcommand{\cL}{\mathcal L}
\newcommand{\cK}{\mathcal K}
\newcommand{\cN}{\mathcal N}
\newcommand{\cO}{\mathcal O}
\newcommand{\cP}{\mathcal P}
\newcommand{\cQ}{\mathcal Q}
\newcommand{\cS}{\mathcal S}
\newcommand{\cT}{\mathcal T}
\newcommand{\cV}{\mathcal V}
\newcommand{\cW}{\mathcal W}
\newcommand{\cZ}{\mathcal Z}
\newcommand{\emp}{\emptyset}
\newcommand{\bs}{\backslash}
\newcommand{\floor}[1]{\left \lfloor #1 \right \rfloor}
\newcommand{\ceil}[1]{\left \lceil #1 \right \rceil}
\newcommand{\abs}[1]{\left | #1 \right |}
\newcommand{\xspace}{}
\newcommand{\proofheader}[1]{\underline{\textbf{#1}}}
\)
</div>
<header id="title-block-header">
<h1 class="title">9.1 An Introduction to Abstraction</h1>
</header>
<section>
<p>Abstraction is fundamental to our everyday lives, not just in computing. Loosely, abstraction is about understanding how to use something without knowing how it works. Consider your refrigerator—how does it work? Does it matter? We know that we can open a fridge door, place something (probably food) inside, and the fridge will keep it cold. So our notion of a fridge is really quite abstract; there are many thousands of refrigerator types, each one designed and built by different companies and people around the world. But this is irrelevant: when you go to a friends house, you can use their fridge just as you would your own, without any extra help.</p>
<p>There are several examples of abstraction in the real world. It doesnt matter how a watch was built, so long as we can use it to tell time. It doesnt matter how a cup was made or what materials it was made out of, so long as we can use it to hold liquid. Divorcing the nitty gritty details of how something works with how to use it is abstraction. And it is abstraction that has allowed for ingenuity and creativity to advance technology (i.e., how something works) without having to re-educate the entire world on how to use a cup.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> Of course, humans have also creatively improved how we use things, like attaching a handle to a cup meant to contain hot coffee.</span></p>
<p>We can think of abstraction as allowing for the separation of two groups of people with different goals: the <em>creators</em> of an entity, and the <em>users</em> (or <em>clients</em>) of that entity. Sometimes theres overlap between these two groups, but much of the time—especially as technology and systems have grown more complex—these two groups are fairly separate. Creators are responsible for designing, building, and implementing an entity, and users are responsible for, well, using it.</p>
<p>The <strong>interface</strong> of an entity is the boundary between creator and user: it is the set of rules (implicit or explicit) governing how users can interact with that entity. We call an interface the <em>public</em> side of an entity; it is the part of the creators work that everyone can interact it. Creators are responsible for the design of the interface, while users are responsible for learning the interface in order to interact with the entity. For example, the interface of a cup is how you use it: where to put liquid and where to hold it when taking a drink.</p>
<h2 id="abstraction-in-computer-science">Abstraction in computer science</h2>
<p>Abstraction and interfaces are incredibly useful concepts in computer science because of the complexity of programming languages, algorithms, and computer hardware that come with modern technology. Weve been using abstraction all the way through this course, playing the role of creator in some cases, and users in others:</p>
<ul>
<li><p>We are <em>users</em> of the Python programming language itself, which provides an interface that hides the details of our computer hardware, processor instructions, memory, storage, and graphics.<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> This isnt unique to Python, of course: <em>every</em> programming language is an interface between the programmer and their computer.</span> While we have learned some details about how the Python interpreter works (like our discussion of its array-based list implementation in the previous chapter), weve barely scratched the surface of this large and complex software.</p></li>
<li><p>We are <em>users</em> of built-in Python functions, data types, and modules. We dont know how the creators of the Python programming language have implemented these built-ins, but have learned how to <em>use</em> them to write useful programs.</p></li>
<li><p>We are <em>creators</em> of new Python functions, data types and modules. Each time you have followed the function or data class design recipe, you have created an interface.</p>
<p>For a <em>function</em>, its interface is its header and docstring: these specify how to call the function, the arguments it expects, and what the function does. The function body, is the implementation of the function, and are not part of its interface—someone who wants to use our function should not have to look a the function body to determine what it does.</p>
<p>For a <em>data class</em>, its interface is the name of the data class and the names and types of its attributes, and the class docstring. In other words, <em>every</em> part of what we write to define a new data class is part of its interface! How data classes are actually implemented has been hidden from us in the <code>@dataclass</code> decorator, though well begin learning about how this implementation works in the next section.</p>
<p>Finally, the interface of a Python <em>module</em> is simply the collection of interfaces of the functions and data types defined in that module, plus any additional documentation in the module docstring. For every Python file youve written so far, youve created a module that could be used by other programmers.</p></li>
<li><p>When studying mathematical statements, we have acted as both <em>users</em> and <em>creators</em>. Every time we write a proof, we act as a creator of knowledge, providing airtight evidence that a statement is True.<label for="sn-2" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-2" class="margin-toggle"/><span class="sidenote"> You can view a proof as an “implementation” of a statement. Rather than acting as a set of instructions to execute to complete a task, a proof is a set of statements that assert the truth of a statement.</span> Every time we use an “external statement” in a proof, like the Quotient-Remainder Theorem or Fermats Little Theorem, we are acting as <em>users</em> of these statements, and do not worry about how they have been proved.</p></li>
</ul>
<h2 id="interfaces-are-contracts">Interfaces are contracts</h2>
<p>As we work with more and more programming interfaces—different functions, data types, modules, and even programming languages—we see just how challenging designing interfaces can be. Every interface is a contract between creator and user: while creators have control over how they design an interface, they have the responsibility to make that interface easy and intuitive for users. Good interfaces are simple and strive to minimize the cognitive load on users; bad interfaces are cumbersome, ambiguous, and require the user to keep track of many unrelated details. Because interfaces are public, as creators we put a lot of effort into designing good interfaces, a topic well discuss in this year but that youll explore far more in future courses.</p>
<p>Moreover, because interfaces are contracts, they are hard to change once released—made public to users—as any change will have ramifications on every user. We have been the users used several Python modules so far, such as <code>timeit</code>, <code>pytest</code>, and <code>doctest</code>. What would happen if the creators of one of these modules decided to make a change to that interface, like changing the <code>timeit</code> function name to <code>time_it</code>? This one character change would cause all code that uses the <code>timeit.timeit</code> function to no longer work! As clients of the <code>timeit</code> module, we would not be very happy.</p>
<p>There are two sides to every contract. Just as creators are beholden to keep the interface they provide, users are limited to that interface as well. When we act as the creators of a function or module, we are free to modify their implementations in any way we wish, as long as we do not change the public interface. We can fix a bug, simplify the code, or use a more efficient algorithm, all to improve our implementation <em>without</em> affecting our users. In software engineering, it is important to clearly define what the public interface of a piece of code actually is, so that its creators know precisely what they must preserve and what they are free to change.</p>
<p>Over the next two chapters, well explore the concepts of abstraction, public interfaces, and private implementations in more detail. Well study how we can build our own Python data types from scratch (without relying on <code>@dataclass</code>) to gain full control over defining a data types public interface. Well create implementations of abstract data types and models of real-world domains, using the ideas weve introduced here to define clear public interfaces for every part of what we do.</p>
</section>
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>
+289
View File
@@ -0,0 +1,289 @@
<!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>9.2 Defining Our Own Data Types, Part 3</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="../tufte.css" />
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<div style="display:none">
\(
\newcommand{\NOT}{\neg}
\newcommand{\AND}{\wedge}
\newcommand{\OR}{\vee}
\newcommand{\XOR}{\oplus}
\newcommand{\IMP}{\Rightarrow}
\newcommand{\IFF}{\Leftrightarrow}
\newcommand{\TRUE}{\text{True}\xspace}
\newcommand{\FALSE}{\text{False}\xspace}
\newcommand{\IN}{\,{\in}\,}
\newcommand{\NOTIN}{\,{\notin}\,}
\newcommand{\TO}{\rightarrow}
\newcommand{\DIV}{\mid}
\newcommand{\NDIV}{\nmid}
\newcommand{\MOD}[1]{\pmod{#1}}
\newcommand{\MODS}[1]{\ (\text{mod}\ #1)}
\newcommand{\N}{\mathbb N}
\newcommand{\Z}{\mathbb Z}
\newcommand{\Q}{\mathbb Q}
\newcommand{\R}{\mathbb R}
\newcommand{\C}{\mathbb C}
\newcommand{\cA}{\mathcal A}
\newcommand{\cB}{\mathcal B}
\newcommand{\cC}{\mathcal C}
\newcommand{\cD}{\mathcal D}
\newcommand{\cE}{\mathcal E}
\newcommand{\cF}{\mathcal F}
\newcommand{\cG}{\mathcal G}
\newcommand{\cH}{\mathcal H}
\newcommand{\cI}{\mathcal I}
\newcommand{\cJ}{\mathcal J}
\newcommand{\cL}{\mathcal L}
\newcommand{\cK}{\mathcal K}
\newcommand{\cN}{\mathcal N}
\newcommand{\cO}{\mathcal O}
\newcommand{\cP}{\mathcal P}
\newcommand{\cQ}{\mathcal Q}
\newcommand{\cS}{\mathcal S}
\newcommand{\cT}{\mathcal T}
\newcommand{\cV}{\mathcal V}
\newcommand{\cW}{\mathcal W}
\newcommand{\cZ}{\mathcal Z}
\newcommand{\emp}{\emptyset}
\newcommand{\bs}{\backslash}
\newcommand{\floor}[1]{\left \lfloor #1 \right \rfloor}
\newcommand{\ceil}[1]{\left \lceil #1 \right \rceil}
\newcommand{\abs}[1]{\left | #1 \right |}
\newcommand{\xspace}{}
\newcommand{\proofheader}[1]{\underline{\textbf{#1}}}
\)
</div>
<header id="title-block-header">
<h1 class="title">9.2 Defining Our Own Data Types, Part 3</h1>
</header>
<section>
<p>All the way back in <a href="../04-complex-data/02-data-classes-1.html">Chapter 4</a>, we learned how to create our own simple data types in Python using the <code>@dataclass</code> decorator. While data classes are very useful, they are just one particular form of classes in Python. The <code>@dataclass</code> decorator takes our data class declaration—its <em>public interface</em>—and automatically creates an implementation of class. This makes it very simple to set up data classes, at the cost of flexibility of implementation.</p>
<p>In this section, well learn about how to create a Python data type from scratch, without the automatic implementation that <code>@dataclass</code> provides. In future sections, well apply what weve learned to defining new Python data types to solve various computational problems.</p>
<h2 id="what-if-we-just-remove-the-dataclass">What if we just remove the <code>@dataclass</code>?</h2>
<p>To start with, recall the <code>Person</code> data class example we used when we first introduced data classes:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1"></a><span class="at">@dataclass</span></span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="kw">class</span> Person:</span>
<span id="cb1-3"><a href="#cb1-3"></a> <span class="co">&quot;&quot;&quot;A custom data type that represents data for a person.&quot;&quot;&quot;</span></span>
<span id="cb1-4"><a href="#cb1-4"></a> given_name: <span class="bu">str</span></span>
<span id="cb1-5"><a href="#cb1-5"></a> family_name: <span class="bu">str</span></span>
<span id="cb1-6"><a href="#cb1-6"></a> age: <span class="bu">int</span></span>
<span id="cb1-7"><a href="#cb1-7"></a> address: <span class="bu">str</span></span></code></pre></div>
<p>We were able to use this data class to create and display an instance of the class and access its attributes:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1"></a><span class="op">&gt;&gt;&gt;</span> david <span class="op">=</span> Person(<span class="st">&#39;David&#39;</span>, <span class="st">&#39;Liu&#39;</span>, <span class="dv">100</span>, <span class="st">&#39;40 St. George Street&#39;</span>)</span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="op">&gt;&gt;&gt;</span> david</span>
<span id="cb2-3"><a href="#cb2-3"></a>Person(given_name<span class="op">=</span><span class="st">&#39;David&#39;</span>, family_name<span class="op">=</span><span class="st">&#39;Liu&#39;</span>, age<span class="op">=</span><span class="dv">100</span>, address<span class="op">=</span><span class="st">&#39;40 St. George Street&#39;</span>)</span>
<span id="cb2-4"><a href="#cb2-4"></a><span class="op">&gt;&gt;&gt;</span> david.given_name</span>
<span id="cb2-5"><a href="#cb2-5"></a><span class="co">&#39;David&#39;</span></span>
<span id="cb2-6"><a href="#cb2-6"></a><span class="op">&gt;&gt;&gt;</span> david.family_name</span>
<span id="cb2-7"><a href="#cb2-7"></a><span class="co">&#39;Liu&#39;</span></span>
<span id="cb2-8"><a href="#cb2-8"></a><span class="op">&gt;&gt;&gt;</span> david.age</span>
<span id="cb2-9"><a href="#cb2-9"></a><span class="dv">100</span></span>
<span id="cb2-10"><a href="#cb2-10"></a><span class="op">&gt;&gt;&gt;</span> david.address</span>
<span id="cb2-11"><a href="#cb2-11"></a><span class="co">&#39;40 St. George Street&#39;</span></span></code></pre></div>
<p>Now lets see what happens if we remove the <code>@dataclass</code> decorator from our class definition. This is indeed valid Python syntax, but with perhaps an unexpected consequence.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1"></a><span class="co"># @dataclass (We&#39;ve commented out this line)</span></span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="kw">class</span> Person:</span>
<span id="cb3-3"><a href="#cb3-3"></a> <span class="co">&quot;&quot;&quot;A custom data type that represents data for a person.&quot;&quot;&quot;</span></span>
<span id="cb3-4"><a href="#cb3-4"></a> given_name: <span class="bu">str</span></span>
<span id="cb3-5"><a href="#cb3-5"></a> family_name: <span class="bu">str</span></span>
<span id="cb3-6"><a href="#cb3-6"></a> age: <span class="bu">int</span></span>
<span id="cb3-7"><a href="#cb3-7"></a> address: <span class="bu">str</span></span>
<span id="cb3-8"><a href="#cb3-8"></a></span>
<span id="cb3-9"><a href="#cb3-9"></a></span>
<span id="cb3-10"><a href="#cb3-10"></a><span class="op">&gt;&gt;&gt;</span> david <span class="op">=</span> Person(<span class="st">&#39;David&#39;</span>, <span class="st">&#39;Liu&#39;</span>, <span class="dv">100</span>, <span class="st">&#39;40 St. George Street&#39;</span>)</span>
<span id="cb3-11"><a href="#cb3-11"></a><span class="pp">TypeError</span>: Person() takes no arguments</span></code></pre></div>
<p>Okay, something went wrong. Even though our class declaration still contains attribute names and type annotations, we cannot call <code>Person</code> and pass in values for those attributes. According to the error message, <code>Person() takes no arguments</code>. So what happens when we try to create an instance of <code>Person</code> and pass in zero arguments?</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1"></a><span class="op">&gt;&gt;&gt;</span> david <span class="op">=</span> Person()</span>
<span id="cb4-2"><a href="#cb4-2"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">type</span>(david)</span>
<span id="cb4-3"><a href="#cb4-3"></a><span class="op">&lt;</span><span class="kw">class</span> <span class="st">&#39;Person&#39;</span><span class="op">&gt;</span></span></code></pre></div>
<p>We successfully created an instance of the <code>Person</code> class. But what happens when we try to access the instance attributes?</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1"></a><span class="op">&gt;&gt;&gt;</span> david.given_name</span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="pp">AttributeError</span>: <span class="st">&#39;Person&#39;</span> <span class="bu">object</span> has no attribute <span class="st">&#39;given_name&#39;</span></span></code></pre></div>
<p>This should make sense: by just calling <code>Person()</code> with no arguments, we havent specified values for any of the instance attributes, so we shouldnt expect to see a value when we access <code>david.given_name</code>.</p>
<h2 id="defining-an-initializer">Defining an initializer</h2>
<p>When we execute the statement <code>david = Person()</code>, all we have in memory is this:</p>
<p><img src="images/empty-person.png" alt="An empty instance of Person" /><br />
</p>
<p>A <code>Person</code> object has been created, but it has no attributes. To fix this (without using <code>@dataclass</code>), we need to define a new method for <code>Person</code> called the <strong>initializer</strong>. The initializer method of a class is called when an instance of the class is created in Python. As its name suggests, the purpose of this method it to initialize all of the instance attributes for the new object. To distinguish it from regular functions, Python always uses the name <code>__init__</code> for the initializer method.</p>
<p>When we use the <code>@dataclass</code> decorator, the Python interpreter automatically creates an initializer method for the class. So lets start by seeing what this “automatic” code for the initializer looks like.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">class</span> Person:</span>
<span id="cb6-2"><a href="#cb6-2"></a> <span class="co">&quot;&quot;&quot;A custom data type that represents data for a person.&quot;&quot;&quot;</span></span>
<span id="cb6-3"><a href="#cb6-3"></a> given_name: <span class="bu">str</span></span>
<span id="cb6-4"><a href="#cb6-4"></a> family_name: <span class="bu">str</span></span>
<span id="cb6-5"><a href="#cb6-5"></a> age: <span class="bu">int</span></span>
<span id="cb6-6"><a href="#cb6-6"></a> address: <span class="bu">str</span></span>
<span id="cb6-7"><a href="#cb6-7"></a></span>
<span id="cb6-8"><a href="#cb6-8"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, given_name: <span class="bu">str</span>, family_name: <span class="bu">str</span>, age: <span class="bu">int</span>, address: <span class="bu">str</span>) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb6-9"><a href="#cb6-9"></a> <span class="co">&quot;&quot;&quot;Initialize a new Person object.&quot;&quot;&quot;</span></span>
<span id="cb6-10"><a href="#cb6-10"></a> <span class="va">self</span>.given_name <span class="op">=</span> given_name</span>
<span id="cb6-11"><a href="#cb6-11"></a> <span class="va">self</span>.family_name <span class="op">=</span> family_name</span>
<span id="cb6-12"><a href="#cb6-12"></a> <span class="va">self</span>.age <span class="op">=</span> age</span>
<span id="cb6-13"><a href="#cb6-13"></a> <span class="va">self</span>.address <span class="op">=</span> address</span></code></pre></div>
<p>Since all methods are functions, it should not surprise you to learn that we define methods using the same keyword (<code>def</code>) as other functions. However, there are two key differences between this method definition and all top-level function definitions weve studied so far. The first is that this method definition is <em>indented</em> so that it is inside the body of the <code>class Person</code> definition. This is how we signal that the function being defined is a method for the <code>Person</code> class.</p>
<p>The second difference is the presence of the parameter <code>self</code>. Every initializer has a first parameter that refers to the instance that has just been created and is to be initialized. By convention, we always call it <code>self</code>. This is such a strong Python convention that most code checkers will complain if you dont follow it.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> This name is the reason we refer to attributes as <code>self.&lt;attr&gt;</code> in class representation invariants.</span> In fact, this convention is so strong that we also typically omit the type annotation for <code>self</code>. We could have written <code>self: Person</code>, but because the type of <code>self</code> should <em>always</em> be the class that the initializer belongs to, this is considered redundant in Python!</p>
<p>To understand how <code>self</code> works, lets examine how we use the initializer:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1"></a><span class="op">&gt;&gt;&gt;</span> david <span class="op">=</span> Person(<span class="st">&#39;David&#39;</span>, <span class="st">&#39;Liu&#39;</span>, <span class="dv">100</span>, <span class="st">&#39;40 St. George Street&#39;</span>)</span></code></pre></div>
<p>Notice that we never mention the initializer <code>__init__</code> by name; it is called automatically, and the values in parentheses are passed to it. Also notice that we pass four values to the initializer, even though it has five parameters. We never have to pass a value for <code>self</code>; Python automatically sets it to the instance that is to be initialized. So this is what is happening in memory at the beginning of the initializer:</p>
<p><img src="images/person-initializer-start.png" alt="Memory at the start of Person.__init__" /><br />
</p>
<p>The initializers job is to create and initialize the instance attributes. To do this, we use one assignment statement per instance attribute. This uses the same dot notation syntax that we saw in Chapter 5 for assigning to instance attributes: <code>self.given_name = given_name</code>, for example. Note that <code>given_name</code> and <code>self.given_name</code> are two different expressions! <code>given_name</code> is a <em>parameter</em> of the initialize, while <code>self.given_name</code> is an <em>instance attribute</em>.<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> Some other programming languages like Java allow you to refer to instance attributes without using dot notation. In Python, however, dot notation is <em>mandatory</em> for accessing and assigning to instance attributes.</span> We can illustrate this distinction by showing the state of memory after all attributes have been initialized, immediately before the initializer returns:</p>
<p><img src="images/person-initializer-end.png" alt="Memory at the end of Person.__init__" /><br />
</p>
<h3 id="what-really-happens-when-we-create-a-new-object">What really happens when we create a new object</h3>
<p>You may have noticed that the initializer return type is <code>None</code>, and that the body of the function does not actually return anything. This is a bit strange, since when we evaluate <code>david = Person('David', 'Liu', 100, '40 St. George Street')</code>, a <code>Person</code> object is definitely returned from the function call and assigned to the variable <code>david</code>.</p>
<p><img src="images/person-initializer-after-return.png" alt="Memory after Person.__init__ returns" /><br />
</p>
<p>Whats going on? It turns out that calling <code>Person</code> doesnt just cause <code>__init__</code> to be called. It actually does three things:<label for="sn-2" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-2" class="margin-toggle"/><span class="sidenote">Of course, this is true not just for our <code>Person</code> class, but in fact <em>every</em> class in Python.</span></p>
<ol type="1">
<li>Create a new <code>Person</code> object behind the scenes.</li>
<li>Call <code>__init__</code> with the new object passed to the parameter <code>self</code>, along with the other arguments.</li>
<li>Return the new object. This step is where the object is returned, not directly from the call to <code>__init__</code> in Step 2.</li>
</ol>
<p>So in fact, <code>__init__</code> is a <em>helper function</em> in the object creation process. Its task is only to initialize attributes for an object; Python handles both creating the object beforehand, and returning the new object after <code>__init__</code> has been called.</p>
<h2 id="methods-as-part-of-a-data-type-interface">Methods as part of a data type interface</h2>
<p>It is certainly possible to accomplish everything that we would ever want to do with our <code>Person</code> class by writing top-level functions, and this is the approach weve taken with data classes up to this point. An alternate and commonly-used approach is to define <em>methods</em> for a data type, which become part of the interface of that data type. Remember that methods are just functions that belong to a data type—but this “belonging to” is not just an abstract relationship, but creates concrete consequences for how the Python interpreter handles them. When we define a data class and top-level functions, the interface of a data class itself only consists of its attributes; we have to remember to import those functions separately in order to use them. When we define a class with methods, those methods are <em>always</em> bundled with the class, and so any instance of the class can use those methods, without needing to import them separately.</p>
<p>We have seen one example of a method definition already: the initializer, <code>__init__</code>. More generally, any function that operates on an instance of a class can be converted into a method by doing the following:</p>
<ul>
<li>Indent the function so that it is part of the class body, underneath the innstance attributes.</li>
<li>Ensure that the first parameter of the function is an instance of the class, and name this parameter <code>self</code>.</li>
</ul>
<p>For example, suppose we had the following function to increase a persons age:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1"></a><span class="kw">def</span> increase_age(person: Person, years: <span class="bu">int</span>) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb8-2"><a href="#cb8-2"></a> <span class="co">&quot;&quot;&quot;Add the given number of years to the given person&#39;s age.</span></span>
<span id="cb8-3"><a href="#cb8-3"></a></span>
<span id="cb8-4"><a href="#cb8-4"></a><span class="co"> &gt;&gt;&gt; david = Person(&#39;David&#39;, &#39;Liu&#39;, 100, &#39;40 St. George Street&#39;)</span></span>
<span id="cb8-5"><a href="#cb8-5"></a><span class="co"> &gt;&gt;&gt; increase_age(david, 10)</span></span>
<span id="cb8-6"><a href="#cb8-6"></a><span class="co"> &gt;&gt;&gt; david.age</span></span>
<span id="cb8-7"><a href="#cb8-7"></a><span class="co"> 110</span></span>
<span id="cb8-8"><a href="#cb8-8"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb8-9"><a href="#cb8-9"></a> person.age <span class="op">=</span> person.age <span class="op">+</span> years</span></code></pre></div>
<p>We can turn <code>increase_age</code> into a <code>Person</code> method as follows:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1"></a><span class="kw">class</span> Person:</span>
<span id="cb9-2"><a href="#cb9-2"></a> <span class="co">&quot;&quot;&quot;A custom data type that represents data for a person.&quot;&quot;&quot;</span></span>
<span id="cb9-3"><a href="#cb9-3"></a> given_name: <span class="bu">str</span></span>
<span id="cb9-4"><a href="#cb9-4"></a> family_name: <span class="bu">str</span></span>
<span id="cb9-5"><a href="#cb9-5"></a> age: <span class="bu">int</span></span>
<span id="cb9-6"><a href="#cb9-6"></a> address: <span class="bu">str</span></span>
<span id="cb9-7"><a href="#cb9-7"></a></span>
<span id="cb9-8"><a href="#cb9-8"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, given_name: <span class="bu">str</span>, family_name: <span class="bu">str</span>, age: <span class="bu">int</span>, address: <span class="bu">str</span>) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb9-9"><a href="#cb9-9"></a> <span class="co">&quot;&quot;&quot;Initialize a new Person object.&quot;&quot;&quot;</span></span>
<span id="cb9-10"><a href="#cb9-10"></a> <span class="va">self</span>.given_name <span class="op">=</span> given_name</span>
<span id="cb9-11"><a href="#cb9-11"></a> <span class="va">self</span>.family_name <span class="op">=</span> family_name</span>
<span id="cb9-12"><a href="#cb9-12"></a> <span class="va">self</span>.age <span class="op">=</span> age</span>
<span id="cb9-13"><a href="#cb9-13"></a> <span class="va">self</span>.address <span class="op">=</span> address</span>
<span id="cb9-14"><a href="#cb9-14"></a></span>
<span id="cb9-15"><a href="#cb9-15"></a> <span class="kw">def</span> increase_age(<span class="va">self</span>, years: <span class="bu">int</span>) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb9-16"><a href="#cb9-16"></a> <span class="co">&quot;&quot;&quot;Add the given number of years to this person&#39;s age.</span></span>
<span id="cb9-17"><a href="#cb9-17"></a></span>
<span id="cb9-18"><a href="#cb9-18"></a><span class="co"> &gt;&gt;&gt; david = Person(&#39;David&#39;, &#39;Liu&#39;, 100, &#39;40 St. George Street&#39;)</span></span>
<span id="cb9-19"><a href="#cb9-19"></a><span class="co"> &gt;&gt;&gt; Person.increase_age(david, 10)</span></span>
<span id="cb9-20"><a href="#cb9-20"></a><span class="co"> &gt;&gt;&gt; david.age</span></span>
<span id="cb9-21"><a href="#cb9-21"></a><span class="co"> 110</span></span>
<span id="cb9-22"><a href="#cb9-22"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb9-23"><a href="#cb9-23"></a> <span class="va">self</span>.age <span class="op">=</span> <span class="va">self</span>.age <span class="op">+</span> years</span></code></pre></div>
<p>Notice that we now use parameter <code>self</code> (without a type annotation) to access instance attributes, just as we did in the initializer. In our function docstring, the phrase “the given person” changes to “this person”,<label for="sn-3" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-3" class="margin-toggle"/><span class="sidenote"> We typically use the word “this” in a method docstring to refer to the object instance that <code>self</code> refers to. In fact, some other programming languages also use <code>this</code> instead of <code>self</code> as a variable or keyword to refer to this object in code.</span> and our doctest example changes the call to <code>increase_age</code> to <code>Person.increase_age</code>.</p>
<h3 id="shortcut-syntax-for-method-calls">Shortcut syntax for method calls</h3>
<p>Now that we are starting to define our own custom classes and methods, we are ready to see a shorthand for calling methods in Python. Lets take a look at the method call from our doctest above:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1"></a><span class="op">&gt;&gt;&gt;</span> Person.increase_age(david, <span class="dv">10</span>)</span></code></pre></div>
<p>This uses dot notation to access the <code>increase_age</code> method of the <code>Person</code> class, calling it with the two arguments <code>david</code> and <code>10</code>, which get assigned to parameters <code>self</code> and <code>years</code>, respectively.</p>
<p>The alternate form for calling the <code>increase_age</code> method is to use dot notation <em>with the <code>Person</code> instance directly</em>:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb11-1"><a href="#cb11-1"></a><span class="op">&gt;&gt;&gt;</span> david.increase_age(<span class="dv">10</span>)</span></code></pre></div>
<p>When we call <code>david.increase_age(10)</code>, the Python interpreter does the following:</p>
<ol type="1">
<li>It looks up the class of <code>david</code>, which is <code>Person</code>.</li>
<li>It looks up the <code>increase_age</code> method of the <code>Person</code> class.</li>
<li>It calls <code>Person.increase_age</code> on <code>david</code> and <code>10</code>. In other words, the interpreter <em>automatically</em> passes the value to the left of the dot (in this case, the object <code>david</code> refers to) as the methods first parameter <code>self</code>.</li>
</ol>
<p>This works not just for our custom class <code>Person</code>, but all built-in data types as well. For example, <code>list.append(lst, 10)</code> can be written as <code>lst.append(10)</code>, and <code>str.lower(s)</code> as simply <code>s.lower()</code>. More generally, a method call of the form <code>obj.method(x1, x2, ..., xn)</code> is equivalent to <code>type(obj).method(obj, x1, x2, ..., xn)</code>.</p>
<p>Though weve been using the more explicit “class dot notation” style (<code>Person.increase_age</code>) so far in this course, well switch over to the “object dot notation” style (<code>david.increase_age</code>) starting in this chapter, as this is the much more common style in Python programming. There are two primary reasons why the latter style is standard:</p>
<ol type="1">
<li><p>It matches other languages with an <em>object-oriented</em> style of programming, where the object being operated own is of central importance. Because we read from left to right, every time we use dot notation with the instance object on the left, we are reminded that it is an object we are working with, whether we are accessing a piece of data bundled with that object or performing an operation on that object.</p>
<p>We read <code>david.age</code> as “access <code>david</code>s age” and <code>david.increase_age(10)</code> as “increase <code>david</code>s age by 10”. In both cases, <code>david</code> is the most important object in the code expression.</p></li>
<li><p>Only the “object dot notation” style of method call supports <em>inheritance</em>, which is a technical feature of classes that well discuss in the next chapter.</p></li>
</ol>
</section>
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>
+183
View File
@@ -0,0 +1,183 @@
<!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>9.3 Data Types, Abstract and Concrete</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="../tufte.css" />
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<div style="display:none">
\(
\newcommand{\NOT}{\neg}
\newcommand{\AND}{\wedge}
\newcommand{\OR}{\vee}
\newcommand{\XOR}{\oplus}
\newcommand{\IMP}{\Rightarrow}
\newcommand{\IFF}{\Leftrightarrow}
\newcommand{\TRUE}{\text{True}\xspace}
\newcommand{\FALSE}{\text{False}\xspace}
\newcommand{\IN}{\,{\in}\,}
\newcommand{\NOTIN}{\,{\notin}\,}
\newcommand{\TO}{\rightarrow}
\newcommand{\DIV}{\mid}
\newcommand{\NDIV}{\nmid}
\newcommand{\MOD}[1]{\pmod{#1}}
\newcommand{\MODS}[1]{\ (\text{mod}\ #1)}
\newcommand{\N}{\mathbb N}
\newcommand{\Z}{\mathbb Z}
\newcommand{\Q}{\mathbb Q}
\newcommand{\R}{\mathbb R}
\newcommand{\C}{\mathbb C}
\newcommand{\cA}{\mathcal A}
\newcommand{\cB}{\mathcal B}
\newcommand{\cC}{\mathcal C}
\newcommand{\cD}{\mathcal D}
\newcommand{\cE}{\mathcal E}
\newcommand{\cF}{\mathcal F}
\newcommand{\cG}{\mathcal G}
\newcommand{\cH}{\mathcal H}
\newcommand{\cI}{\mathcal I}
\newcommand{\cJ}{\mathcal J}
\newcommand{\cL}{\mathcal L}
\newcommand{\cK}{\mathcal K}
\newcommand{\cN}{\mathcal N}
\newcommand{\cO}{\mathcal O}
\newcommand{\cP}{\mathcal P}
\newcommand{\cQ}{\mathcal Q}
\newcommand{\cS}{\mathcal S}
\newcommand{\cT}{\mathcal T}
\newcommand{\cV}{\mathcal V}
\newcommand{\cW}{\mathcal W}
\newcommand{\cZ}{\mathcal Z}
\newcommand{\emp}{\emptyset}
\newcommand{\bs}{\backslash}
\newcommand{\floor}[1]{\left \lfloor #1 \right \rfloor}
\newcommand{\ceil}[1]{\left \lceil #1 \right \rceil}
\newcommand{\abs}[1]{\left | #1 \right |}
\newcommand{\xspace}{}
\newcommand{\proofheader}[1]{\underline{\textbf{#1}}}
\)
</div>
<header id="title-block-header">
<h1 class="title">9.3 Data Types, Abstract and Concrete</h1>
</header>
<section>
<p>So far in this course, weve used the term <em>data type</em> to actually mean two different things. Most of the time, we use it to mean a data type in the Python programming language, like <code>int</code> or <code>list</code> or a data class weve defined. When we use the term “data type” in this way, it is synonymous with the term <em>Python class</em>, which is the name the Python language gives to all of its data types. Well now call refer to these Python classes as <strong>concrete data types</strong>, since they have a concrete implementation in Python code. This is true for both built-in data types, data classes that we define, and the more general classes we learned about in <a href="02-classes.html">Section 9.2</a>.</p>
<p>However, theres another way weve used the term “data type” that goes all the way back to <a href="../01-working-with-data/01-data-types.html">1.1 The Different Types of Data</a>: as abstract representations of data that transcend any one specific programming language. For example, the Python <code>list</code> class is implemented differently than the Java <code>ArrayList</code> or JavaScript <code>Array</code>, but all three share some common expectations of what list operations they support. We can describe these common, language-independent list operations by defining an <strong>abstract data type (ADT)</strong>, which defines an entity that stores some kind of data and the operations that can be performed on it. Using the terminology from [Section 9.1], an abstract data type is a pure interface it is concerned only with the <em>what</em>—what data is stored, what we can do with this data—and not the <em>how</em>—how a computer actually stores this data or implements these operations.</p>
<h2 id="familiar-abstract-data-types">Familiar abstract data types</h2>
<p>Lets take a moment here to review some of the collection-based abstract data types weve seen already in this course.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> One caveat with this list: while computer scientists generally agree on what the “main” abstract data types are, they often disagree on what operations each one actually supports. Youll notice here that weve taken a fairly conservative approach for specifying operations, limiting ourselves to the most basic ones.</span></p>
<ul>
<li><p><strong>Set</strong></p>
<ul>
<li>Data: a collection of unique elements</li>
<li>Operations: get size, insert a value (without introducing duplicates), remove a specified value, check membership in the set.</li>
</ul></li>
<li><p><strong>List</strong></p>
<ul>
<li>Data: an ordered sequence of elements (which may or may not be unique)</li>
<li>Operations: get size, access element by index, insert a value at a given index, remove a value at a given index</li>
</ul></li>
<li><p><strong>Mapping</strong></p>
<ul>
<li>Data: a collection of key-value pairs, where each key is unique and associated with a single value</li>
<li>Operations: get size, lookup a value for a given key, insert a new key-value pair, remove a key-value pair, update the value associated with a given key</li>
</ul></li>
<li><p><strong>Iterable</strong></p>
<ul>
<li>Data: a collection of values (may or may not be unique)</li>
<li>Operations: iterate through the elements of the collection one at a time.</li>
</ul></li>
</ul>
<p>There are a few more foundational abstract data types in computer science that well cover in this chapter, and in future courses. We have discussed many of these throughout the semester so far, and have used many in Python. But the true power of ADTs is that they are abstract enough to transcend any individual program or even programming languages. ADTs like lists, sets, and maps form a common vocabulary that is necessary to being a professional computer scientist.</p>
<h2 id="abstract-vs.-concrete-data-types">Abstract vs. concrete data types</h2>
<p>Abstract data types form a high-level interface between a computer scientist and how the computer stores program data. A concrete data type is an implementation of an abstract data type: unlike abstract data types, they <em>are</em> actually concerned with how the data is stored and how their operations are implemented. The creators of the Python programming language took various abstract data types and created a set of built-in concrete data types (classes), making careful decisions about how each class would store its data and implement its methods. Indeed, as Python programmers we benefit from all the work theyve put in to create classes that not just support common ADTs, but to make their implementations extremely fast using clever programming techniques.<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> Youll learn about some of these techniques in CSC263/265!</span></p>
<p>So a <code>dict</code>, for instance, is not itself an abstract data type. But the <code>dict</code> data type is an obvious implementation of the Mapping ADT. However, <em>there is NOT a one-to-one correspondence between abstract data types and concrete data types</em>, in Python or any other programming language. A single abstract data type can be implemented by many different concrete data types. For example, although the Python <code>dict</code> is a natural implementation of the Mapping ADT, we could implement the Mapping ADT instead with a <code>list</code>, where each element is a tuple storing a key-value pair:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1"></a><span class="co"># A Map using a Python dict</span></span>
<span id="cb1-2"><a href="#cb1-2"></a>{<span class="dv">0</span>: <span class="st">&#39;hello&#39;</span>, <span class="dv">1</span>: <span class="dv">42</span>, <span class="dv">2</span>: <span class="st">&#39;goodbye&#39;</span>}</span>
<span id="cb1-3"><a href="#cb1-3"></a></span>
<span id="cb1-4"><a href="#cb1-4"></a><span class="co"># A Map using a Python list</span></span>
<span id="cb1-5"><a href="#cb1-5"></a>[(<span class="dv">0</span>, <span class="st">&#39;hello&#39;</span>), (<span class="dv">1</span>, <span class="dv">42</span>), (<span class="dv">2</span>, <span class="st">&#39;goodbye&#39;</span>)]</span></code></pre></div>
<p>Conversely, every concrete data type can be used to implement multiple ADTs. The Python <code>list</code> can be used to implement not just the List ADT, but each of the other above ADTs as well. For instance, think about how you would implement the Set ADT with a <code>list</code>, and in particular, how you would avoid duplicates.<label for="sn-2" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-2" class="margin-toggle"/><span class="sidenote"> Though just because something is possible doesnt mean it is a good idea in practice. Beginning Python programmers often implement use a <code>list</code> when all they need is the Set ADTs operations. As we discussed in <a href="../08-runtime/09-data-types-runtime.html">Section 8.6</a>, this leads to slower programs, and so should be avoided.</span> A <code>dict</code> could also implement any of the ADTs above, and the same is true of the new data structures you will learn in this course.</p>
<p>You might be wondering what is the point of making this distinction—so what if <code>list</code>s can implement the Mapping ADT, wed never use this in “real” Python code when we have a <code>dict</code> instead. And thats true! But what this distinction reminds us is that we always have <em>choices</em> when implementing an interface. Rather than saying “its not possible to implement a Map using <code>list</code>”, we instead say “it is possible to implement a Map using <code>list</code>, but this choice is worse than using <code>dict</code>”.</p>
<p>Any idea why is a <code>dict</code> better than <code>list</code> at implementing the Mapping ADT? If we ignore the fact that weve been using <code>dict</code> for this purpose all along, the answer is not obvious! It comes down to <em>efficiency</em>: though <code>dict</code> and <code>list</code> can both be used to implement the Map ADT, the implementation of <code>dict</code> makes the Mapping operations much faster than how we would (straightforwardly) implement the Mapping ADT using a <code>list</code>. As well see a few times this chapter, running time analysis is one of the key ways to evaluate and compare different implementations of an ADT.</p>
</section>
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>
+347
View File
@@ -0,0 +1,347 @@
<!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>9.4 Stacks</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="../tufte.css" />
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" type="text/javascript"></script>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<div style="display:none">
\(
\newcommand{\NOT}{\neg}
\newcommand{\AND}{\wedge}
\newcommand{\OR}{\vee}
\newcommand{\XOR}{\oplus}
\newcommand{\IMP}{\Rightarrow}
\newcommand{\IFF}{\Leftrightarrow}
\newcommand{\TRUE}{\text{True}\xspace}
\newcommand{\FALSE}{\text{False}\xspace}
\newcommand{\IN}{\,{\in}\,}
\newcommand{\NOTIN}{\,{\notin}\,}
\newcommand{\TO}{\rightarrow}
\newcommand{\DIV}{\mid}
\newcommand{\NDIV}{\nmid}
\newcommand{\MOD}[1]{\pmod{#1}}
\newcommand{\MODS}[1]{\ (\text{mod}\ #1)}
\newcommand{\N}{\mathbb N}
\newcommand{\Z}{\mathbb Z}
\newcommand{\Q}{\mathbb Q}
\newcommand{\R}{\mathbb R}
\newcommand{\C}{\mathbb C}
\newcommand{\cA}{\mathcal A}
\newcommand{\cB}{\mathcal B}
\newcommand{\cC}{\mathcal C}
\newcommand{\cD}{\mathcal D}
\newcommand{\cE}{\mathcal E}
\newcommand{\cF}{\mathcal F}
\newcommand{\cG}{\mathcal G}
\newcommand{\cH}{\mathcal H}
\newcommand{\cI}{\mathcal I}
\newcommand{\cJ}{\mathcal J}
\newcommand{\cL}{\mathcal L}
\newcommand{\cK}{\mathcal K}
\newcommand{\cN}{\mathcal N}
\newcommand{\cO}{\mathcal O}
\newcommand{\cP}{\mathcal P}
\newcommand{\cQ}{\mathcal Q}
\newcommand{\cS}{\mathcal S}
\newcommand{\cT}{\mathcal T}
\newcommand{\cV}{\mathcal V}
\newcommand{\cW}{\mathcal W}
\newcommand{\cZ}{\mathcal Z}
\newcommand{\emp}{\emptyset}
\newcommand{\bs}{\backslash}
\newcommand{\floor}[1]{\left \lfloor #1 \right \rfloor}
\newcommand{\ceil}[1]{\left \lceil #1 \right \rceil}
\newcommand{\abs}[1]{\left | #1 \right |}
\newcommand{\xspace}{}
\newcommand{\proofheader}[1]{\underline{\textbf{#1}}}
\)
</div>
<header id="title-block-header">
<h1 class="title">9.4 Stacks</h1>
</header>
<section>
<p>Over the next few sections of this chapter, well learn about three new abstract data types: Stack, Queue, and Priority Queue. All three of these ADTs store a collection of items, and support operations to add an item and remove an item. However, unlike a Set or List, in which users may specify which item to remove (by value or by index, respectively), these three ADTs remove and return their items in a fixed order—client code is allowed no choice. This might seem restrictive and simplistic, but youll soon learn how the power of these ADTs lies in their simplicity. Once you learn about them, youll start seeing them everywhere, and be able to effectively communicate about these ADTs to any other computer scientist.</p>
<h2 id="the-stack-adt">The Stack ADT</h2>
<p>The <strong>Stack</strong> ADT is very simple. A stack contains zero or more items. When you add an item, it goes “on the top” of the stack (we call this “pushing” onto the stack) and when you remove an item, it is removed from the top also (we call this “popping” from the stack).<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> The name “stack” is a deliberate metaphor for a stack of books on a table.</span> The net effect is that the first item added to the stack is the last item removed. We call this <em>Last-In-First-Out (LIFO)</em> behaviour. To summarize:</p>
<ul>
<li><p><strong>Stack</strong></p>
<ul>
<li>Data: a collection of items</li>
<li>Operations: determine whether the stack is empty, add an item (<em>push</em>), remove the most recently-added item (<em>pop</em>)</li>
</ul></li>
</ul>
<p>In code:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">class</span> Stack:</span>
<span id="cb1-2"><a href="#cb1-2"></a> <span class="co">&quot;&quot;&quot;A last-in-first-out (LIFO) stack of items.</span></span>
<span id="cb1-3"><a href="#cb1-3"></a></span>
<span id="cb1-4"><a href="#cb1-4"></a><span class="co"> Stores data in last-in, first-out order. When removing an item from the</span></span>
<span id="cb1-5"><a href="#cb1-5"></a><span class="co"> stack, the most recently-added item is the one that is removed.</span></span>
<span id="cb1-6"><a href="#cb1-6"></a></span>
<span id="cb1-7"><a href="#cb1-7"></a><span class="co"> Sample usage:</span></span>
<span id="cb1-8"><a href="#cb1-8"></a></span>
<span id="cb1-9"><a href="#cb1-9"></a><span class="co"> &gt;&gt;&gt; s = Stack()</span></span>
<span id="cb1-10"><a href="#cb1-10"></a><span class="co"> &gt;&gt;&gt; s.is_empty()</span></span>
<span id="cb1-11"><a href="#cb1-11"></a><span class="co"> True</span></span>
<span id="cb1-12"><a href="#cb1-12"></a><span class="co"> &gt;&gt;&gt; s.push(&#39;hello&#39;)</span></span>
<span id="cb1-13"><a href="#cb1-13"></a><span class="co"> &gt;&gt;&gt; s.is_empty()</span></span>
<span id="cb1-14"><a href="#cb1-14"></a><span class="co"> False</span></span>
<span id="cb1-15"><a href="#cb1-15"></a><span class="co"> &gt;&gt;&gt; s.push(&#39;goodbye&#39;)</span></span>
<span id="cb1-16"><a href="#cb1-16"></a><span class="co"> &gt;&gt;&gt; s.pop()</span></span>
<span id="cb1-17"><a href="#cb1-17"></a><span class="co"> &#39;goodbye&#39;</span></span>
<span id="cb1-18"><a href="#cb1-18"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-19"><a href="#cb1-19"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb1-20"><a href="#cb1-20"></a> <span class="co">&quot;&quot;&quot;Initialize a new empty stack.&quot;&quot;&quot;</span></span>
<span id="cb1-21"><a href="#cb1-21"></a></span>
<span id="cb1-22"><a href="#cb1-22"></a> <span class="kw">def</span> is_empty(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="bu">bool</span>:</span>
<span id="cb1-23"><a href="#cb1-23"></a> <span class="co">&quot;&quot;&quot;Return whether this stack contains no items.</span></span>
<span id="cb1-24"><a href="#cb1-24"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-25"><a href="#cb1-25"></a></span>
<span id="cb1-26"><a href="#cb1-26"></a> <span class="kw">def</span> push(<span class="va">self</span>, item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb1-27"><a href="#cb1-27"></a> <span class="co">&quot;&quot;&quot;Add a new element to the top of this stack.</span></span>
<span id="cb1-28"><a href="#cb1-28"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-29"><a href="#cb1-29"></a></span>
<span id="cb1-30"><a href="#cb1-30"></a> <span class="kw">def</span> pop(<span class="va">self</span>) <span class="op">-&gt;</span> Any:</span>
<span id="cb1-31"><a href="#cb1-31"></a> <span class="co">&quot;&quot;&quot;Remove and return the element at the top of this stack.</span></span>
<span id="cb1-32"><a href="#cb1-32"></a></span>
<span id="cb1-33"><a href="#cb1-33"></a><span class="co"> Preconditions:</span></span>
<span id="cb1-34"><a href="#cb1-34"></a><span class="co"> - not self.is_empty()</span></span>
<span id="cb1-35"><a href="#cb1-35"></a><span class="co"> &quot;&quot;&quot;</span></span></code></pre></div>
<p>At this point, you may be wondering how we fill in the method bodies, picturing perhaps a <code>list</code> instance attribute to store the items in the stack. But remember, thinking about implementation is irrelevant when you are using an ADT. At this point, you should picture a pile of objects stacked on top of each other—this is enough to understand each of the doctest examples in the above code. Abstraction allows us to separate our understanding of what the Stack ADT is from how it is implemented.</p>
<h2 id="applications-of-stacks">Applications of stacks</h2>
<p>Because they have so few methods, it may seem like stacks are not that powerful. But in fact, stacks are useful for many things. For instance, they can be used to check for balanced parentheses in a mathematical expression. And consider the execution of a Python program. We have talked about frames that store the names available at a given moment in its execution. What happens when <code>f</code> calls <code>g</code>, which calls <code>h</code>? When <code>h</code> is over, we go back to <code>g</code> and when <code>g</code> is over we go back to <code>f</code>. To make this happen, our frames go on a stack! Hence the names <em>call stack</em> and <em>stack frame</em> from our memory model.</p>
<p>As a more “real world” example, consider the undo feature in many different applications. When we perform an action by mistake and want to undo it, we want to undo <em>the most recent</em> action, and so the Stack ADT is the perfect abstract data type for keeping track of the history of our actions so that we can undo them. A similar application lies in how web browsers store page visits so that we can go back to the most recently-visited page.</p>
<h2 id="implementing-the-stack-adt-using-lists">Implementing the Stack ADT using lists</h2>
<p>Next, well now implement the Stack ADT using a built-in Python data structure: the <code>list</code>. Weve chosen to use the <em>end</em> of the list to represent the top of the stack.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode python fullwidth"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">class</span> Stack1:</span>
<span id="cb2-2"><a href="#cb2-2"></a> <span class="co">&quot;&quot;&quot;A last-in-first-out (LIFO) stack of items.</span></span>
<span id="cb2-3"><a href="#cb2-3"></a></span>
<span id="cb2-4"><a href="#cb2-4"></a><span class="co"> Stores data in first-in, last-out order. When removing an item from the</span></span>
<span id="cb2-5"><a href="#cb2-5"></a><span class="co"> stack, the most recently-added item is the one that is removed.</span></span>
<span id="cb2-6"><a href="#cb2-6"></a></span>
<span id="cb2-7"><a href="#cb2-7"></a><span class="co"> Instance Attributes:</span></span>
<span id="cb2-8"><a href="#cb2-8"></a><span class="co"> - items: The items stored in the stack. The end of the list represents</span></span>
<span id="cb2-9"><a href="#cb2-9"></a><span class="co"> the top of the stack.</span></span>
<span id="cb2-10"><a href="#cb2-10"></a></span>
<span id="cb2-11"><a href="#cb2-11"></a><span class="co"> &gt;&gt;&gt; s = Stack1()</span></span>
<span id="cb2-12"><a href="#cb2-12"></a><span class="co"> &gt;&gt;&gt; s.is_empty()</span></span>
<span id="cb2-13"><a href="#cb2-13"></a><span class="co"> True</span></span>
<span id="cb2-14"><a href="#cb2-14"></a><span class="co"> &gt;&gt;&gt; s.push(&#39;hello&#39;)</span></span>
<span id="cb2-15"><a href="#cb2-15"></a><span class="co"> &gt;&gt;&gt; s.is_empty()</span></span>
<span id="cb2-16"><a href="#cb2-16"></a><span class="co"> False</span></span>
<span id="cb2-17"><a href="#cb2-17"></a><span class="co"> &gt;&gt;&gt; s.push(&#39;goodbye&#39;)</span></span>
<span id="cb2-18"><a href="#cb2-18"></a><span class="co"> &gt;&gt;&gt; s.pop()</span></span>
<span id="cb2-19"><a href="#cb2-19"></a><span class="co"> &#39;goodbye&#39;</span></span>
<span id="cb2-20"><a href="#cb2-20"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb2-21"><a href="#cb2-21"></a> items: <span class="bu">list</span></span>
<span id="cb2-22"><a href="#cb2-22"></a></span>
<span id="cb2-23"><a href="#cb2-23"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb2-24"><a href="#cb2-24"></a> <span class="co">&quot;&quot;&quot;Initialize a new empty stack.</span></span>
<span id="cb2-25"><a href="#cb2-25"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb2-26"><a href="#cb2-26"></a> <span class="va">self</span>.items <span class="op">=</span> []</span>
<span id="cb2-27"><a href="#cb2-27"></a></span>
<span id="cb2-28"><a href="#cb2-28"></a> <span class="kw">def</span> is_empty(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="bu">bool</span>:</span>
<span id="cb2-29"><a href="#cb2-29"></a> <span class="co">&quot;&quot;&quot;Return whether this stack contains no items.</span></span>
<span id="cb2-30"><a href="#cb2-30"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb2-31"><a href="#cb2-31"></a> <span class="cf">return</span> <span class="va">self</span>.items <span class="op">==</span> []</span>
<span id="cb2-32"><a href="#cb2-32"></a></span>
<span id="cb2-33"><a href="#cb2-33"></a> <span class="kw">def</span> push(<span class="va">self</span>, item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb2-34"><a href="#cb2-34"></a> <span class="co">&quot;&quot;&quot;Add a new element to the top of this stack.</span></span>
<span id="cb2-35"><a href="#cb2-35"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb2-36"><a href="#cb2-36"></a> <span class="va">self</span>.items.append(item)</span>
<span id="cb2-37"><a href="#cb2-37"></a></span>
<span id="cb2-38"><a href="#cb2-38"></a> <span class="kw">def</span> pop(<span class="va">self</span>) <span class="op">-&gt;</span> Any:</span>
<span id="cb2-39"><a href="#cb2-39"></a> <span class="co">&quot;&quot;&quot;Remove and return the element at the top of this stack.</span></span>
<span id="cb2-40"><a href="#cb2-40"></a></span>
<span id="cb2-41"><a href="#cb2-41"></a><span class="co"> Preconditions:</span></span>
<span id="cb2-42"><a href="#cb2-42"></a><span class="co"> - not self.is_empty()</span></span>
<span id="cb2-43"><a href="#cb2-43"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb2-44"><a href="#cb2-44"></a> <span class="cf">return</span> <span class="va">self</span>.items.pop()</span></code></pre></div>
<h2 id="attributes-and-the-class-interface">Attributes and the class interface</h2>
<p>Our current <code>Stack1</code> class is correct, but has one subtle difference with the Stack ADT it is supposed to implement. While a user can create a new <code>Stack1</code> object and call its methods <code>push</code> and <code>pop</code> to interact with it, they can also do one more thing: access the <code>items</code> instance attribute. This means that any user of a <code>Stack1</code> object can access any item in the stack at any time, or even mutate <code>items</code> to modify the contents of the stack in unexpected ways.</p>
<p>You might wonder why this is an issue—if a user wants to change the <code>items</code> attribute, let them! And indeed this is a common and valid approach in programming, particularly in favour with many Python developers. However, it is not the only approach. Another school of thought is that a data types interface should communicate not just how to use it, but also how <em>not</em> to use it. For our current <code>Stack1</code> implementation, the instance attribute <code>items</code> is part of the class interface, and so all users can reasonably expect to use it.</p>
<p>To make an instance attribute that <em>isnt</em> part of a class interface, we prefix its name with an underscore <code>_</code>. We refer to attributes whose names begin with an underscore as <strong>private instance attributes</strong>, and those without the underscore (all the attributes weve seen so far) as <strong>public instance attributes</strong>. These names suggest how theyre interpreted when it comes to a class interface: all public instance attributes are part of the interface, and all private ones arent.</p>
<p>Heres how we could modify our <code>Stack1</code> implementation to make <code>items</code> a private attribute instead.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode python fullwidth"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1"></a><span class="kw">class</span> Stack1:</span>
<span id="cb3-2"><a href="#cb3-2"></a> <span class="co">&quot;&quot;&quot;A last-in-first-out (LIFO) stack of items.</span></span>
<span id="cb3-3"><a href="#cb3-3"></a></span>
<span id="cb3-4"><a href="#cb3-4"></a><span class="co"> Stores data in first-in, last-out order. When removing an item from the</span></span>
<span id="cb3-5"><a href="#cb3-5"></a><span class="co"> stack, the most recently-added item is the one that is removed.</span></span>
<span id="cb3-6"><a href="#cb3-6"></a></span>
<span id="cb3-7"><a href="#cb3-7"></a><span class="co"> &gt;&gt;&gt; s = Stack1()</span></span>
<span id="cb3-8"><a href="#cb3-8"></a><span class="co"> &gt;&gt;&gt; s.is_empty()</span></span>
<span id="cb3-9"><a href="#cb3-9"></a><span class="co"> True</span></span>
<span id="cb3-10"><a href="#cb3-10"></a><span class="co"> &gt;&gt;&gt; s.push(&#39;hello&#39;)</span></span>
<span id="cb3-11"><a href="#cb3-11"></a><span class="co"> &gt;&gt;&gt; s.is_empty()</span></span>
<span id="cb3-12"><a href="#cb3-12"></a><span class="co"> False</span></span>
<span id="cb3-13"><a href="#cb3-13"></a><span class="co"> &gt;&gt;&gt; s.push(&#39;goodbye&#39;)</span></span>
<span id="cb3-14"><a href="#cb3-14"></a><span class="co"> &gt;&gt;&gt; s.pop()</span></span>
<span id="cb3-15"><a href="#cb3-15"></a><span class="co"> &#39;goodbye&#39;</span></span>
<span id="cb3-16"><a href="#cb3-16"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb3-17"><a href="#cb3-17"></a> <span class="co"># Private Instance Attributes:</span></span>
<span id="cb3-18"><a href="#cb3-18"></a> <span class="co"># - _items: The items stored in the stack. The end of the list represents</span></span>
<span id="cb3-19"><a href="#cb3-19"></a> <span class="co"># the top of the stack.</span></span>
<span id="cb3-20"><a href="#cb3-20"></a> _items: <span class="bu">list</span></span>
<span id="cb3-21"><a href="#cb3-21"></a></span>
<span id="cb3-22"><a href="#cb3-22"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb3-23"><a href="#cb3-23"></a> <span class="co">&quot;&quot;&quot;Initialize a new empty stack.</span></span>
<span id="cb3-24"><a href="#cb3-24"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb3-25"><a href="#cb3-25"></a> <span class="va">self</span>._items <span class="op">=</span> []</span>
<span id="cb3-26"><a href="#cb3-26"></a></span>
<span id="cb3-27"><a href="#cb3-27"></a> <span class="kw">def</span> is_empty(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="bu">bool</span>:</span>
<span id="cb3-28"><a href="#cb3-28"></a> <span class="co">&quot;&quot;&quot;Return whether this stack contains no items.</span></span>
<span id="cb3-29"><a href="#cb3-29"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb3-30"><a href="#cb3-30"></a> <span class="cf">return</span> <span class="va">self</span>._items <span class="op">==</span> []</span>
<span id="cb3-31"><a href="#cb3-31"></a></span>
<span id="cb3-32"><a href="#cb3-32"></a> <span class="kw">def</span> push(<span class="va">self</span>, item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb3-33"><a href="#cb3-33"></a> <span class="co">&quot;&quot;&quot;Add a new element to the top of this stack.</span></span>
<span id="cb3-34"><a href="#cb3-34"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb3-35"><a href="#cb3-35"></a> <span class="va">self</span>._items.append(item)</span>
<span id="cb3-36"><a href="#cb3-36"></a></span>
<span id="cb3-37"><a href="#cb3-37"></a> <span class="kw">def</span> pop(<span class="va">self</span>) <span class="op">-&gt;</span> Any:</span>
<span id="cb3-38"><a href="#cb3-38"></a> <span class="co">&quot;&quot;&quot;Remove and return the element at the top of this stack.</span></span>
<span id="cb3-39"><a href="#cb3-39"></a></span>
<span id="cb3-40"><a href="#cb3-40"></a><span class="co"> Preconditions:</span></span>
<span id="cb3-41"><a href="#cb3-41"></a><span class="co"> - not self.is_empty()</span></span>
<span id="cb3-42"><a href="#cb3-42"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb3-43"><a href="#cb3-43"></a> <span class="cf">return</span> <span class="va">self</span>._items.pop()</span></code></pre></div>
<p>Other than renaming the attribute from <code>items</code> to <code>_items</code>, the only change is in how we document this attribute. Weve kept the same format, but now moved the description from the class docstring to comments in the class body. By doing so, there is now no mention of this attribute when we call <code>help</code> on our class:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">help</span>(Stack1)</span>
<span id="cb4-2"><a href="#cb4-2"></a><span class="kw">class</span> Stack1(builtins.<span class="bu">object</span>)</span>
<span id="cb4-3"><a href="#cb4-3"></a> <span class="op">|</span> Stack1() <span class="op">-&gt;</span> <span class="va">None</span></span>
<span id="cb4-4"><a href="#cb4-4"></a> <span class="op">|</span></span>
<span id="cb4-5"><a href="#cb4-5"></a> <span class="op">|</span> A last<span class="op">-</span><span class="kw">in</span><span class="op">-</span>first<span class="op">-</span>out (LIFO) stack of items.</span>
<span id="cb4-6"><a href="#cb4-6"></a> <span class="op">|</span></span>
<span id="cb4-7"><a href="#cb4-7"></a> <span class="op">|</span> Stores data <span class="kw">in</span> a last<span class="op">-</span><span class="kw">in</span>, first<span class="op">-</span>out order. When removing an item <span class="im">from</span> the</span>
<span id="cb4-8"><a href="#cb4-8"></a> <span class="op">|</span> stack, the most recently<span class="op">-</span>added item <span class="kw">is</span> the one that <span class="kw">is</span> removed.</span>
<span id="cb4-9"><a href="#cb4-9"></a> <span class="op">|</span></span>
<span id="cb4-10"><a href="#cb4-10"></a> <span class="op">|</span> <span class="op">&gt;&gt;&gt;</span> s <span class="op">=</span> Stack1()</span>
<span id="cb4-11"><a href="#cb4-11"></a> <span class="op">|</span> <span class="op">&gt;&gt;&gt;</span> s.is_empty()</span>
<span id="cb4-12"><a href="#cb4-12"></a> <span class="op">|</span> <span class="va">True</span></span>
<span id="cb4-13"><a href="#cb4-13"></a> <span class="op">|</span> <span class="op">&gt;&gt;&gt;</span> s.push(<span class="st">&#39;hello&#39;</span>)</span>
<span id="cb4-14"><a href="#cb4-14"></a> <span class="op">|</span> <span class="op">&gt;&gt;&gt;</span> s.is_empty()</span>
<span id="cb4-15"><a href="#cb4-15"></a> <span class="op">|</span> <span class="va">False</span></span>
<span id="cb4-16"><a href="#cb4-16"></a> <span class="op">|</span> <span class="op">&gt;&gt;&gt;</span> s.push(<span class="st">&#39;goodbye&#39;</span>)</span>
<span id="cb4-17"><a href="#cb4-17"></a> <span class="op">|</span> <span class="op">&gt;&gt;&gt;</span> s.pop()</span>
<span id="cb4-18"><a href="#cb4-18"></a> <span class="op">|</span> <span class="st">&#39;goodbye&#39;</span></span>
<span id="cb4-19"><a href="#cb4-19"></a> <span class="op">|</span></span>
<span id="cb4-20"><a href="#cb4-20"></a> <span class="op">|</span> [The rest <span class="kw">is</span> omitted]</span>
<span id="cb4-21"><a href="#cb4-21"></a> <span class="op">|</span></span></code></pre></div>
<h3 id="warning-private-attributes-can-be-accessed">Warning: private attributes can be accessed!</h3>
<p>One of the distinctive features of Python that separates it from many other programming languages is that private instance attributes can still be accessed from outside the class.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1"></a><span class="op">&gt;&gt;&gt;</span> s <span class="op">=</span> Stack1()</span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="op">&gt;&gt;&gt;</span> s.push(<span class="dv">10</span>)</span>
<span id="cb5-3"><a href="#cb5-3"></a><span class="op">&gt;&gt;&gt;</span> s.push(<span class="dv">20</span>)</span>
<span id="cb5-4"><a href="#cb5-4"></a><span class="op">&gt;&gt;&gt;</span> s._items</span>
<span id="cb5-5"><a href="#cb5-5"></a>[<span class="dv">10</span>, <span class="dv">20</span>]</span></code></pre></div>
<p>This is a design choice made by the creators of the Python programming language to prefer <em>flexibility</em> over <em>restriction</em> when it comes to accessing attributes. But does this mean private attributes are meaningless? <em>No!</em> By making an instance attribute private, we are communicating that client code should <em>not</em> access this attribute: it is not an expected way of interacting with this class. As a result, we reduce the cognitive load on the client (one less attribute to think about when using the class), and also give flexibility to the designer of the class to change or even remove a private attribute if they want to update their implementation of the class, without affecting the class public interface.</p>
<h2 id="analyzing-efficiency">Analyzing efficiency</h2>
<p>We implemented <code>Stack1</code> using the back of the <code>_items</code> list to represent the top of the stack. You might wonder why we didnt use the front of <code>_items</code> instead. Indeed, the implemention wouldnt have to change much:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">class</span> Stack2:</span>
<span id="cb6-2"><a href="#cb6-2"></a> <span class="co"># Duplicated code from Stack1 omitted. Only push and pop are different.</span></span>
<span id="cb6-3"><a href="#cb6-3"></a></span>
<span id="cb6-4"><a href="#cb6-4"></a> <span class="kw">def</span> push(<span class="va">self</span>, item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb6-5"><a href="#cb6-5"></a> <span class="co">&quot;&quot;&quot;Add a new element to the top of this stack.</span></span>
<span id="cb6-6"><a href="#cb6-6"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb6-7"><a href="#cb6-7"></a> <span class="va">self</span>._items.insert(<span class="dv">0</span>, item)</span>
<span id="cb6-8"><a href="#cb6-8"></a></span>
<span id="cb6-9"><a href="#cb6-9"></a> <span class="kw">def</span> pop(<span class="va">self</span>) <span class="op">-&gt;</span> Any:</span>
<span id="cb6-10"><a href="#cb6-10"></a> <span class="co">&quot;&quot;&quot;Remove and return the element at the top of this stack.</span></span>
<span id="cb6-11"><a href="#cb6-11"></a></span>
<span id="cb6-12"><a href="#cb6-12"></a><span class="co"> Preconditions:</span></span>
<span id="cb6-13"><a href="#cb6-13"></a><span class="co"> - not self.is_empty()</span></span>
<span id="cb6-14"><a href="#cb6-14"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb6-15"><a href="#cb6-15"></a> <span class="cf">return</span> <span class="va">self</span>._items.pop(<span class="dv">0</span>)</span></code></pre></div>
<p>The key difference between <code>Stack1</code> and <code>Stack2</code> is not their code complexity but their <em>efficiency</em>. In Chapter 8, we learned that Python uses an array-based implementation for lists. Because of this, the <code>list.append</code> operation for an array-based list is <span class="math inline">\(\Theta(1)\)</span>, therefore <code>Stack1.push</code> is also <span class="math inline">\(\Theta(1)\)</span>. In contrast, <code>list.insert</code> has complexity <span class="math inline">\(\Theta(n - i)\)</span>, where <span class="math inline">\(i\)</span> is the index argument passed to <code>list.insert</code>. In <code>Stack2.push</code>, <span class="math inline">\(i = 0\)</span> and so the method has complexity <span class="math inline">\(\Theta(n)\)</span>. So the <code>push</code> operation for stacks is more efficient when we treat the end of an array-based list as the top of the stack.</p>
<p>Similarly, removing the last element of an array-based list using <code>list.pop</code> is also <span class="math inline">\(\Theta(1)\)</span>, and so the running time of <code>Stack1.pop</code> is <span class="math inline">\(\Theta(1)\)</span>. However, <code>Stack2.pop</code> uses passes an index of 0 to <code>list.pop</code>, which causes the method to have a <span class="math inline">\(\Theta(n)\)</span> running time.</p>
<p>The decision of which implementation has superior efficiency is clear: <code>Stack1</code> will always be more efficient than <code>Stack2</code>. Having such a clear-cut winner is actually quite rare. There are almost always trade-offs associated with choosing one implementation over another. We will see one such trade-off when we introduce our next ADT: queues.</p>
</section>
<!--
If a client creates a `Stack` object in their code, they know
there are exactly three operations that can be performed on it:
checking whether it's empty, pushing an item onto it, and popping an item from it.
This reduces cognitive load for the programmer dramatically.
Modern, complex software would be impossible otherwise.
-->
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>
+271
View File
@@ -0,0 +1,271 @@
<!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>9.5 Exceptions as a Part of the Public Interface</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="../tufte.css" />
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<div style="display:none">
\(
\newcommand{\NOT}{\neg}
\newcommand{\AND}{\wedge}
\newcommand{\OR}{\vee}
\newcommand{\XOR}{\oplus}
\newcommand{\IMP}{\Rightarrow}
\newcommand{\IFF}{\Leftrightarrow}
\newcommand{\TRUE}{\text{True}\xspace}
\newcommand{\FALSE}{\text{False}\xspace}
\newcommand{\IN}{\,{\in}\,}
\newcommand{\NOTIN}{\,{\notin}\,}
\newcommand{\TO}{\rightarrow}
\newcommand{\DIV}{\mid}
\newcommand{\NDIV}{\nmid}
\newcommand{\MOD}[1]{\pmod{#1}}
\newcommand{\MODS}[1]{\ (\text{mod}\ #1)}
\newcommand{\N}{\mathbb N}
\newcommand{\Z}{\mathbb Z}
\newcommand{\Q}{\mathbb Q}
\newcommand{\R}{\mathbb R}
\newcommand{\C}{\mathbb C}
\newcommand{\cA}{\mathcal A}
\newcommand{\cB}{\mathcal B}
\newcommand{\cC}{\mathcal C}
\newcommand{\cD}{\mathcal D}
\newcommand{\cE}{\mathcal E}
\newcommand{\cF}{\mathcal F}
\newcommand{\cG}{\mathcal G}
\newcommand{\cH}{\mathcal H}
\newcommand{\cI}{\mathcal I}
\newcommand{\cJ}{\mathcal J}
\newcommand{\cL}{\mathcal L}
\newcommand{\cK}{\mathcal K}
\newcommand{\cN}{\mathcal N}
\newcommand{\cO}{\mathcal O}
\newcommand{\cP}{\mathcal P}
\newcommand{\cQ}{\mathcal Q}
\newcommand{\cS}{\mathcal S}
\newcommand{\cT}{\mathcal T}
\newcommand{\cV}{\mathcal V}
\newcommand{\cW}{\mathcal W}
\newcommand{\cZ}{\mathcal Z}
\newcommand{\emp}{\emptyset}
\newcommand{\bs}{\backslash}
\newcommand{\floor}[1]{\left \lfloor #1 \right \rfloor}
\newcommand{\ceil}[1]{\left \lceil #1 \right \rceil}
\newcommand{\abs}[1]{\left | #1 \right |}
\newcommand{\xspace}{}
\newcommand{\proofheader}[1]{\underline{\textbf{#1}}}
\)
</div>
<header id="title-block-header">
<h1 class="title">9.5 Exceptions as a Part of the Public Interface</h1>
</header>
<section>
<p>The stack implementations we studied in the previous section included a precondition on their <code>pop</code> method specifying that the stack must not be empty. Preconditions are used to rule out erroneous situations like attempting to remove an item from an empty stack, but they come with one drawback: every precondition we add increases the complexity of the functions interface. A precondition becomes the responsibility of the <em>user</em> of the function to check, for example, with code like</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1"></a><span class="cf">if</span> <span class="kw">not</span> my_stack.is_empty():</span>
<span id="cb1-2"><a href="#cb1-2"></a> top_item <span class="op">=</span> my_stack.pop()</span></code></pre></div>
<p>Sometimes these checks are straightforward, but depending on the preconditions we specify, they can be onerous as well. In this section, well introduce an alternate mechanism for signaling an erroneous state from within a function call.</p>
<h2 id="warm-up-letting-an-error-happen">Warm-up: letting an error happen</h2>
<p>Consider this version of <code>Stack.pop</code>, which removes the precondition but keeps the same implementation:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1"></a> <span class="kw">def</span> pop(<span class="va">self</span>) <span class="op">-&gt;</span> Any:</span>
<span id="cb2-2"><a href="#cb2-2"></a> <span class="co">&quot;&quot;&quot;Remove and return the element at the top of this stack.</span></span>
<span id="cb2-3"><a href="#cb2-3"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb2-4"><a href="#cb2-4"></a> <span class="cf">return</span> <span class="va">self</span>._items.pop()</span></code></pre></div>
<p>When we call <code>pop</code> on an empty stack, we encounter the following error:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1"></a><span class="op">&gt;&gt;&gt;</span> s <span class="op">=</span> Stack()</span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="op">&gt;&gt;&gt;</span> s.pop()</span>
<span id="cb3-3"><a href="#cb3-3"></a>Traceback (most recent call last):</span>
<span id="cb3-4"><a href="#cb3-4"></a> File <span class="st">&quot;&lt;input&gt;&quot;</span>, line <span class="dv">1</span>, <span class="kw">in</span> <span class="op">&lt;</span>module<span class="op">&gt;</span></span>
<span id="cb3-5"><a href="#cb3-5"></a> File <span class="st">&quot;...&quot;</span>, line <span class="dv">58</span>, <span class="kw">in</span> pop</span>
<span id="cb3-6"><a href="#cb3-6"></a> <span class="cf">return</span> <span class="va">self</span>._items.pop()</span>
<span id="cb3-7"><a href="#cb3-7"></a><span class="pp">IndexError</span>: pop <span class="im">from</span> empty <span class="bu">list</span></span></code></pre></div>
<p>As we saw earlier in the course, when an exception is raised Python stops the normal control flow of the currently running program. From the perspective of the client code, it is good to see an exception to know that something has gone wrong, but bad that the exceptions report refers to a list (<code>IndexError: pop from empty list</code>) and a private attribute (<code>self._items</code>) that the client code should have no knowledge of.</p>
<h2 id="custom-exceptions">Custom exceptions</h2>
<p>A better solution is to raise a custom exception that is descriptive, yet does not reveal any implementation details. We can achieve this very easily in Python: we define our own type of error by defining a new class:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1"></a><span class="kw">class</span> EmptyStackError(<span class="pp">Exception</span>):</span>
<span id="cb4-2"><a href="#cb4-2"></a> <span class="co">&quot;&quot;&quot;Exception raised when calling pop on an empty stack.&quot;&quot;&quot;</span></span></code></pre></div>
<p>There is some slightly new syntax here: the <code>(Exception)</code> that follows the class name. For now, it is enough to know that this will properly create a new type of exception. The technical mechanism used, <em>inheritance</em>, is one well cover later in this chapter.</p>
<p>Heres how well use <code>EmptyStackError</code> in our <code>pop</code> method:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1"></a> <span class="kw">def</span> pop(<span class="va">self</span>) <span class="op">-&gt;</span> Any:</span>
<span id="cb5-2"><a href="#cb5-2"></a> <span class="co">&quot;&quot;&quot;Remove and return the element at the top of this stack.</span></span>
<span id="cb5-3"><a href="#cb5-3"></a></span>
<span id="cb5-4"><a href="#cb5-4"></a><span class="co"> Raise an EmptyStackError if this stack is empty.</span></span>
<span id="cb5-5"><a href="#cb5-5"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb5-6"><a href="#cb5-6"></a> <span class="cf">if</span> <span class="va">self</span>.is_empty():</span>
<span id="cb5-7"><a href="#cb5-7"></a> <span class="cf">raise</span> EmptyStackError</span>
<span id="cb5-8"><a href="#cb5-8"></a> <span class="cf">else</span>:</span>
<span id="cb5-9"><a href="#cb5-9"></a> <span class="cf">return</span> <span class="va">self</span>._items.pop()</span></code></pre></div>
<p>There are two important changes in this version of <code>pop</code>. First, in the method docstring there is a new sentence which names both the type of exception and the scenario that will cause that exception to be raised. This exception is now part of the <em>public interface</em> of <code>Stack.pop</code>, meaning users of this class will be expected to take note of this exception. Second, this implementation now uses a new Python keyword, <code>raise</code>, which unsurprisingly raises an exception.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> Even though were using our custom exception class here, <code>raise</code> works with any exception type, such as <code>IndexError</code> and <code>AttributeError</code>.</span> A raise statement can be used anywhere in our code to raise exceptions, even ones that weve defined ourselves. Lets see what happens now when we call <code>pop</code> on an empty stack:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1"></a><span class="op">&gt;&gt;&gt;</span> s <span class="op">=</span> Stack()</span>
<span id="cb6-2"><a href="#cb6-2"></a><span class="op">&gt;&gt;&gt;</span> s.pop()</span>
<span id="cb6-3"><a href="#cb6-3"></a>Traceback (most recent call last):</span>
<span id="cb6-4"><a href="#cb6-4"></a> File <span class="st">&quot;&lt;input&gt;&quot;</span>, line <span class="dv">1</span>, <span class="kw">in</span> <span class="op">&lt;</span>module<span class="op">&gt;</span></span>
<span id="cb6-5"><a href="#cb6-5"></a> File <span class="st">&quot;...&quot;</span>, line <span class="dv">60</span>, <span class="kw">in</span> pop</span>
<span id="cb6-6"><a href="#cb6-6"></a> <span class="cf">raise</span> EmptyStackError</span>
<span id="cb6-7"><a href="#cb6-7"></a>EmptyStackError</span></code></pre></div>
<p>As before, an exception is raised. But now the line shown is just this simple <code>raise</code> statement; it doesnt mention any implementation details of the class. And it specifies that an <code>EmptyStackError</code> was the problem, as was documented in the method docstring.</p>
<h3 id="custom-exception-messages">Custom exception messages</h3>
<p>One current limitation of the above approach is that simply the name of the exception class does not convey a lot of meaning. To provide a custom exception message, we can define a new special method with the name <code>__str__</code> in our exception class:<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> Like <code>__init__</code>, the name <code>__str__</code> has special meaning in Python. Well study it and more methods like it later in the course.</span></p>
<div class="sourceCode" id="cb7"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1"></a><span class="kw">class</span> EmptyStackError(<span class="pp">Exception</span>):</span>
<span id="cb7-2"><a href="#cb7-2"></a> <span class="co">&quot;&quot;&quot;Exception raised when calling pop on an empty stack.&quot;&quot;&quot;</span></span>
<span id="cb7-3"><a href="#cb7-3"></a></span>
<span id="cb7-4"><a href="#cb7-4"></a> <span class="kw">def</span> <span class="fu">__str__</span>(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="bu">str</span>:</span>
<span id="cb7-5"><a href="#cb7-5"></a> <span class="co">&quot;&quot;&quot;Return a string representation of this error.&quot;&quot;&quot;</span></span>
<span id="cb7-6"><a href="#cb7-6"></a> <span class="cf">return</span> <span class="st">&#39;pop may not be called on an empty stack&#39;</span></span>
<span id="cb7-7"><a href="#cb7-7"></a></span>
<span id="cb7-8"><a href="#cb7-8"></a></span>
<span id="cb7-9"><a href="#cb7-9"></a><span class="op">&gt;&gt;&gt;</span> s <span class="op">=</span> Stack()</span>
<span id="cb7-10"><a href="#cb7-10"></a><span class="op">&gt;&gt;&gt;</span> s.pop()</span>
<span id="cb7-11"><a href="#cb7-11"></a>Traceback (most recent call last):</span>
<span id="cb7-12"><a href="#cb7-12"></a> File <span class="st">&quot;&lt;input&gt;&quot;</span>, line <span class="dv">1</span>, <span class="kw">in</span> <span class="op">&lt;</span>module<span class="op">&gt;</span></span>
<span id="cb7-13"><a href="#cb7-13"></a> File <span class="st">&quot;...&quot;</span>, line <span class="dv">60</span>, <span class="kw">in</span> pop</span>
<span id="cb7-14"><a href="#cb7-14"></a> <span class="cf">raise</span> EmptyStackError</span>
<span id="cb7-15"><a href="#cb7-15"></a>EmptyStackError: pop may <span class="kw">not</span> be called on an empty stack</span></code></pre></div>
<h2 id="testing-exceptions">Testing exceptions</h2>
<p>Because we include <code>EmptyStackError</code> as part of the public interface of the <code>Stack.pop</code> method, we should write tests to check that this behaviour occurs as expected. But unlike the tests weve written so far, we cannot simply call <code>pop</code> on an empty stack and check the return value or the state of the stack after <code>pop</code> returns. Raising an error interrupts the regular control flow of a Python program—and this includes test cases!</p>
<p>The <code>pytest</code> module<label for="sn-2" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-2" class="margin-toggle"/><span class="sidenote"> It is also possible to write doctests that check for exceptions. See <a href="../B-Python-libraries/01-doctest.html">Appendix B.1</a> for details.</span> allows us to write tests that expects an exception to occur using a function <code>pytest.raises</code> together with the <code>with</code> keyword: Here is an example of a test case to check that calling <code>Stack.pop</code> on an empty stack raises an <code>EmptyStackError</code>.</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1"></a><span class="co"># Assuming our stack implementation is contained in a file stack.py.</span></span>
<span id="cb8-2"><a href="#cb8-2"></a><span class="im">from</span> stack <span class="im">import</span> Stack, EmptyStackError</span>
<span id="cb8-3"><a href="#cb8-3"></a><span class="im">import</span> pytest</span>
<span id="cb8-4"><a href="#cb8-4"></a></span>
<span id="cb8-5"><a href="#cb8-5"></a></span>
<span id="cb8-6"><a href="#cb8-6"></a><span class="kw">def</span> test_empty_stack_error():</span>
<span id="cb8-7"><a href="#cb8-7"></a> <span class="co">&quot;&quot;&quot;Test that popping from an empty stack raises an exception.&quot;&quot;&quot;</span></span>
<span id="cb8-8"><a href="#cb8-8"></a> s <span class="op">=</span> Stack()</span>
<span id="cb8-9"><a href="#cb8-9"></a></span>
<span id="cb8-10"><a href="#cb8-10"></a> <span class="cf">with</span> pytest.raises(EmptyStackError):</span>
<span id="cb8-11"><a href="#cb8-11"></a> s.pop()</span></code></pre></div>
<p>The <code>with</code> keyword acts as an assertion, expecting an <code>EmptyStackError</code> to be raised by the body of the <code>with</code> block, the function call <code>s.pop()</code>. The test <em>passes</em> when that exception is raised, and <em>fails</em> when that exception is not raised (this includes the case when a different exception is raised instead of the expected one).</p>
<h2 id="handling-exceptions">Handling exceptions</h2>
<p>Weve said repeatedly that when an exception is raised, the normal execution of the program is stopped, and the exception is reported to the user. However, <code>pytest.raises</code> seems to circumvent this: after an <code>EmptyStackError</code> is raised in our test, the test simply <em>passes</em> and execution proceeds to the next test. How does <code>pytest.raises</code> achieve this?</p>
<p>Python provides a compound statement, the <strong>try-except</strong> statement, to execute a block of code and handle a case where one or more pre-specified exceptions are raised in that block. Here is the simplest form of a try-except statement:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1"></a><span class="cf">try</span>:</span>
<span id="cb9-2"><a href="#cb9-2"></a> <span class="op">&lt;</span>statement<span class="op">&gt;</span></span>
<span id="cb9-3"><a href="#cb9-3"></a> ...</span>
<span id="cb9-4"><a href="#cb9-4"></a><span class="cf">except</span> <span class="op">&lt;</span>ExceptionClass<span class="op">&gt;</span>:</span>
<span id="cb9-5"><a href="#cb9-5"></a> <span class="op">&lt;</span>statement<span class="op">&gt;</span></span>
<span id="cb9-6"><a href="#cb9-6"></a> ...</span></code></pre></div>
<p>When a try-except statement is executed:</p>
<ol type="1">
<li><p>First, the block of code indented within the <code>try</code> is executed.</p></li>
<li><p>If no exception occurs when executing this block, the <code>except</code> part is skipped, and the Python interpreter continues to the next statement after the try-except.</p></li>
<li><p>If an exception occurs when executing this block:</p>
<ul>
<li><p>If the exception has type <code>&lt;ExceptionClass&gt;</code>, the block under the <code>except</code> is executed, and then after that the Python interpreter continues executing the next statement after the try-except.</p>
<p>Importantly, in this case the program does <em>not</em> immediately halt!</p></li>
<li><p>However, if the exception is a different type, this does stop the normal program execution.</p></li>
</ul></li>
</ol>
<p>In practice, client code often uses try-except statements to call functions that may raise an error as part of their public interface. This shields users from seeing errors that they should never see, and allows the rest of the program to continue.</p>
<p>For example, here is how we could implement a function that takes a stack and returns the second item from the top of the stack.</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1"></a><span class="kw">def</span> second_from_top(s: Stack) <span class="op">-&gt;</span> Optional[<span class="bu">str</span>]:</span>
<span id="cb10-2"><a href="#cb10-2"></a> <span class="co">&quot;&quot;&quot;Return the item that is second from the top of s.</span></span>
<span id="cb10-3"><a href="#cb10-3"></a></span>
<span id="cb10-4"><a href="#cb10-4"></a><span class="co"> If there is no such item in the Stack, returns None.</span></span>
<span id="cb10-5"><a href="#cb10-5"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb10-6"><a href="#cb10-6"></a> <span class="cf">try</span>:</span>
<span id="cb10-7"><a href="#cb10-7"></a> hold1 <span class="op">=</span> s.pop()</span>
<span id="cb10-8"><a href="#cb10-8"></a> <span class="cf">except</span> EmptyStackError:</span>
<span id="cb10-9"><a href="#cb10-9"></a> <span class="co"># In this case, s is empty. We can return None.</span></span>
<span id="cb10-10"><a href="#cb10-10"></a> <span class="cf">return</span> <span class="va">None</span></span>
<span id="cb10-11"><a href="#cb10-11"></a></span>
<span id="cb10-12"><a href="#cb10-12"></a> <span class="cf">try</span>:</span>
<span id="cb10-13"><a href="#cb10-13"></a> hold2 <span class="op">=</span> s.pop()</span>
<span id="cb10-14"><a href="#cb10-14"></a> <span class="cf">except</span> EmptyStackError:</span>
<span id="cb10-15"><a href="#cb10-15"></a> <span class="co"># In this case, s had only one element.</span></span>
<span id="cb10-16"><a href="#cb10-16"></a> <span class="co"># We restore s to its original state and return None.</span></span>
<span id="cb10-17"><a href="#cb10-17"></a> s.push(hold1)</span>
<span id="cb10-18"><a href="#cb10-18"></a> <span class="cf">return</span> <span class="va">None</span></span>
<span id="cb10-19"><a href="#cb10-19"></a></span>
<span id="cb10-20"><a href="#cb10-20"></a> <span class="co"># If we reach this point, both of the previous s.pop() calls succeeded.</span></span>
<span id="cb10-21"><a href="#cb10-21"></a> <span class="co"># In this case, we restore s to its original state and return the second item.</span></span>
<span id="cb10-22"><a href="#cb10-22"></a> s.push(hold2)</span>
<span id="cb10-23"><a href="#cb10-23"></a> s.push(hold1)</span>
<span id="cb10-24"><a href="#cb10-24"></a></span>
<span id="cb10-25"><a href="#cb10-25"></a> <span class="cf">return</span> hold2</span></code></pre></div>
<h2 id="references">References</h2>
<ul>
<li>CSC108 videos: Exceptions (<a href="https://youtu.be/mhsu6mRKRdE?list=PLfMGJf6SEIv4qYogjAyLyfv3h_NUEKbWd">video</a>)</li>
</ul>
</section>
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>
+257
View File
@@ -0,0 +1,257 @@
<!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>9.6 Queues</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="../tufte.css" />
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" type="text/javascript"></script>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<div style="display:none">
\(
\newcommand{\NOT}{\neg}
\newcommand{\AND}{\wedge}
\newcommand{\OR}{\vee}
\newcommand{\XOR}{\oplus}
\newcommand{\IMP}{\Rightarrow}
\newcommand{\IFF}{\Leftrightarrow}
\newcommand{\TRUE}{\text{True}\xspace}
\newcommand{\FALSE}{\text{False}\xspace}
\newcommand{\IN}{\,{\in}\,}
\newcommand{\NOTIN}{\,{\notin}\,}
\newcommand{\TO}{\rightarrow}
\newcommand{\DIV}{\mid}
\newcommand{\NDIV}{\nmid}
\newcommand{\MOD}[1]{\pmod{#1}}
\newcommand{\MODS}[1]{\ (\text{mod}\ #1)}
\newcommand{\N}{\mathbb N}
\newcommand{\Z}{\mathbb Z}
\newcommand{\Q}{\mathbb Q}
\newcommand{\R}{\mathbb R}
\newcommand{\C}{\mathbb C}
\newcommand{\cA}{\mathcal A}
\newcommand{\cB}{\mathcal B}
\newcommand{\cC}{\mathcal C}
\newcommand{\cD}{\mathcal D}
\newcommand{\cE}{\mathcal E}
\newcommand{\cF}{\mathcal F}
\newcommand{\cG}{\mathcal G}
\newcommand{\cH}{\mathcal H}
\newcommand{\cI}{\mathcal I}
\newcommand{\cJ}{\mathcal J}
\newcommand{\cL}{\mathcal L}
\newcommand{\cK}{\mathcal K}
\newcommand{\cN}{\mathcal N}
\newcommand{\cO}{\mathcal O}
\newcommand{\cP}{\mathcal P}
\newcommand{\cQ}{\mathcal Q}
\newcommand{\cS}{\mathcal S}
\newcommand{\cT}{\mathcal T}
\newcommand{\cV}{\mathcal V}
\newcommand{\cW}{\mathcal W}
\newcommand{\cZ}{\mathcal Z}
\newcommand{\emp}{\emptyset}
\newcommand{\bs}{\backslash}
\newcommand{\floor}[1]{\left \lfloor #1 \right \rfloor}
\newcommand{\ceil}[1]{\left \lceil #1 \right \rceil}
\newcommand{\abs}[1]{\left | #1 \right |}
\newcommand{\xspace}{}
\newcommand{\proofheader}[1]{\underline{\textbf{#1}}}
\)
</div>
<header id="title-block-header">
<h1 class="title">9.6 Queues</h1>
</header>
<section>
<p>Picture a lineup at a fast food restaurant. The first person in line is the first one served, then the next person in line, and so forth. As new people join the line, they join at the back, so that everyone who joined before them are served before them. This is the exact opposite of a stack: in this lineup situation, people leave the line in the <em>same</em> order they joined it.</p>
<p>In this section, well introduce a new abstract data type to represent this type of collection, see how to implement it in Python, and analyze our implementations take a close look at the operations a queue supports, how we might implement one in Python, and how efficient our implementation is.</p>
<h2 id="the-queue-adt">The Queue ADT</h2>
<p>A <strong>queue</strong> is another collection of data that, like a stack, adds and removes items in a fixed order. Unlike a stack, items come out of a queue in the order in which they entered. We call this behaviour <em>First-In-First-Out (FIFO)</em>.</p>
<ul>
<li><p><strong>Queue</strong></p>
<ul>
<li>Data: a collection of items</li>
<li>Operations: determine whether the queue is empty, add an item (<em>enqueue</em>), remove the least recently-added item (<em>dequeue</em>)</li>
</ul></li>
</ul>
<p>In code:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">class</span> Queue:</span>
<span id="cb1-2"><a href="#cb1-2"></a> <span class="co">&quot;&quot;&quot;A first-in-first-out (FIFO) queue of items.</span></span>
<span id="cb1-3"><a href="#cb1-3"></a></span>
<span id="cb1-4"><a href="#cb1-4"></a><span class="co"> Stores data in a first-in, first-out order. When removing an item from the</span></span>
<span id="cb1-5"><a href="#cb1-5"></a><span class="co"> queue, the most recently-added item is the one that is removed.</span></span>
<span id="cb1-6"><a href="#cb1-6"></a></span>
<span id="cb1-7"><a href="#cb1-7"></a><span class="co"> &gt;&gt;&gt; q = Queue()</span></span>
<span id="cb1-8"><a href="#cb1-8"></a><span class="co"> &gt;&gt;&gt; q.is_empty()</span></span>
<span id="cb1-9"><a href="#cb1-9"></a><span class="co"> True</span></span>
<span id="cb1-10"><a href="#cb1-10"></a><span class="co"> &gt;&gt;&gt; q.enqueue(&#39;hello&#39;)</span></span>
<span id="cb1-11"><a href="#cb1-11"></a><span class="co"> &gt;&gt;&gt; q.is_empty()</span></span>
<span id="cb1-12"><a href="#cb1-12"></a><span class="co"> False</span></span>
<span id="cb1-13"><a href="#cb1-13"></a><span class="co"> &gt;&gt;&gt; q.enqueue(&#39;goodbye&#39;)</span></span>
<span id="cb1-14"><a href="#cb1-14"></a><span class="co"> &gt;&gt;&gt; q.dequeue()</span></span>
<span id="cb1-15"><a href="#cb1-15"></a><span class="co"> &#39;hello&#39;</span></span>
<span id="cb1-16"><a href="#cb1-16"></a><span class="co"> &gt;&gt;&gt; q.dequeue()</span></span>
<span id="cb1-17"><a href="#cb1-17"></a><span class="co"> &#39;goodbye&#39;</span></span>
<span id="cb1-18"><a href="#cb1-18"></a><span class="co"> &gt;&gt;&gt; q.is_empty()</span></span>
<span id="cb1-19"><a href="#cb1-19"></a><span class="co"> True</span></span>
<span id="cb1-20"><a href="#cb1-20"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-21"><a href="#cb1-21"></a></span>
<span id="cb1-22"><a href="#cb1-22"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb1-23"><a href="#cb1-23"></a> <span class="co">&quot;&quot;&quot;Initialize a new empty queue.&quot;&quot;&quot;</span></span>
<span id="cb1-24"><a href="#cb1-24"></a></span>
<span id="cb1-25"><a href="#cb1-25"></a> <span class="kw">def</span> is_empty(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="bu">bool</span>:</span>
<span id="cb1-26"><a href="#cb1-26"></a> <span class="co">&quot;&quot;&quot;Return whether this queue contains no items.</span></span>
<span id="cb1-27"><a href="#cb1-27"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-28"><a href="#cb1-28"></a></span>
<span id="cb1-29"><a href="#cb1-29"></a> <span class="kw">def</span> enqueue(<span class="va">self</span>, item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb1-30"><a href="#cb1-30"></a> <span class="co">&quot;&quot;&quot;Add &lt;item&gt; to the back of this queue.</span></span>
<span id="cb1-31"><a href="#cb1-31"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-32"><a href="#cb1-32"></a></span>
<span id="cb1-33"><a href="#cb1-33"></a> <span class="kw">def</span> dequeue(<span class="va">self</span>) <span class="op">-&gt;</span> Any:</span>
<span id="cb1-34"><a href="#cb1-34"></a> <span class="co">&quot;&quot;&quot;Remove and return the item at the front of this queue.</span></span>
<span id="cb1-35"><a href="#cb1-35"></a></span>
<span id="cb1-36"><a href="#cb1-36"></a><span class="co"> Raise an EmptyQueueError if this queue is empty.</span></span>
<span id="cb1-37"><a href="#cb1-37"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-38"><a href="#cb1-38"></a></span>
<span id="cb1-39"><a href="#cb1-39"></a></span>
<span id="cb1-40"><a href="#cb1-40"></a><span class="kw">class</span> EmptyQueueError(<span class="pp">Exception</span>):</span>
<span id="cb1-41"><a href="#cb1-41"></a> <span class="co">&quot;&quot;&quot;Exception raised when calling dequeue on an empty queue.&quot;&quot;&quot;</span></span>
<span id="cb1-42"><a href="#cb1-42"></a></span>
<span id="cb1-43"><a href="#cb1-43"></a> <span class="kw">def</span> <span class="fu">__str__</span>(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="bu">str</span>:</span>
<span id="cb1-44"><a href="#cb1-44"></a> <span class="co">&quot;&quot;&quot;Return a string representation of this error.&quot;&quot;&quot;</span></span>
<span id="cb1-45"><a href="#cb1-45"></a> <span class="cf">return</span> <span class="st">&#39;dequeue may not be called on an empty queue&#39;</span></span></code></pre></div>
<p>Much like a stack, we can also picture implementing this with a Python list. And, once again, we need to decide which end of the list is considered the front. Unlike the stack, we will see that there is a trade-off in choosing which end of the list is considered a front. Before reading the rest of the section, try to informally reason with yourself why this might be, taking into account that a queue is a FIFO.</p>
<h2 id="list-based-implementation-of-the-queue-adt">List-based implementation of the Queue ADT</h2>
<p>In the following implementation, we use a Python list that is hidden from the client. We have decided that the beginning of the list (i.e., index 0) is the front of the queue. This means that new items that are enqueued will be added at the end of the list, and items that are dequeued are removed from the beginning of the list.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">class</span> Queue:</span>
<span id="cb2-2"><a href="#cb2-2"></a> <span class="co">&quot;&quot;&quot;A first-in-first-out (FIFO) queue of items.</span></span>
<span id="cb2-3"><a href="#cb2-3"></a></span>
<span id="cb2-4"><a href="#cb2-4"></a><span class="co"> Stores data in a first-in, first-out order. When removing an item from the</span></span>
<span id="cb2-5"><a href="#cb2-5"></a><span class="co"> queue, the most recently-added item is the one that is removed.</span></span>
<span id="cb2-6"><a href="#cb2-6"></a></span>
<span id="cb2-7"><a href="#cb2-7"></a><span class="co"> &gt;&gt;&gt; q = Queue()</span></span>
<span id="cb2-8"><a href="#cb2-8"></a><span class="co"> &gt;&gt;&gt; q.is_empty()</span></span>
<span id="cb2-9"><a href="#cb2-9"></a><span class="co"> True</span></span>
<span id="cb2-10"><a href="#cb2-10"></a><span class="co"> &gt;&gt;&gt; q.enqueue(&#39;hello&#39;)</span></span>
<span id="cb2-11"><a href="#cb2-11"></a><span class="co"> &gt;&gt;&gt; q.is_empty()</span></span>
<span id="cb2-12"><a href="#cb2-12"></a><span class="co"> False</span></span>
<span id="cb2-13"><a href="#cb2-13"></a><span class="co"> &gt;&gt;&gt; q.enqueue(&#39;goodbye&#39;)</span></span>
<span id="cb2-14"><a href="#cb2-14"></a><span class="co"> &gt;&gt;&gt; q.dequeue()</span></span>
<span id="cb2-15"><a href="#cb2-15"></a><span class="co"> &#39;hello&#39;</span></span>
<span id="cb2-16"><a href="#cb2-16"></a><span class="co"> &gt;&gt;&gt; q.dequeue()</span></span>
<span id="cb2-17"><a href="#cb2-17"></a><span class="co"> &#39;goodbye&#39;</span></span>
<span id="cb2-18"><a href="#cb2-18"></a><span class="co"> &gt;&gt;&gt; q.is_empty()</span></span>
<span id="cb2-19"><a href="#cb2-19"></a><span class="co"> True</span></span>
<span id="cb2-20"><a href="#cb2-20"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb2-21"><a href="#cb2-21"></a> <span class="co"># Private Instance Attributes:</span></span>
<span id="cb2-22"><a href="#cb2-22"></a> <span class="co"># - _items: The items stored in this queue. The front of the list represents</span></span>
<span id="cb2-23"><a href="#cb2-23"></a> <span class="co"># the front of the queue.</span></span>
<span id="cb2-24"><a href="#cb2-24"></a> _items: <span class="bu">list</span></span>
<span id="cb2-25"><a href="#cb2-25"></a></span>
<span id="cb2-26"><a href="#cb2-26"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb2-27"><a href="#cb2-27"></a> <span class="co">&quot;&quot;&quot;Initialize a new empty queue.&quot;&quot;&quot;</span></span>
<span id="cb2-28"><a href="#cb2-28"></a> <span class="va">self</span>._items <span class="op">=</span> []</span>
<span id="cb2-29"><a href="#cb2-29"></a></span>
<span id="cb2-30"><a href="#cb2-30"></a> <span class="kw">def</span> is_empty(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="bu">bool</span>:</span>
<span id="cb2-31"><a href="#cb2-31"></a> <span class="co">&quot;&quot;&quot;Return whether this queue contains no items.</span></span>
<span id="cb2-32"><a href="#cb2-32"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb2-33"><a href="#cb2-33"></a> <span class="cf">return</span> <span class="va">self</span>._items <span class="op">==</span> []</span>
<span id="cb2-34"><a href="#cb2-34"></a></span>
<span id="cb2-35"><a href="#cb2-35"></a> <span class="kw">def</span> enqueue(<span class="va">self</span>, item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb2-36"><a href="#cb2-36"></a> <span class="co">&quot;&quot;&quot;Add &lt;item&gt; to the back of this queue.</span></span>
<span id="cb2-37"><a href="#cb2-37"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb2-38"><a href="#cb2-38"></a> <span class="va">self</span>._items.append(item)</span>
<span id="cb2-39"><a href="#cb2-39"></a></span>
<span id="cb2-40"><a href="#cb2-40"></a> <span class="kw">def</span> dequeue(<span class="va">self</span>) <span class="op">-&gt;</span> Optional[Any]:</span>
<span id="cb2-41"><a href="#cb2-41"></a> <span class="co">&quot;&quot;&quot;Remove and return the item at the front of this queue.</span></span>
<span id="cb2-42"><a href="#cb2-42"></a></span>
<span id="cb2-43"><a href="#cb2-43"></a><span class="co"> Raise an EmptyQueueError if this queue is empty.</span></span>
<span id="cb2-44"><a href="#cb2-44"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb2-45"><a href="#cb2-45"></a> <span class="cf">if</span> <span class="va">self</span>.is_empty():</span>
<span id="cb2-46"><a href="#cb2-46"></a> <span class="cf">raise</span> EmptyQueueError</span>
<span id="cb2-47"><a href="#cb2-47"></a> <span class="cf">else</span>:</span>
<span id="cb2-48"><a href="#cb2-48"></a> <span class="cf">return</span> <span class="va">self</span>._items.pop(<span class="dv">0</span>)</span></code></pre></div>
<h2 id="implementation-efficiency">Implementation efficiency</h2>
<p>Our <code>Queue.enqueue</code> calls <code>list.append</code>, which we know takes constant (<span class="math inline">\(\Theta(1)\)</span>) time. However, the <code>Queue.dequeue</code> calls <code>self._items.pop(0)</code>, which takes <span class="math inline">\(\Theta(n)\)</span> time (where <span class="math inline">\(n\)</span> is the number of items stored in the queue). If we changed things around so that the front of the queue is the end of the list (rather than the beginning), we simply swap these running times. This presents a trade-off; using an array-based list, we can <em>either</em> have an efficient enqueue or an efficient dequeue operation.</p>
<p>Is there, perhaps, another data structure we can use instead of a list to improve efficiency? Unfortunately, both <code>dict</code> and <code>set</code> are unordered data structures, but queues need to maintain (and remember) a very specific order. One interesting programming challenge is to implement a queue using two stacks, which can be done correctly but is not always more efficient. Eventually you will learn about even more interesting data structures, and it may be a good idea to revisit the Queue ADT and see how to use your new arsenal of data structures instead of a Python list. And because of abstraction (i.e., <code>_items</code> is a private attribute), you can modify your <code>Queue</code> implementation however you like without having to change any client code that uses it!</p>
</section>
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>
+272
View File
@@ -0,0 +1,272 @@
<!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>9.7 Priority Queues</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="../tufte.css" />
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" type="text/javascript"></script>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<div style="display:none">
\(
\newcommand{\NOT}{\neg}
\newcommand{\AND}{\wedge}
\newcommand{\OR}{\vee}
\newcommand{\XOR}{\oplus}
\newcommand{\IMP}{\Rightarrow}
\newcommand{\IFF}{\Leftrightarrow}
\newcommand{\TRUE}{\text{True}\xspace}
\newcommand{\FALSE}{\text{False}\xspace}
\newcommand{\IN}{\,{\in}\,}
\newcommand{\NOTIN}{\,{\notin}\,}
\newcommand{\TO}{\rightarrow}
\newcommand{\DIV}{\mid}
\newcommand{\NDIV}{\nmid}
\newcommand{\MOD}[1]{\pmod{#1}}
\newcommand{\MODS}[1]{\ (\text{mod}\ #1)}
\newcommand{\N}{\mathbb N}
\newcommand{\Z}{\mathbb Z}
\newcommand{\Q}{\mathbb Q}
\newcommand{\R}{\mathbb R}
\newcommand{\C}{\mathbb C}
\newcommand{\cA}{\mathcal A}
\newcommand{\cB}{\mathcal B}
\newcommand{\cC}{\mathcal C}
\newcommand{\cD}{\mathcal D}
\newcommand{\cE}{\mathcal E}
\newcommand{\cF}{\mathcal F}
\newcommand{\cG}{\mathcal G}
\newcommand{\cH}{\mathcal H}
\newcommand{\cI}{\mathcal I}
\newcommand{\cJ}{\mathcal J}
\newcommand{\cL}{\mathcal L}
\newcommand{\cK}{\mathcal K}
\newcommand{\cN}{\mathcal N}
\newcommand{\cO}{\mathcal O}
\newcommand{\cP}{\mathcal P}
\newcommand{\cQ}{\mathcal Q}
\newcommand{\cS}{\mathcal S}
\newcommand{\cT}{\mathcal T}
\newcommand{\cV}{\mathcal V}
\newcommand{\cW}{\mathcal W}
\newcommand{\cZ}{\mathcal Z}
\newcommand{\emp}{\emptyset}
\newcommand{\bs}{\backslash}
\newcommand{\floor}[1]{\left \lfloor #1 \right \rfloor}
\newcommand{\ceil}[1]{\left \lceil #1 \right \rceil}
\newcommand{\abs}[1]{\left | #1 \right |}
\newcommand{\xspace}{}
\newcommand{\proofheader}[1]{\underline{\textbf{#1}}}
\)
</div>
<header id="title-block-header">
<h1 class="title">9.7 Priority Queues</h1>
</header>
<section>
<p>Not all lineups work the same way. While the lineup at a McDonalds restaurant serves customers in a first-in-first-out order, the emergency room at a hospital does not see patients in the order that they arrive. Instead, the medical team perform an initial assessment of each patient for the severity of their illness, and patients with more life-threatening issues are seen earlier than others, regardless of when they arrived. In other words, patients are <em>prioritized</em> based on their condition.</p>
<h2 id="the-priority-queue-adt">The Priority Queue ADT</h2>
<p>The <strong>Priority Queue ADT</strong> is similar to the Queue ADT, except that every item has some measure of its “priority”. Items are removed from a Priority Queue in order of their priority, and ties are broken in FIFO order. To summarize:</p>
<ul>
<li><strong>Priority Queue</strong>
<ul>
<li>Data: a collection of items and their priorities</li>
<li>Operations: determine whether the priority queue is empty, add an item with a priority (<em>enqueue</em>), remove the highest priority item (<em>dequeue</em>)</li>
</ul></li>
</ul>
<p>One subtlety with our definition of this ADT is in how we represent priorities. For this section, well simply represent priorities as integers, with larger integers representing higher priorities. Well see a different way of representing priorites in the next chapter.</p>
<p>Here is the public interface of a <code>PriorityQueue</code> class.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">class</span> PriorityQueue:</span>
<span id="cb1-2"><a href="#cb1-2"></a> <span class="co">&quot;&quot;&quot;A collection items that are be removed in priority order.</span></span>
<span id="cb1-3"><a href="#cb1-3"></a></span>
<span id="cb1-4"><a href="#cb1-4"></a><span class="co"> When removing an item from the queue, the highest-priority item is the one</span></span>
<span id="cb1-5"><a href="#cb1-5"></a><span class="co"> that is removed.</span></span>
<span id="cb1-6"><a href="#cb1-6"></a></span>
<span id="cb1-7"><a href="#cb1-7"></a><span class="co"> &gt;&gt;&gt; pq = PriorityQueue()</span></span>
<span id="cb1-8"><a href="#cb1-8"></a><span class="co"> &gt;&gt;&gt; pq.is_empty()</span></span>
<span id="cb1-9"><a href="#cb1-9"></a><span class="co"> True</span></span>
<span id="cb1-10"><a href="#cb1-10"></a><span class="co"> &gt;&gt;&gt; pq.enqueue(1, &#39;hello&#39;)</span></span>
<span id="cb1-11"><a href="#cb1-11"></a><span class="co"> &gt;&gt;&gt; pq.is_empty()</span></span>
<span id="cb1-12"><a href="#cb1-12"></a><span class="co"> False</span></span>
<span id="cb1-13"><a href="#cb1-13"></a><span class="co"> &gt;&gt;&gt; pq.enqueue(5, &#39;goodbye&#39;)</span></span>
<span id="cb1-14"><a href="#cb1-14"></a><span class="co"> &gt;&gt;&gt; pq.enqueue(2, &#39;hi&#39;)</span></span>
<span id="cb1-15"><a href="#cb1-15"></a><span class="co"> &gt;&gt;&gt; pq.dequeue()</span></span>
<span id="cb1-16"><a href="#cb1-16"></a><span class="co"> &#39;goodbye&#39;</span></span>
<span id="cb1-17"><a href="#cb1-17"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-18"><a href="#cb1-18"></a></span>
<span id="cb1-19"><a href="#cb1-19"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb1-20"><a href="#cb1-20"></a> <span class="co">&quot;&quot;&quot;Initialize a new and empty priority queue.&quot;&quot;&quot;</span></span>
<span id="cb1-21"><a href="#cb1-21"></a></span>
<span id="cb1-22"><a href="#cb1-22"></a> <span class="kw">def</span> is_empty(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="bu">bool</span>:</span>
<span id="cb1-23"><a href="#cb1-23"></a> <span class="co">&quot;&quot;&quot;Return whether this priority queue contains no items.</span></span>
<span id="cb1-24"><a href="#cb1-24"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-25"><a href="#cb1-25"></a></span>
<span id="cb1-26"><a href="#cb1-26"></a> <span class="kw">def</span> enqueue(<span class="va">self</span>, priority: <span class="bu">int</span>, item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb1-27"><a href="#cb1-27"></a> <span class="co">&quot;&quot;&quot;Add the given item with the given priority to this priority queue.</span></span>
<span id="cb1-28"><a href="#cb1-28"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-29"><a href="#cb1-29"></a></span>
<span id="cb1-30"><a href="#cb1-30"></a> <span class="kw">def</span> dequeue(<span class="va">self</span>) <span class="op">-&gt;</span> Any:</span>
<span id="cb1-31"><a href="#cb1-31"></a> <span class="co">&quot;&quot;&quot;Remove and return the item with the highest priority.</span></span>
<span id="cb1-32"><a href="#cb1-32"></a></span>
<span id="cb1-33"><a href="#cb1-33"></a><span class="co"> Raise an EmptyPriorityQueueError when the priority queue is empty.</span></span>
<span id="cb1-34"><a href="#cb1-34"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-35"><a href="#cb1-35"></a></span>
<span id="cb1-36"><a href="#cb1-36"></a></span>
<span id="cb1-37"><a href="#cb1-37"></a><span class="kw">class</span> EmptyPriorityQueueError(<span class="pp">Exception</span>):</span>
<span id="cb1-38"><a href="#cb1-38"></a> <span class="co">&quot;&quot;&quot;Exception raised when calling pop on an empty stack.&quot;&quot;&quot;</span></span>
<span id="cb1-39"><a href="#cb1-39"></a></span>
<span id="cb1-40"><a href="#cb1-40"></a> <span class="kw">def</span> <span class="fu">__str__</span>(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="bu">str</span>:</span>
<span id="cb1-41"><a href="#cb1-41"></a> <span class="co">&quot;&quot;&quot;Return a string representation of this error.&quot;&quot;&quot;</span></span>
<span id="cb1-42"><a href="#cb1-42"></a> <span class="cf">return</span> <span class="st">&#39;You called dequeue on an empty priority queue.&#39;</span></span></code></pre></div>
<h2 id="list-based-implementation-of-the-priority-queue-adt">List-based implementation of the Priority Queue ADT</h2>
<p>Unlike with the Stack and Queue ADTs, it is not clear if we can use a list here. Somehow we need to not only store items, but also keep track of which one has the largest priority, and in the case of ties, which one was inserted first.</p>
<p>Our implementation idea here is to use a private attribute that is a <em>list of tuples</em>, where each tuple is a <code>(priority, item)</code> pair. Our list will also be <em>sorted</em> with respect to priority (breaking ties by insertion order), so that the <em>last</em> element in the list is always the next item to be removed from the priority queue.</p>
<p>With this idea, three of the four <code>PriorityQueue</code> methods are straightforward to implement:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1"></a><span class="im">from</span> typing <span class="im">import</span> Any</span>
<span id="cb2-2"><a href="#cb2-2"></a></span>
<span id="cb2-3"><a href="#cb2-3"></a></span>
<span id="cb2-4"><a href="#cb2-4"></a><span class="kw">class</span> PriorityQueue:</span>
<span id="cb2-5"><a href="#cb2-5"></a> <span class="co">&quot;&quot;&quot;A queue of items that can be dequeued in priority order.</span></span>
<span id="cb2-6"><a href="#cb2-6"></a></span>
<span id="cb2-7"><a href="#cb2-7"></a><span class="co"> When removing an item from the queue, the highest-priority item is the one</span></span>
<span id="cb2-8"><a href="#cb2-8"></a><span class="co"> that is removed.</span></span>
<span id="cb2-9"><a href="#cb2-9"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb2-10"><a href="#cb2-10"></a> <span class="co"># Private Instance Attributes:</span></span>
<span id="cb2-11"><a href="#cb2-11"></a> <span class="co"># - _items: a list of the items in this priority queue</span></span>
<span id="cb2-12"><a href="#cb2-12"></a> _items: <span class="bu">list</span>[<span class="bu">tuple</span>[<span class="bu">int</span>, Any]]</span>
<span id="cb2-13"><a href="#cb2-13"></a></span>
<span id="cb2-14"><a href="#cb2-14"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb2-15"><a href="#cb2-15"></a> <span class="co">&quot;&quot;&quot;Initialize a new and empty priority queue.&quot;&quot;&quot;</span></span>
<span id="cb2-16"><a href="#cb2-16"></a> <span class="va">self</span>._items <span class="op">=</span> []</span>
<span id="cb2-17"><a href="#cb2-17"></a></span>
<span id="cb2-18"><a href="#cb2-18"></a> <span class="kw">def</span> is_empty(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="bu">bool</span>:</span>
<span id="cb2-19"><a href="#cb2-19"></a> <span class="co">&quot;&quot;&quot;Return whether this priority queue contains no items.</span></span>
<span id="cb2-20"><a href="#cb2-20"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb2-21"><a href="#cb2-21"></a> <span class="cf">return</span> <span class="va">self</span>._items <span class="op">==</span> []</span>
<span id="cb2-22"><a href="#cb2-22"></a></span>
<span id="cb2-23"><a href="#cb2-23"></a> <span class="kw">def</span> dequeue(<span class="va">self</span>) <span class="op">-&gt;</span> Any:</span>
<span id="cb2-24"><a href="#cb2-24"></a> <span class="co">&quot;&quot;&quot;Remove and return the item with the highest priority.</span></span>
<span id="cb2-25"><a href="#cb2-25"></a></span>
<span id="cb2-26"><a href="#cb2-26"></a><span class="co"> Raise an EmptyPriorityQueueError when the priority queue is empty.</span></span>
<span id="cb2-27"><a href="#cb2-27"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb2-28"><a href="#cb2-28"></a> <span class="cf">if</span> <span class="va">self</span>.is_empty():</span>
<span id="cb2-29"><a href="#cb2-29"></a> <span class="cf">raise</span> EmptyPriorityQueueError</span>
<span id="cb2-30"><a href="#cb2-30"></a> <span class="cf">else</span>:</span>
<span id="cb2-31"><a href="#cb2-31"></a> _priority, item <span class="op">=</span> <span class="va">self</span>._items.pop()</span>
<span id="cb2-32"><a href="#cb2-32"></a> <span class="cf">return</span> item</span></code></pre></div>
<p>As an exercise, well leave you to show that each of these operations also runs in <span class="math inline">\(\Theta(1)\)</span> time. But what about <code>PriorityQueue.enqueue</code>? An initial approach might be to first insert the new priority and item into the list, and then sort the list by priority. But this is a bit inefficient: we shouldnt need to re-sort the entire list, if we start with a sorted list and are simply inserting one new item.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> We make this observation precise by observing that the worst-case running time of <code>list.sort</code> is <span class="math inline">\(\Theta(n \log n)\)</span>. Well study sorting algorithms in detail later on this year.</span> So instead, our <code>enqueue</code> implementation will search for the right index in the list to add the new item. For example, suppose we want to insert the item <code>'hi'</code> with priority <code>5</code> into the priority queue with <code>self._items</code> equal to <code>[(1, 'a'), (4, 'b'), (6, 'c'), (10, 'd')]</code>. We need to insert <code>(5, 'hi')</code> into index 2 in this list:</p>
<p><img src="./images/priority_queue_enqueue.png" alt="A diagram of priority queue enqueue" /><br />
</p>
<p>Here is our implementation of <code>enqueue</code>:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1"></a><span class="kw">class</span> PriorityQueue:</span>
<span id="cb3-2"><a href="#cb3-2"></a> ...</span>
<span id="cb3-3"><a href="#cb3-3"></a></span>
<span id="cb3-4"><a href="#cb3-4"></a> <span class="kw">def</span> enqueue(<span class="va">self</span>, priority: <span class="bu">int</span>, item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb3-5"><a href="#cb3-5"></a> <span class="co">&quot;&quot;&quot;Add the given item with the given priority to this priority queue.</span></span>
<span id="cb3-6"><a href="#cb3-6"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb3-7"><a href="#cb3-7"></a> i <span class="op">=</span> <span class="dv">0</span></span>
<span id="cb3-8"><a href="#cb3-8"></a> <span class="cf">while</span> i <span class="op">&lt;</span> <span class="bu">len</span>(<span class="va">self</span>._items) <span class="kw">and</span> <span class="va">self</span>._items[i][<span class="dv">0</span>] <span class="op">&lt;</span> priority:</span>
<span id="cb3-9"><a href="#cb3-9"></a> <span class="co"># Loop invariant: all items in self._items[0:i]</span></span>
<span id="cb3-10"><a href="#cb3-10"></a> <span class="co"># have a lower priority than &lt;priority&gt;.</span></span>
<span id="cb3-11"><a href="#cb3-11"></a> i <span class="op">=</span> i <span class="op">+</span> <span class="dv">1</span></span>
<span id="cb3-12"><a href="#cb3-12"></a></span>
<span id="cb3-13"><a href="#cb3-13"></a> <span class="va">self</span>._items.insert(i, (priority, item))</span></code></pre></div>
<p>In the second part of the loop condition, you might wonder about the <code>&lt;</code>: could we do <code>self._items[i][0] &lt;= priority</code> instead? Does it make a difference? It turns out that switching <code>&lt;</code> for <code>&lt;=</code> in the second part of the condition does make a difference when it comes to breaking ties. Well leave it as an exercise for you to work this out: try tracing an <code>enqueue</code> operation for the item <code>'hi'</code> with priority <code>5</code> into the priority queue with <code>self._items</code> equal to <code>[(1, 'a'), (5, 'b'), (5, 'c'), (10, 'd')]</code>.</p>
<p>And finally, what is the running time of this implementation of <code>PriorityQueue.enqueue</code>, for a priority queue with <span class="math inline">\(n\)</span> elements? The loop here is a bit tricky to analyze because the number of iterations is not a fixed number in terms of <span class="math inline">\(n\)</span>. Here is one analysis:</p>
<ul>
<li><p>The while loop takes <em>at most</em> <span class="math inline">\(n\)</span> iterations, since <code>i</code> starts at 0 and increases by 1 at each iteration, and the loop must stop when <code>i</code> reaches <span class="math inline">\(n\)</span> (if it hasnt stopped earlier).</p>
<p>Since each loop iteration takes 1 step, in total the while loop takes at most <span class="math inline">\(n\)</span> steps.</p></li>
<li><p>We know from our study of array-based lists that <code>list.insert</code> takes at most <span class="math inline">\(n\)</span> steps, where <span class="math inline">\(n\)</span> is the length of the list being inserted into.</p></li>
<li><p>Adding up these two quantities, the total running time of this algorithm is at most <span class="math inline">\(n + n = 2n\)</span> steps, which is <span class="math inline">\(\cO(n)\)</span>.</p></li>
</ul>
<p>Of course, we shouldnt be satisfied with just an upper bound on the running time! It turns out that we can do better by incorporating the value of variable <code>i</code> in our calculation. Let <span class="math inline">\(I\)</span> be the value of variable <code>i</code> <em>after</em> the loop finishes. Then:</p>
<ul>
<li>We now know that the while loop takes <em>exactly</em> <span class="math inline">\(I\)</span> iterations, for a total of <span class="math inline">\(I\)</span> steps (1 step per iteration).</li>
<li>We know that calling <code>list.insert</code> on a list of length <span class="math inline">\(n\)</span> to insert an item at index <span class="math inline">\(I\)</span> takes <span class="math inline">\(n - I\)</span> steps.</li>
<li>So the total running time is actually <span class="math inline">\(I + (n - I) = n\)</span> steps, which is <span class="math inline">\(\Theta(n)\)</span>.</li>
</ul>
<p>In other words, weve shown that <em>every</em> call to this implementation of <code>PriorityQueue.enqueue</code> will take <span class="math inline">\(\Theta(n)\)</span> time, regardless of the priority being inserted.</p>
<h3 id="using-an-unsorted-list">Using an unsorted list</h3>
<p>Our implementation of <code>PriorityQueue</code> has a constant-time <code>dequeue</code> but a linear-time <code>enqueue</code>. You might naturally wonder if we can do better: what if we used an unsorted list of tuples instead? This would allow us to have <span class="math inline">\(\Theta(1)\)</span> <code>enqueue</code> operations, simply by appending a new <code>(priority, item)</code> tuple to the end of <code>self._items</code>. However, we have simply shifted the work over to the <code>dequeue</code> operation. Specifically, we must search for the highest priority item in a list of unsorted items, which would take <span class="math inline">\(\Theta(n)\)</span> time. Yet another trade-off!</p>
<h3 id="looking-ahead-heaps">Looking ahead: heaps</h3>
<p>In CSC263/CSC265, youll learn about the <em>heap</em>, a data structure which is commonly used to implement the Priority Queue ADT in practice. We can use this data structure to implement both <code>PriorityQueue.enqueue</code> and <code>PriorityQueue.dequeue</code> with a worst-case running time of <span class="math inline">\(\Theta(\log n)\)</span>.<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> This is actually the approach taken by Pythons built-in <a href="https://docs.python.org/3/library/heapq.html"><code>heapq</code> module</a>. Pretty neat!</span></p>
</section>
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>
+316
View File
@@ -0,0 +1,316 @@
<!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>9.8 Defining a Shared Public Interface with Inheritance</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="../tufte.css" />
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<div style="display:none">
\(
\newcommand{\NOT}{\neg}
\newcommand{\AND}{\wedge}
\newcommand{\OR}{\vee}
\newcommand{\XOR}{\oplus}
\newcommand{\IMP}{\Rightarrow}
\newcommand{\IFF}{\Leftrightarrow}
\newcommand{\TRUE}{\text{True}\xspace}
\newcommand{\FALSE}{\text{False}\xspace}
\newcommand{\IN}{\,{\in}\,}
\newcommand{\NOTIN}{\,{\notin}\,}
\newcommand{\TO}{\rightarrow}
\newcommand{\DIV}{\mid}
\newcommand{\NDIV}{\nmid}
\newcommand{\MOD}[1]{\pmod{#1}}
\newcommand{\MODS}[1]{\ (\text{mod}\ #1)}
\newcommand{\N}{\mathbb N}
\newcommand{\Z}{\mathbb Z}
\newcommand{\Q}{\mathbb Q}
\newcommand{\R}{\mathbb R}
\newcommand{\C}{\mathbb C}
\newcommand{\cA}{\mathcal A}
\newcommand{\cB}{\mathcal B}
\newcommand{\cC}{\mathcal C}
\newcommand{\cD}{\mathcal D}
\newcommand{\cE}{\mathcal E}
\newcommand{\cF}{\mathcal F}
\newcommand{\cG}{\mathcal G}
\newcommand{\cH}{\mathcal H}
\newcommand{\cI}{\mathcal I}
\newcommand{\cJ}{\mathcal J}
\newcommand{\cL}{\mathcal L}
\newcommand{\cK}{\mathcal K}
\newcommand{\cN}{\mathcal N}
\newcommand{\cO}{\mathcal O}
\newcommand{\cP}{\mathcal P}
\newcommand{\cQ}{\mathcal Q}
\newcommand{\cS}{\mathcal S}
\newcommand{\cT}{\mathcal T}
\newcommand{\cV}{\mathcal V}
\newcommand{\cW}{\mathcal W}
\newcommand{\cZ}{\mathcal Z}
\newcommand{\emp}{\emptyset}
\newcommand{\bs}{\backslash}
\newcommand{\floor}[1]{\left \lfloor #1 \right \rfloor}
\newcommand{\ceil}[1]{\left \lceil #1 \right \rceil}
\newcommand{\abs}[1]{\left | #1 \right |}
\newcommand{\xspace}{}
\newcommand{\proofheader}[1]{\underline{\textbf{#1}}}
\)
</div>
<header id="title-block-header">
<h1 class="title">9.8 Defining a Shared Public Interface with Inheritance</h1>
</header>
<section>
<p>In this chapter, we have learned that an abstract data type can have multiple implementations, and seen this first-hand with a variety of ADTs. For example, in <a href="04-stacks.html">9.4 Stacks</a> we saw that the Stack ADT can be implemented using a Python list in two different ways, storing the top of the stack at the end of the list (<code>Stack1</code>) or the front of the list (<code>Stack2</code>). Though these two classes had different implementations, they shared the same <em>public interface</em> of the Stack ADT.</p>
<p>One limitation of the code we wrote for these two classes is that the only way to tell that <code>Stack1</code> and <code>Stack2</code> had the same interface was from their method names and docstrings. In this section, well see how to create a special kind of Python class that is used to define a public interface that can be implemented by other classes, using a Python language feature known as <em>inheritance</em>.</p>
<h2 id="the-stack-abstract-class">The Stack abstract class</h2>
<p>Let us begin by defining a <code>Stack</code> class that consists only of the <em>public interface</em> of the Stack ADT.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">class</span> Stack:</span>
<span id="cb1-2"><a href="#cb1-2"></a> <span class="co">&quot;&quot;&quot;A last-in-first-out (LIFO) stack of items.</span></span>
<span id="cb1-3"><a href="#cb1-3"></a></span>
<span id="cb1-4"><a href="#cb1-4"></a><span class="co"> This is an abstract class. Only subclasses should be instantiated.</span></span>
<span id="cb1-5"><a href="#cb1-5"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-6"><a href="#cb1-6"></a></span>
<span id="cb1-7"><a href="#cb1-7"></a> <span class="kw">def</span> is_empty(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="bu">bool</span>:</span>
<span id="cb1-8"><a href="#cb1-8"></a> <span class="co">&quot;&quot;&quot;Return whether this stack contains no items.</span></span>
<span id="cb1-9"><a href="#cb1-9"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-10"><a href="#cb1-10"></a> <span class="cf">raise</span> <span class="pp">NotImplementedError</span></span>
<span id="cb1-11"><a href="#cb1-11"></a></span>
<span id="cb1-12"><a href="#cb1-12"></a> <span class="kw">def</span> push(<span class="va">self</span>, item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb1-13"><a href="#cb1-13"></a> <span class="co">&quot;&quot;&quot;Add a new element to the top of this stack.</span></span>
<span id="cb1-14"><a href="#cb1-14"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-15"><a href="#cb1-15"></a> <span class="cf">raise</span> <span class="pp">NotImplementedError</span></span>
<span id="cb1-16"><a href="#cb1-16"></a></span>
<span id="cb1-17"><a href="#cb1-17"></a> <span class="kw">def</span> pop(<span class="va">self</span>) <span class="op">-&gt;</span> Any:</span>
<span id="cb1-18"><a href="#cb1-18"></a> <span class="co">&quot;&quot;&quot;Remove and return the element at the top of this stack.</span></span>
<span id="cb1-19"><a href="#cb1-19"></a></span>
<span id="cb1-20"><a href="#cb1-20"></a><span class="co"> Raise an EmptyStackError if this stack is empty.</span></span>
<span id="cb1-21"><a href="#cb1-21"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb1-22"><a href="#cb1-22"></a> <span class="cf">raise</span> <span class="pp">NotImplementedError</span></span>
<span id="cb1-23"><a href="#cb1-23"></a></span>
<span id="cb1-24"><a href="#cb1-24"></a></span>
<span id="cb1-25"><a href="#cb1-25"></a><span class="kw">class</span> EmptyStackError(<span class="pp">Exception</span>):</span>
<span id="cb1-26"><a href="#cb1-26"></a> <span class="co">&quot;&quot;&quot;Exception raised when calling pop on an empty stack.&quot;&quot;&quot;</span></span></code></pre></div>
<p>In Python, we mark a method as unimplemented by having its body raise a special exception, <code>NotImplementedError</code>. We say that a method is <strong>abstract</strong> when it is not implemented and raises this error; we say that a <em>class</em> is <strong>abstract</strong> when at least one of its methods is abstract (i.e., not implemented). A <strong>concrete class</strong> is a class that is not abstract; so far in this course, weve been dealing with concrete classes, and called them concrete data types.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> The terminology here is a bit confusing because of the multiple uses of certain terms. A concrete Python class is the same as a concrete data type. However, an abstract Python class is <em>not</em> the same thing as an abstract data type; the former has a technical meaning specific to the Python programming language, while the latter is the name given to an abstract description of a data type that is programming language-independent.</span></p>
<p>Now, you might wonder what the purpose of an abstract class is. Indeed, a programmer who creates a <code>Stack</code> object will quickly find it is useless, because calling the Stack ADT operations cause errors:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1"></a><span class="op">&gt;&gt;&gt;</span> s <span class="op">=</span> Stack()</span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="op">&gt;&gt;&gt;</span> s.push(<span class="dv">30</span>)</span>
<span id="cb2-3"><a href="#cb2-3"></a>Traceback...</span>
<span id="cb2-4"><a href="#cb2-4"></a><span class="pp">NotImplementedError</span></span>
<span id="cb2-5"><a href="#cb2-5"></a><span class="op">&gt;&gt;&gt;</span> s.pop()</span>
<span id="cb2-6"><a href="#cb2-6"></a>Traceback...</span>
<span id="cb2-7"><a href="#cb2-7"></a><span class="pp">NotImplementedError</span></span></code></pre></div>
<p>If we cant use the <code>Stack</code> object for any of the Stack ADT operations, what was the point in creating it? The answer is very much based on abstraction, hence the name abstract class. The <code>Stack</code> class we have defined is a direct translation of the Stack ADT: an <strong>interface</strong> that describes the methods that a concrete class that wants to implement the Stack ADT <em>must</em> define. Python gives us a way to describe the relationship between an abstract class and a concrete class that implements its methods directly in the code.</p>
<h2 id="inheriting-the-stack-abstract-class">Inheriting the Stack abstract class</h2>
<p>Earlier in this chapter, we defined two new types: <code>Stack1</code> and <code>Stack2</code>. However, despite the two types sharing the same method names, the code did not indicate that the types were related in any way. Now that we have the abstract class <code>Stack</code>, we can indicate this relationship in the code through <strong>inheritance</strong>:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1"></a><span class="kw">class</span> Stack1(Stack):</span>
<span id="cb3-2"><a href="#cb3-2"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb3-3"><a href="#cb3-3"></a> <span class="co">&quot;&quot;&quot;Initialize a new empty stack.</span></span>
<span id="cb3-4"><a href="#cb3-4"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb3-5"><a href="#cb3-5"></a> <span class="va">self</span>._items <span class="op">=</span> []</span>
<span id="cb3-6"><a href="#cb3-6"></a></span>
<span id="cb3-7"><a href="#cb3-7"></a> <span class="kw">def</span> is_empty(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="bu">bool</span>:</span>
<span id="cb3-8"><a href="#cb3-8"></a> <span class="co">&quot;&quot;&quot;...&quot;&quot;&quot;</span></span>
<span id="cb3-9"><a href="#cb3-9"></a> <span class="cf">return</span> <span class="va">self</span>._items <span class="op">==</span> []</span>
<span id="cb3-10"><a href="#cb3-10"></a></span>
<span id="cb3-11"><a href="#cb3-11"></a> <span class="kw">def</span> push(<span class="va">self</span>, item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb3-12"><a href="#cb3-12"></a> <span class="co">&quot;&quot;&quot;...&quot;&quot;&quot;</span></span>
<span id="cb3-13"><a href="#cb3-13"></a> <span class="va">self</span>._items.append(item)</span>
<span id="cb3-14"><a href="#cb3-14"></a></span>
<span id="cb3-15"><a href="#cb3-15"></a> <span class="kw">def</span> pop(<span class="va">self</span>) <span class="op">-&gt;</span> Any:</span>
<span id="cb3-16"><a href="#cb3-16"></a> <span class="co">&quot;&quot;&quot;...&quot;&quot;&quot;</span></span>
<span id="cb3-17"><a href="#cb3-17"></a> <span class="cf">return</span> <span class="va">self</span>._items.pop()</span>
<span id="cb3-18"><a href="#cb3-18"></a></span>
<span id="cb3-19"><a href="#cb3-19"></a></span>
<span id="cb3-20"><a href="#cb3-20"></a><span class="kw">class</span> Stack2(Stack):</span>
<span id="cb3-21"><a href="#cb3-21"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb3-22"><a href="#cb3-22"></a> <span class="co">&quot;&quot;&quot;Initialize a new empty stack.</span></span>
<span id="cb3-23"><a href="#cb3-23"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb3-24"><a href="#cb3-24"></a> <span class="va">self</span>._items <span class="op">=</span> []</span>
<span id="cb3-25"><a href="#cb3-25"></a></span>
<span id="cb3-26"><a href="#cb3-26"></a> <span class="kw">def</span> is_empty(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="bu">bool</span>:</span>
<span id="cb3-27"><a href="#cb3-27"></a> <span class="co">&quot;&quot;&quot;...&quot;&quot;&quot;</span></span>
<span id="cb3-28"><a href="#cb3-28"></a> <span class="cf">return</span> <span class="va">self</span>._items <span class="op">==</span> []</span>
<span id="cb3-29"><a href="#cb3-29"></a></span>
<span id="cb3-30"><a href="#cb3-30"></a> <span class="kw">def</span> push(<span class="va">self</span>, item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb3-31"><a href="#cb3-31"></a> <span class="co">&quot;&quot;&quot;...&quot;&quot;&quot;</span></span>
<span id="cb3-32"><a href="#cb3-32"></a> <span class="va">self</span>._items.insert(<span class="dv">0</span>, item)</span>
<span id="cb3-33"><a href="#cb3-33"></a></span>
<span id="cb3-34"><a href="#cb3-34"></a> <span class="kw">def</span> pop(<span class="va">self</span>) <span class="op">-&gt;</span> Any:</span>
<span id="cb3-35"><a href="#cb3-35"></a> <span class="co">&quot;&quot;&quot;...&quot;&quot;&quot;</span></span>
<span id="cb3-36"><a href="#cb3-36"></a> <span class="cf">return</span> <span class="va">self</span>._items.pop(<span class="dv">0</span>)</span></code></pre></div>
<p>In the class header <code>class Stack1(Stack)</code> and <code>class Stack2(Stack)</code>, the syntax <code>(Stack)</code> indicates that <code>Stack1</code> and <code>Stack2</code> inherit from <code>Stack</code>. There are specific words we use to talk about these relationships:</p>
<ul>
<li><code>Stack</code>: base class, superclass, and parent class are synonyms.</li>
<li><code>Stack1</code>, <code>Stack2</code>: subclass, child class, and derived class are synonyms.</li>
</ul>
<p>For example, we can say that “<code>Stack</code> is the parent class of <code>Stack1</code>” or “<code>Stack2</code> is a subclass of <code>Stack</code>”.</p>
<p><img src="images/stacks_inheritance_diagram.png" /></p>
<p>When one class in Python inherits from another, there are two important consequences. First, the Python interpreter treats every instance of the subclass as an instance of the superclass as well.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1"></a><span class="op">&gt;&gt;&gt;</span> s1 <span class="op">=</span> Stack1()</span>
<span id="cb4-2"><a href="#cb4-2"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">isinstance</span>(s1, Stack1)</span>
<span id="cb4-3"><a href="#cb4-3"></a><span class="va">True</span></span>
<span id="cb4-4"><a href="#cb4-4"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">isinstance</span>(s1, Stack)</span>
<span id="cb4-5"><a href="#cb4-5"></a><span class="va">True</span></span>
<span id="cb4-6"><a href="#cb4-6"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">isinstance</span>(s1, Stack2)</span>
<span id="cb4-7"><a href="#cb4-7"></a><span class="va">False</span></span></code></pre></div>
<p>Second, when the superclass is abstract, the subclass must implement all abstract methods from the superclass, without changing the public interface of those methods. Just like preconditions and representation invariants, inheritance serves as another form of <em>contract</em>:</p>
<ul>
<li>The implementor of the subclass must implement the methods from the abstract superclass.</li>
<li>Any user of the subclass may assume that they can call the superclass methods on instances of the subclass.</li>
</ul>
<p>So for example, if we say that <code>Stack1</code> is a subclass of <code>Stack</code>, then any user of <code>Stack1</code> can expect to be able to call <code>push</code>, <code>pop</code>, and <code>is_empty</code> on <code>Stack1</code> instances. And of course the same applies to <code>Stack2</code> as well.</p>
<p>It is this expectation that allows us to use inheritance in Python to express a <em>shared public interface</em> between multiples classes. In our example, because <code>Stack1</code> and <code>Stack2</code> are both subclasses of <code>Stack</code>, we expect them implement all the stack methods. They might also implement additional methods that are unique to each subclass (<em>not</em> shared), but this is not required.</p>
<h2 id="writing-polymorphic-code-using-inheritance">Writing polymorphic code using inheritance</h2>
<p>Suppose we are writing code that operations on a stack, like in the following function:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">def</span> push_and_pop(s: ..., item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb5-2"><a href="#cb5-2"></a> <span class="co">&quot;&quot;&quot;Push and pop the given item onto the stack s.&quot;&quot;&quot;</span></span>
<span id="cb5-3"><a href="#cb5-3"></a> s.push(item)</span>
<span id="cb5-4"><a href="#cb5-4"></a> s.pop()</span></code></pre></div>
<p>What type annotation would be appropriate for <code>s</code>? If we use a concrete stack implementation like <code>Stack1</code>, this would rule out other stack implementations for this function. Instead, we use the abstract class <code>Stack</code> as the type annotation, to indicate that our function <code>push_and_pop</code> can be called with <em>any</em> instance of any <code>Stack</code> subclass.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">def</span> push_and_pop(s: Stack, item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb6-2"><a href="#cb6-2"></a> <span class="co">&quot;&quot;&quot;Push and pop the given item onto the stack s.&quot;&quot;&quot;</span></span>
<span id="cb6-3"><a href="#cb6-3"></a> s.push(item)</span>
<span id="cb6-4"><a href="#cb6-4"></a> s.pop()</span></code></pre></div>
<p>Remember that <code>Stack</code> defines a public interface that is shared between all of its subclasses: the body of <code>push_and_pop</code> only needs to call methods from that interface (<code>pop</code> and <code>push</code>), and doesnt worry about how those methods are implemented. This allows us to pass to the <code>push_and_pop</code> function a <code>Stack1</code> or <code>Stack2</code> object, which both inherit from <code>Stack</code>.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1"></a><span class="op">&gt;&gt;&gt;</span> s1 <span class="op">=</span> Stack1()</span>
<span id="cb7-2"><a href="#cb7-2"></a><span class="op">&gt;&gt;&gt;</span> push_and_pop(s1) <span class="co"># This works!</span></span>
<span id="cb7-3"><a href="#cb7-3"></a><span class="op">&gt;&gt;&gt;</span> s2 <span class="op">=</span> Stack2()</span>
<span id="cb7-4"><a href="#cb7-4"></a><span class="op">&gt;&gt;&gt;</span> push_and_pop(s2) <span class="co"># This also works!</span></span></code></pre></div>
<p>You might notice that there are actually three versions of <code>push</code> in our code: <code>Stack.push</code>, <code>Stack1.push</code>, and <code>Stack2.push</code>. So which method does the Python interpreter choose when the <code>push_and_pop</code> function is called? This is how it works for <code>s.push(item)</code> (<code>s.pop()</code> is handled similarly):</p>
<ol type="1">
<li>When the Python interpreter evaluates <code>s.push(item)</code>, it first computes <code>type(s)</code>. The result will depend on the argument we passed in—in our above example, <code>type(s1)</code> is <code>Stack1</code>, and <code>type(s2)</code> is <code>Stack2</code>.</li>
<li>The Python interpreter then looks in that class for a <code>push</code> method and calls it, passing in <code>s</code> for the <code>self</code> argument.<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote">There are instances with inheritance where a subclass might not implement a particular method from the superclass. Well look at some examples of this in the next section.</span></li>
</ol>
<p>We say that the Python interpreter <em>dynamically looks up (or resolves) the <code>s.push</code>/<code>.pop</code> method</em>, because the actual method called by <code>s.push</code>/<code>s.pop</code> changes depending on the argument passed to <code>push_and_pop</code>.</p>
<p>We say that the <code>push_and_pop</code> function is <strong>polymorphic</strong>, meaning it can take as inputs values of different concrete data type and select a specific method based on the type of input. This support for polymorphism is also why the “object dot notation” style of method call is preferred to the “class dot notation” style weve been using up to this point. Consider the following two alternate implementations of <code>push_and_pop</code>:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1"></a><span class="kw">def</span> push_and_pop_alt1(s: Stack, item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb8-2"><a href="#cb8-2"></a> <span class="co">&quot;&quot;&quot;Push and pop the given item onto the stack s.&quot;&quot;&quot;</span></span>
<span id="cb8-3"><a href="#cb8-3"></a> Stack.push(s, item)</span>
<span id="cb8-4"><a href="#cb8-4"></a> Stack.pop(s)</span>
<span id="cb8-5"><a href="#cb8-5"></a></span>
<span id="cb8-6"><a href="#cb8-6"></a></span>
<span id="cb8-7"><a href="#cb8-7"></a><span class="kw">def</span> push_and_pop_alt2(s: Stack, item: Any) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb8-8"><a href="#cb8-8"></a> <span class="co">&quot;&quot;&quot;Push and pop the given item onto the stack s.&quot;&quot;&quot;</span></span>
<span id="cb8-9"><a href="#cb8-9"></a> Stack1.push(s, item)</span>
<span id="cb8-10"><a href="#cb8-10"></a> Stack1.pop(s)</span></code></pre></div>
<p>The first version (<code>alt1</code>) explicitly calls the <code>Stack.push</code> and <code>Stack.pop</code> methods, both of which are unimplemented and would raise a <code>NotImplementedError</code>. The second version (<code>alt2</code>) calls concrete methods <code>Stack1.push</code> and <code>Stack1.pop</code>, which assumes a specific stack implementation (<code>Stack1</code>), and so <code>push_and_pop</code> would only be guaranteed to work on <code>Stack1</code> instances, but not any other <code>Stack</code> subclass. This makes <code>push_and_pop</code> no longer polymorphic: the correct type annotation for <code>s</code> would be <code>Stack1</code>, not <code>Stack</code>.</p>
<h3 id="application-running-timing-experiments-on-stack-implementation">Application: running timing experiments on stack implementation</h3>
<p>Because both <code>Stack1</code> and <code>Stack2</code> are different implementations of the same interface, we can use polymorphism to help us measure the performance of each. Below, we time the <code>push_and_pop</code> function, first with a <code>Stack1</code> object and second with a <code>Stack2</code> object.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1"></a><span class="cf">if</span> <span class="va">__name__</span> <span class="op">==</span> <span class="st">&#39;__main__&#39;</span>:</span>
<span id="cb9-2"><a href="#cb9-2"></a> <span class="co"># Import the main timing function.</span></span>
<span id="cb9-3"><a href="#cb9-3"></a> <span class="im">from</span> timeit <span class="im">import</span> timeit</span>
<span id="cb9-4"><a href="#cb9-4"></a></span>
<span id="cb9-5"><a href="#cb9-5"></a> <span class="co"># The stack sizes we want to try.</span></span>
<span id="cb9-6"><a href="#cb9-6"></a> STACK_SIZES <span class="op">=</span> [<span class="dv">1000</span>, <span class="dv">10000</span>, <span class="dv">100000</span>, <span class="dv">1000000</span>, <span class="dv">10000000</span>]</span>
<span id="cb9-7"><a href="#cb9-7"></a> <span class="cf">for</span> stack_size <span class="kw">in</span> STACK_SIZES:</span>
<span id="cb9-8"><a href="#cb9-8"></a> stack1 <span class="op">=</span> Stack1()</span>
<span id="cb9-9"><a href="#cb9-9"></a> stack2 <span class="op">=</span> Stack2()</span>
<span id="cb9-10"><a href="#cb9-10"></a></span>
<span id="cb9-11"><a href="#cb9-11"></a> <span class="co"># Bypass the Stack interface to create a stack of size &lt;stack_size&gt;.</span></span>
<span id="cb9-12"><a href="#cb9-12"></a> <span class="co"># This speeds up the experiment, but we know this violates</span></span>
<span id="cb9-13"><a href="#cb9-13"></a> <span class="co"># encapsulation!</span></span>
<span id="cb9-14"><a href="#cb9-14"></a> stack1._items <span class="op">=</span> <span class="bu">list</span>(<span class="bu">range</span>(<span class="dv">0</span>, stack_size))</span>
<span id="cb9-15"><a href="#cb9-15"></a> stack2._items <span class="op">=</span> <span class="bu">list</span>(<span class="bu">range</span>(<span class="dv">0</span>, stack_size))</span>
<span id="cb9-16"><a href="#cb9-16"></a></span>
<span id="cb9-17"><a href="#cb9-17"></a> <span class="co"># Call push_and_pop(stack1) 1000 times, and store the time taken.</span></span>
<span id="cb9-18"><a href="#cb9-18"></a> t1 <span class="op">=</span> timeit(<span class="st">&#39;push_and_pop(stack1, 10)&#39;</span>, number<span class="op">=</span><span class="dv">1000</span>, <span class="bu">globals</span><span class="op">=</span><span class="bu">globals</span>())</span>
<span id="cb9-19"><a href="#cb9-19"></a> t2 <span class="op">=</span> timeit(<span class="st">&#39;push_and_pop(stack2, 10)&#39;</span>, number<span class="op">=</span><span class="dv">1000</span>, <span class="bu">globals</span><span class="op">=</span><span class="bu">globals</span>())</span>
<span id="cb9-20"><a href="#cb9-20"></a></span>
<span id="cb9-21"><a href="#cb9-21"></a> <span class="bu">print</span>(<span class="ss">f&#39;Stack size </span><span class="sc">{</span>stack_size<span class="sc">:&gt;8}</span><span class="ss">; Stack1 time </span><span class="sc">{t1}</span><span class="ss">; Stack2 time </span><span class="sc">{t2}</span><span class="ss">&#39;</span>)</span></code></pre></div>
<p>If we have several implementations of an ADT, each inheriting from the same base class, then we can quickly run experiments on all of them but only need to remember a single interface. This creates a rule of thumb: when indicating the type of an object (e.g., through a type contract), choose the most generic type possible. Following this rule of thumb means that the client code is not constrained to one particular implementation (such as <code>Stack1</code>) and can readily change the underlying object so long as the new object type shares the same public interface.</p>
<p>Many software applications follow the same principle. For example, you may have used software with “plugins”:<label for="sn-2" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-2" class="margin-toggle"/><span class="sidenote">Like PyCharm!</span> each plugin implements a shared public interface, allowing the software to use it without knowing any of the details. For example, Adobe develops the powerful Photoshop application for image editing. David comes along and discovers a feature he really wants is missing. Rather than asking Adobe to implement the new feature, he can implement it himself as a plugin. Thus, Adobe has allowed independent developers to <em>extend the functionality</em> of their software after it has been released and without any employees of their own. Behold, the power of abstraction!</p>
</section>
<!--
otherwise, Python next searches for `push` in the superclass of the type of `s`.^[
And then the superclass of the superclass, etc., until it either finds a definition of `push` or it has exhausted all possibilities, in which case it raises an `AttributeError`.
]
This is why, if `Stack1` does not implement the `push` method, Python can still find `push` method if `Stack1.push` is called (the one inherited from `Stack` that raises a `NotImplementedError`).
However, if `Stack1` does implement the `push` method, then its implementation **overrides** the implementation in the parent class.
In other words, Python is following a "chain of responsibility" until it finds the person (class) responsible for the implementation.
-->
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>
+189
View File
@@ -0,0 +1,189 @@
<!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>9.9 The object Superclass</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="../tufte.css" />
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<div style="display:none">
\(
\newcommand{\NOT}{\neg}
\newcommand{\AND}{\wedge}
\newcommand{\OR}{\vee}
\newcommand{\XOR}{\oplus}
\newcommand{\IMP}{\Rightarrow}
\newcommand{\IFF}{\Leftrightarrow}
\newcommand{\TRUE}{\text{True}\xspace}
\newcommand{\FALSE}{\text{False}\xspace}
\newcommand{\IN}{\,{\in}\,}
\newcommand{\NOTIN}{\,{\notin}\,}
\newcommand{\TO}{\rightarrow}
\newcommand{\DIV}{\mid}
\newcommand{\NDIV}{\nmid}
\newcommand{\MOD}[1]{\pmod{#1}}
\newcommand{\MODS}[1]{\ (\text{mod}\ #1)}
\newcommand{\N}{\mathbb N}
\newcommand{\Z}{\mathbb Z}
\newcommand{\Q}{\mathbb Q}
\newcommand{\R}{\mathbb R}
\newcommand{\C}{\mathbb C}
\newcommand{\cA}{\mathcal A}
\newcommand{\cB}{\mathcal B}
\newcommand{\cC}{\mathcal C}
\newcommand{\cD}{\mathcal D}
\newcommand{\cE}{\mathcal E}
\newcommand{\cF}{\mathcal F}
\newcommand{\cG}{\mathcal G}
\newcommand{\cH}{\mathcal H}
\newcommand{\cI}{\mathcal I}
\newcommand{\cJ}{\mathcal J}
\newcommand{\cL}{\mathcal L}
\newcommand{\cK}{\mathcal K}
\newcommand{\cN}{\mathcal N}
\newcommand{\cO}{\mathcal O}
\newcommand{\cP}{\mathcal P}
\newcommand{\cQ}{\mathcal Q}
\newcommand{\cS}{\mathcal S}
\newcommand{\cT}{\mathcal T}
\newcommand{\cV}{\mathcal V}
\newcommand{\cW}{\mathcal W}
\newcommand{\cZ}{\mathcal Z}
\newcommand{\emp}{\emptyset}
\newcommand{\bs}{\backslash}
\newcommand{\floor}[1]{\left \lfloor #1 \right \rfloor}
\newcommand{\ceil}[1]{\left \lceil #1 \right \rceil}
\newcommand{\abs}[1]{\left | #1 \right |}
\newcommand{\xspace}{}
\newcommand{\proofheader}[1]{\underline{\textbf{#1}}}
\)
</div>
<header id="title-block-header">
<h1 class="title">9.9 The <code>object</code> Superclass</h1>
</header>
<section>
<p>In our very first chapter, we described every piece of data as an <em>object</em>, and have continued to use this term throughout this course. It turns out that “object” is not merely a theoretical concept, but made explicit in the Python language. Python has a special class called <code>object</code>, which is an <em>ancestor class</em><label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote">By “ancestor” we mean either a parent class, or a parent of a parent class, etc.</span> of every other class, both built-in classes like <code>int</code> or our custom data classes and the classes weve defined in this chapter. And this includes abstract classes like <code>Stack</code>!</p>
<p>By default, whenever we define a new class (including data classes), if we do not specify a superclass in parentheses, <code>object</code> is the <em>implicit</em> superclass, which is why we can write <code>class Stack:</code> instead of <code>class Stack(object):</code>.</p>
<p><img src="images/object_inheritance_diagram.png" /></p>
<h2 id="the-object-special-methods">The <code>object</code> special methods</h2>
<p>This <code>object</code> class defines several special methods as part of its shared public interface, including:<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> The Python convention is to name methods that have a special purpose with double underscores. These are sometimes called “dunder” methods (<strong>d</strong>ouble <strong>under</strong>score).</span></p>
<ul>
<li><code>__init__(self, ...)</code>, the initializer</li>
<li><code>__str__(self)</code>, which returns a <code>str</code> representation of the object.</li>
</ul>
<h3 id="method-inheritance">Method inheritance</h3>
<p>Unlike our <code>Stack</code> abstract class earlier this chapter, the <code>object</code> class is actually <em>not abstract</em>, and implements each of these methods. We can use this to illustrate a different form of inheritance, where the superclass is a concrete class. In this case, inheritance is used not just to define a shared public interface, but also to provide <em>default implementations</em> for each method in the interface.</p>
<p>For example, suppose we create a dummy class with a completely empty body:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">class</span> Donut:</span>
<span id="cb1-2"><a href="#cb1-2"></a> <span class="co">&quot;&quot;&quot;A donut, because why not?&quot;</span></span></code></pre></div>
<p>This class inherits the <code>object.__init__</code> method, which allows us to create new <code>Donut</code> instances.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1"></a><span class="op">&gt;&gt;&gt;</span> donut <span class="op">=</span> Donut()</span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">type</span>(donut)</span>
<span id="cb2-3"><a href="#cb2-3"></a><span class="op">&lt;</span><span class="kw">class</span> <span class="st">&#39;__main__.Donut&#39;</span><span class="op">&gt;</span></span></code></pre></div>
<p>Similarly, this class inherits the <code>object.__str__</code> method, which returns a string that states the class name and memory location of the object:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1"></a><span class="op">&gt;&gt;&gt;</span> d <span class="op">=</span> Donut()</span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="op">&gt;&gt;&gt;</span> d.<span class="fu">__str__</span>()</span>
<span id="cb3-3"><a href="#cb3-3"></a><span class="co">&#39;&lt;__main__.Donut object at 0x7fc299d7b588&gt;&#39;</span></span></code></pre></div>
<p>We can use the built-in <code>dir</code> function to see all of the special methods that <code>Donut</code> has inherited from <code>object</code>:<label for="sn-2" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-2" class="margin-toggle"/><span class="sidenote">Though this list includes few special attributes set directly by the Python interpreter, which are beyond the scope of this course.</span></p>
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">dir</span>(Donut)</span>
<span id="cb4-2"><a href="#cb4-2"></a>[<span class="st">&#39;__class__&#39;</span>, <span class="st">&#39;__delattr__&#39;</span>, <span class="st">&#39;__dict__&#39;</span>, <span class="st">&#39;__dir__&#39;</span>, <span class="st">&#39;__doc__&#39;</span>, <span class="st">&#39;__eq__&#39;</span>, <span class="st">&#39;__format__&#39;</span>, <span class="st">&#39;__ge__&#39;</span>, <span class="st">&#39;__getattribute__&#39;</span>, <span class="st">&#39;__gt__&#39;</span>, <span class="st">&#39;__hash__&#39;</span>, <span class="st">&#39;__init__&#39;</span>, <span class="st">&#39;__init_subclass__&#39;</span>, <span class="st">&#39;__le__&#39;</span>, <span class="st">&#39;__lt__&#39;</span>, <span class="st">&#39;__module__&#39;</span>, <span class="st">&#39;__ne__&#39;</span>, <span class="st">&#39;__new__&#39;</span>, <span class="st">&#39;__reduce__&#39;</span>, <span class="st">&#39;__reduce_ex__&#39;</span>, <span class="st">&#39;__repr__&#39;</span>, <span class="st">&#39;__setattr__&#39;</span>, <span class="st">&#39;__sizeof__&#39;</span>, <span class="st">&#39;__str__&#39;</span>, <span class="st">&#39;__subclasshook__&#39;</span>, <span class="st">&#39;__weakref__&#39;</span>]</span></code></pre></div>
<p>There is another reason these methods are special beyond simply being inherited from the <code>object</code> superclass: they are often called by other functions or parts of Python syntax. For example, we have already seen how the <code>__init__</code> method is called when a new object is initialized.</p>
<p>The <code>__str__</code> method is called when we attempt to convert an object to a string by calling <code>str</code> on it:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1"></a><span class="op">&gt;&gt;&gt;</span> d <span class="op">=</span> Donut()</span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="op">&gt;&gt;&gt;</span> d.<span class="fu">__str__</span>()</span>
<span id="cb5-3"><a href="#cb5-3"></a><span class="co">&#39;&lt;__main__.Donut object at 0x7fc299d7b588&gt;&#39;</span></span>
<span id="cb5-4"><a href="#cb5-4"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">str</span>(d)</span>
<span id="cb5-5"><a href="#cb5-5"></a><span class="co">&#39;&lt;__main__.Donut object at 0x7fc299d7b588&gt;&#39;</span></span></code></pre></div>
<p>Similarly, the built-in <code>print</code> function actually first converts its arguments into strings using their <code>__str__</code> methods, and then prints out the resulting text.</p>
<h3 id="method-overriding">Method overriding</h3>
<p>Now, even though the <code>object</code> superclass contains default implementations of <code>__init__</code> and <code>__str__</code>, in practice we often want to define our own custom implementations of these methods.</p>
<p>Every time weve defined our own <code>__init__</code> in a class, we have <strong>overridden</strong> the <code>object.__init__</code> method. Formally, we say that a class <code>C</code> <strong>overrides</strong> a method <code>m</code> when the method <code>m</code> is defined in the superclass of <code>C</code>, and is also given a concrete implementation in the body of <code>C</code>.<label for="sn-3" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-3" class="margin-toggle"/><span class="sidenote"> This definition applies whether the superclass of <code>C</code> has <code>m</code> as an abstract or concrete method. For example, we could say that <code>Stack1</code> overrides the <code>push</code> and <code>pop</code> method from its abstract superclass <code>Stack</code>.</span></p>
<p>Similarly, when we defined a custom exception class in <a href="05-section.html">Section 9.5</a>,</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">class</span> EmptyStackError(<span class="pp">Exception</span>):</span>
<span id="cb6-2"><a href="#cb6-2"></a> <span class="co">&quot;&quot;&quot;Exception raised when calling pop on an empty stack.&quot;&quot;&quot;</span></span>
<span id="cb6-3"><a href="#cb6-3"></a></span>
<span id="cb6-4"><a href="#cb6-4"></a> <span class="kw">def</span> <span class="fu">__str__</span>(<span class="va">self</span>) <span class="op">-&gt;</span> <span class="bu">str</span>:</span>
<span id="cb6-5"><a href="#cb6-5"></a> <span class="co">&quot;&quot;&quot;Return a string representation of this error.&quot;&quot;&quot;</span></span>
<span id="cb6-6"><a href="#cb6-6"></a> <span class="cf">return</span> <span class="st">&#39;pop may not be called on an empty stack&#39;</span></span></code></pre></div>
<p>this class <em>overrode</em> the <code>__str__</code> method to use its own string representation, which is displayed when this exception is raised.</p>
</section>
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>