Files
CSC110/05-memory-model/02-mutable-data-types.html
T
Hykilpikonna 6fffdf686a deploy
2021-12-07 22:28:01 -05:00

209 lines
18 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>5.2 Operations on Mutable Data Types</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">5.2 Operations on Mutable Data Types</h1>
</header>
<section>
<p>In the last section, we introduced the concept of mutable data types, and saw how we could mutate Python lists with the <code>list.append</code> method. In this section, well survey some of the other ways of mutating lists and other mutable Python data types. For a full reference of Pythons mutating methods on these data types, please see <a href="../A-python-builtins/02-types.html">Appendix A.2 Python Built-In Data Types Reference</a>.</p>
<h2 id="list.append-list.insert-and-list.extend"><code>list.append</code>, <code>list.insert</code>, and <code>list.extend</code></h2>
<p>In addition to <code>list.append</code>, there are two other ways of adding new items to a Python list. The first is <code>list.insert</code>, which takes a list, an <em>index</em> and an object, and inserts the object at the given index into the list at the given index.</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="op">&gt;&gt;&gt;</span> strings <span class="op">=</span> [<span class="st">&#39;a&#39;</span>, <span class="st">&#39;b&#39;</span>, <span class="st">&#39;c&#39;</span>, <span class="st">&#39;d&#39;</span>]</span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">list</span>.insert(strings, <span class="dv">2</span>, <span class="st">&#39;hello&#39;</span>) <span class="co"># Insert &#39;hello&#39; into strings at index 2</span></span>
<span id="cb1-3"><a href="#cb1-3"></a><span class="op">&gt;&gt;&gt;</span> strings</span>
<span id="cb1-4"><a href="#cb1-4"></a>[<span class="st">&#39;a&#39;</span>, <span class="st">&#39;b&#39;</span>, <span class="st">&#39;hello&#39;</span>, <span class="st">&#39;c&#39;</span>, <span class="st">&#39;d&#39;</span>]</span></code></pre></div>
<p>The second is <code>list.extend</code>, which takes two lists and adds all items from the second list at the end of the first list, as if <code>append</code> were called once per element of the second 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="op">&gt;&gt;&gt;</span> strings <span class="op">=</span> [<span class="st">&#39;a&#39;</span>, <span class="st">&#39;b&#39;</span>, <span class="st">&#39;c&#39;</span>, <span class="st">&#39;d&#39;</span>]</span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">list</span>.extend(strings, [<span class="st">&#39;CSC110&#39;</span>, <span class="st">&#39;CSC111&#39;</span>])</span>
<span id="cb2-3"><a href="#cb2-3"></a><span class="op">&gt;&gt;&gt;</span> strings</span>
<span id="cb2-4"><a href="#cb2-4"></a>[<span class="st">&#39;a&#39;</span>, <span class="st">&#39;b&#39;</span>, <span class="st">&#39;c&#39;</span>, <span class="st">&#39;d&#39;</span>, <span class="st">&#39;CSC110&#39;</span>, <span class="st">&#39;CSC111&#39;</span>]</span></code></pre></div>
<h2 id="assigning-to-a-specific-list-index">Assigning to a specific list index</h2>
<p>There is one more way to put a value into a list: by overwriting the element stored at a specific index. Given a list <code>lst</code>, weve seen that we can access specific elements using indexing syntax <code>lst[0]</code>, <code>lst[1]</code>, <code>lst[2]</code>, etc. We can also use this kind of expression as the <em>left side</em> of an assignment statement to mutate the list by modifying a specific index.</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> strings <span class="op">=</span> [<span class="st">&#39;a&#39;</span>, <span class="st">&#39;b&#39;</span>, <span class="st">&#39;c&#39;</span>, <span class="st">&#39;d&#39;</span>]</span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="op">&gt;&gt;&gt;</span> strings[<span class="dv">2</span>] <span class="op">=</span> <span class="st">&#39;Hello&#39;</span></span>
<span id="cb3-3"><a href="#cb3-3"></a><span class="op">&gt;&gt;&gt;</span> strings</span>
<span id="cb3-4"><a href="#cb3-4"></a>[<span class="st">&#39;a&#39;</span>, <span class="st">&#39;b&#39;</span>, <span class="st">&#39;Hello&#39;</span>, <span class="st">&#39;d&#39;</span>]</span></code></pre></div>
<p>Note that unlike <code>list.insert</code>, assigning to an index removes the element previously stored at that index from the list!</p>
<h2 id="mutating-sets">Mutating sets</h2>
<p>Python <code>set</code>s are mutable. Because they are unordered, they are simpler than <code>list</code>s, and offer just two main mutating methods: <code>set.add</code> and <code>set.remove</code>, which (as you can probably guess) add and remove an element from a set, respectively.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> <code>list</code> also provides a few mutating methods that remove elements, though we did not cover them in this section.</span> Well illustrate <code>set.add</code> by showing how to re-implement our <code>squares</code> function from the previous section with <code>set</code> instead of <code>list</code>:</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">def</span> squares(numbers: <span class="bu">set</span>[<span class="bu">int</span>]) <span class="op">-&gt;</span> <span class="bu">set</span>[<span class="bu">int</span>]:</span>
<span id="cb4-2"><a href="#cb4-2"></a> <span class="co">&quot;&quot;&quot;Return a set containing the squares of all the given numbers.</span></span>
<span id="cb4-3"><a href="#cb4-3"></a></span>
<span id="cb4-4"><a href="#cb4-4"></a><span class="co"> ...</span></span>
<span id="cb4-5"><a href="#cb4-5"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb4-6"><a href="#cb4-6"></a> squares_so_far <span class="op">=</span> <span class="bu">set</span>()</span>
<span id="cb4-7"><a href="#cb4-7"></a> <span class="cf">for</span> n <span class="kw">in</span> numbers:</span>
<span id="cb4-8"><a href="#cb4-8"></a> <span class="bu">set</span>.add(squares_so_far, n <span class="op">*</span> n)</span>
<span id="cb4-9"><a href="#cb4-9"></a></span>
<span id="cb4-10"><a href="#cb4-10"></a> <span class="cf">return</span> squares_so_far</span></code></pre></div>
<p>Note that <code>set.add</code> will only add the element if the set does not already contain it, as sets cannot contain duplicates. In addition, sets are unordered whereas <code>list.append</code> will add the element to the end of the sequence.</p>
<h2 id="mutating-dictionaries">Mutating dictionaries</h2>
<p>The most common ways for dictionaries to be mutated is by adding a new key-value pair, or changing the associated value for a key-value pair in the dictionary. This does not use a function call, but rather the same syntax as assigning by list index.</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> items <span class="op">=</span> {<span class="st">&#39;a&#39;</span>: <span class="dv">1</span>, <span class="st">&#39;b&#39;</span>: <span class="dv">2</span>}</span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="op">&gt;&gt;&gt;</span> items[<span class="st">&#39;c&#39;</span>] <span class="op">=</span> <span class="dv">3</span></span>
<span id="cb5-3"><a href="#cb5-3"></a><span class="op">&gt;&gt;&gt;</span> items</span>
<span id="cb5-4"><a href="#cb5-4"></a>{<span class="st">&#39;a&#39;</span>: <span class="dv">1</span>, <span class="st">&#39;b&#39;</span>: <span class="dv">2</span>, <span class="st">&#39;c&#39;</span>: <span class="dv">3</span>}</span></code></pre></div>
<p>The second assignment statement adds a new key-value pair to <code>items</code>, with the key being <code>'c'</code> and the items being <code>3</code>. In this case, the left-hand side of the assignment is not a variable but instead an expression representing a component of <code>items</code>, in this case the key <code>'c'</code> in the dictionary. When this assignment statement is evaluated, the right-hand side value <code>3</code> is stored in the dictionary items as the corresponding value for <code>'c'</code>.</p>
<p>Assignment statements in this form can also be used to mutate the dictionary by taking an existing key-value pair and replacing the value with a different one. Heres an example of that:</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> items[<span class="st">&#39;a&#39;</span>] <span class="op">=</span> <span class="dv">100</span></span>
<span id="cb6-2"><a href="#cb6-2"></a><span class="op">&gt;&gt;&gt;</span> items</span>
<span id="cb6-3"><a href="#cb6-3"></a>{<span class="st">&#39;a&#39;</span>: <span class="dv">100</span>, <span class="st">&#39;b&#39;</span>: <span class="dv">2</span>, <span class="st">&#39;c&#39;</span>: <span class="dv">3</span>}</span></code></pre></div>
<h2 id="mutating-data-classes">Mutating data classes</h2>
<p>Python data classes are mutable by default.<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> Technically there is a way to create immutable data classes, but this is beyond the scope of this course.</span> To illustrate this, well return to our <code>Person</code> class:</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="at">@dataclass</span></span>
<span id="cb7-2"><a href="#cb7-2"></a><span class="kw">class</span> Person:</span>
<span id="cb7-3"><a href="#cb7-3"></a> <span class="co">&quot;&quot;&quot;A person with some basic demographic information.</span></span>
<span id="cb7-4"><a href="#cb7-4"></a></span>
<span id="cb7-5"><a href="#cb7-5"></a><span class="co"> Representation Invariants:</span></span>
<span id="cb7-6"><a href="#cb7-6"></a><span class="co"> - self.age &gt;= 0</span></span>
<span id="cb7-7"><a href="#cb7-7"></a></span>
<span id="cb7-8"><a href="#cb7-8"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb7-9"><a href="#cb7-9"></a> given_name: <span class="bu">str</span></span>
<span id="cb7-10"><a href="#cb7-10"></a> family_name: <span class="bu">str</span></span>
<span id="cb7-11"><a href="#cb7-11"></a> age: <span class="bu">int</span></span>
<span id="cb7-12"><a href="#cb7-12"></a> address: <span class="bu">str</span></span></code></pre></div>
<p>We mutate instances of data classes by modifying their attributes. We do this by assigning to their attributes directly, using <em>dot notation</em> on the left side of an assignment statement.</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="op">&gt;&gt;&gt;</span> p <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="cb8-2"><a href="#cb8-2"></a><span class="op">&gt;&gt;&gt;</span> p.age <span class="op">=</span> <span class="dv">200</span></span>
<span id="cb8-3"><a href="#cb8-3"></a><span class="op">&gt;&gt;&gt;</span> p</span>
<span id="cb8-4"><a href="#cb8-4"></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">200</span>, address<span class="op">=</span><span class="st">&#39;40 St. George Street&#39;</span>)</span></code></pre></div>
<p>One note of caution here: as you start mutating data class instances, you must always remember to respect the representation invariants associated with that data class. For example, setting <code>p.age = -1</code> would violate the <code>Person</code> representation invariant. To protect against this, <code>python_ta</code> checks representation invariants whenever you assign to attributes of data classes, as long as the <code>python_ta.contracts.check_all_contracts</code> function has been called in your file.</p>
</section>
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>