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
@@ -0,0 +1,222 @@
<!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.1 Variable Reassignment and Object Mutation</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">5.1 Variable Reassignment and Object Mutation</h1>
</header>
<section>
<p>So far, we have largely treated objects and variables in Python as being constant over time: once an object is created or a variable is initialized, its value has not changed during the program. This property has made it easier to reason about our code: once we set the value of the variable once, we can easily look up its value at any later point in the program.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote">Indeed, this is a fact that we take for granted in mathematics: if we say “let <span class="math inline">\(x\)</span> = 10” in a calculation or proof, we expect <span class="math inline">\(x\)</span> to keep that same value from start to finish!</span></p>
<p>However, in programs it is sometimes useful to have objects and variables change value over time. We saw one example of this last week when we studied for loops, in which both the loop variable and accumulator take on multiple values over the course of running the loop. In this section, well introduce two related but distinct actions in a program: <em>variable reassignment</em> and <em>object mutation</em>.</p>
<h2 id="variable-reassignment">Variable reassignment</h2>
<p>Recall that a statement of the form <code>___ = ___</code> is called an <em>assignment statement</em>, which takes a variable name on the left-hand side and an expression on the right-hand side, and assigns the value of the expression to the variable.</p>
<p>A <strong>variable reassignment</strong> is a Python action that assigns a value to a variable that already refers to a value. The most common kind of variable reassignment is with an assignment statement:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1"></a>x <span class="op">=</span> <span class="dv">1</span></span>
<span id="cb1-2"><a href="#cb1-2"></a>x <span class="op">=</span> <span class="dv">5</span> <span class="co"># The variable x is reassigned on this line.</span></span></code></pre></div>
<p>A variable reassignment <em>changes which object a variable refers to</em>. In the above example, variable <code>x</code> changes from referring to an object representing the number <code>1</code> to an object representing <code>5</code>.</p>
<p>The loops that we studied last week all used variable reassignment to update the <em>accumulator variable</em> inside the loop.</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> my_sum(nums: <span class="bu">list</span>[<span class="bu">int</span>]) <span class="op">-&gt;</span> <span class="bu">int</span>:</span>
<span id="cb2-2"><a href="#cb2-2"></a> sum_so_far <span class="op">=</span> <span class="dv">0</span></span>
<span id="cb2-3"><a href="#cb2-3"></a> <span class="cf">for</span> num <span class="kw">in</span> nums:</span>
<span id="cb2-4"><a href="#cb2-4"></a> sum_so_far <span class="op">=</span> sum_so_far <span class="op">+</span> num</span>
<span id="cb2-5"><a href="#cb2-5"></a> <span class="cf">return</span> sum_so_far</span></code></pre></div>
<p>At each iteration, the statement <code>sum_so_far = sum_so_far + num</code> did two things:</p>
<ol type="1">
<li>Evaluate the right-hand side (<code>sum_so_far + num</code>) using the <em>current</em> value of <code>sum_so_far</code>, obtaining a new object.</li>
<li>Reassign <code>sum_so_far</code> to refer to that new object.</li>
</ol>
<p>This is the Python mechanism that causes <code>sum_so_far</code> to refer to the total sum at the end of the loop, which of course was the whole point of the loop! Indeed, updating loop accumulators is one of the most natural uses of variable reassignment.</p>
<p>This loop actually illustrates another common form of variable reassignment: reassigning the <em>loop variable</em> to a different value at each for loop iteration. For example, when we call <code>my_sum([10, 20, 30])</code>, the loop variable <code>num</code> gets assigned to the value <code>10</code>, then the value <code>20</code>, and then the value <code>30</code>.</p>
<h2 id="reassignment-is-independent-of-prior-uses">Reassignment is independent of prior uses</h2>
<p>Consider the following Python code snippet:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1"></a>x <span class="op">=</span> <span class="dv">1</span></span>
<span id="cb3-2"><a href="#cb3-2"></a>y <span class="op">=</span> x <span class="op">+</span> <span class="dv">2</span></span>
<span id="cb3-3"><a href="#cb3-3"></a>x <span class="op">=</span> <span class="dv">7</span></span></code></pre></div>
<p>Here, the variable <code>x</code> is reassigned to <code>7</code> on line 3. But what happens to <code>y</code>? Does it now also get “reassigned” to <code>9</code> (which is <code>7 + 2</code>), or does it stay at its original value <code>3</code>?</p>
<p>We can express Pythons behaviour here with one simple rule: <strong>variable reassignment only changes the immediate variable being reassigned, and does not change any other variables or objects, even ones that were defined using the variable being reassigned</strong>. And so in the above example, <code>y</code> still refers to the value <code>3</code>, even after <code>x</code> is reassigned to <code>7</code>.</p>
<p>This rule might seem a bit strange at first, but is actually the simplest way that Python could execute variable reassignment: it allows programmers to reason about these assignment statements in a top-down order, without worrying that future assignment statements could affect previous ones. If were tracing through our code carefully and read <code>y = x + 2</code>, I can safely predict the value of <code>y</code> based on the current value of <code>x</code>, without worrying about how <code>x</code> might be reassigned later in the program.</p>
<p>That said, there is one complication with this line of reasoning that comes up with the next form of “value change”, object mutation.</p>
<h2 id="object-mutation">Object mutation</h2>
<p>In <a href="../04-complex-data/07-nested-loops.html">4.7 Nested Loops</a>, we saw how <code>product</code> could help us calculate the Cartesian product by accumulating all possible pairs of elements in a list. Consider a function that also accumulates values in a list:</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(nums: <span class="bu">list</span>[<span class="bu">int</span>]) <span class="op">-&gt;</span> <span class="bu">list</span>[<span class="bu">int</span>]:</span>
<span id="cb4-2"><a href="#cb4-2"></a> <span class="co">&quot;&quot;&quot;Return a list of the squares of the given numbers.&quot;&quot;&quot;</span></span>
<span id="cb4-3"><a href="#cb4-3"></a> squares_so_far <span class="op">=</span> []</span>
<span id="cb4-4"><a href="#cb4-4"></a></span>
<span id="cb4-5"><a href="#cb4-5"></a> <span class="cf">for</span> num <span class="kw">in</span> nums:</span>
<span id="cb4-6"><a href="#cb4-6"></a> squares_so_far <span class="op">=</span> squares_so_far <span class="op">+</span> [num <span class="op">*</span> num]</span>
<span id="cb4-7"><a href="#cb4-7"></a> <span class="cf">return</span> squares_so_far</span></code></pre></div>
<p>Both the <code>squares</code> and <code>product</code> functions work properly, but are rather inefficient.<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> Well study what we mean by “inefficient” more precisely later in this course.</span> In <code>squares</code>, each loop iteration creates a new <code>list</code> object (a copy of the current list plus one more element at the end) and reassigns <code>squares_so_far</code> to it. It would be easier (and faster) if we could somehow reuse the same object but modify it by adding elements to it; the same applies to other collection data types like <code>set</code> and <code>dict</code> as well.</p>
<p>In Python, <strong>object mutation</strong> (often shortened to just <strong>mutation</strong>) is an operation that changes the value of an existing object. For example, Pythons <code>list</code> data type contains several methods that <strong>mutate</strong> the given <code>list</code> object rather than create a new one. Heres how we could improve our <code>squares</code> implementation by using <code>list.append</code>,<label for="sn-2" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-2" class="margin-toggle"/><span class="sidenote">Check out <a href="../A-python-builtins/02-types.html">Appendix A.2 Python Built-In Data Types Reference</a> for a list of methods, including mutating ones, for lists, sets, dictionaries, and more.</span> a method that adds a single value to the end of a list:</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> squares(nums: <span class="bu">list</span>[<span class="bu">int</span>]) <span class="op">-&gt;</span> <span class="bu">list</span>[<span class="bu">int</span>]:</span>
<span id="cb5-2"><a href="#cb5-2"></a> <span class="co">&quot;&quot;&quot;Return a list of the squares of the given numbers.&quot;&quot;&quot;</span></span>
<span id="cb5-3"><a href="#cb5-3"></a> squares_so_far <span class="op">=</span> []</span>
<span id="cb5-4"><a href="#cb5-4"></a></span>
<span id="cb5-5"><a href="#cb5-5"></a> <span class="cf">for</span> num <span class="kw">in</span> nums:</span>
<span id="cb5-6"><a href="#cb5-6"></a> <span class="bu">list</span>.append(squares_so_far, num <span class="op">*</span> num)</span>
<span id="cb5-7"><a href="#cb5-7"></a> <span class="cf">return</span> squares_so_far</span></code></pre></div>
<p>Now, <code>squares</code> runs by assigning <code>squares_so_far</code> to a single list object before the loop, and then mutating that list object at each loop iteration. The outward behaviour is the same, but this code is more efficient because a bunch of new list objects are not created. To use the terminology from before, <code>squares_so_far</code> is <em>not</em> reassigned; instead, the object that it refers to gets mutated.</p>
<p>One final note: you might notice that the loop body calls <code>list.append</code> without an assignment statement. This is because <code>list.append</code> returns <code>None</code>, a special Python value that indicates “no value”. Just as we explored previously with the <code>print</code> function, <code>list.append</code> has a <em>side effect</em> that it mutates its <code>list</code> argument, but does not return anything.</p>
<h2 id="mutable-and-immutable-data-types">Mutable and immutable data types</h2>
<p>We say that a Python data type is <strong>mutable</strong> when it supports at least one kind of mutating operation, and <strong>immutable</strong> if it does not. Sets, lists, and dictionaries are all mutable data types, as are the data classes we studied in the previous chapter. All of the non-collection types weve studied—<code>int</code>, <code>float</code>, <code>bool</code>, and <code>str</code>—are immutable.</p>
<p>Instances of an immutable data type cannot change their value during the execution of a Python program. So for example, if we have an object representing the number <code>3</code> in Python, that objects value will <em>always</em> be 3. But remember, a variable that refers to this object might be reassigned to a different object later. This is why is is important that we differentiate between variables and objects!</p>
<h2 id="list-vs.-tuple-and-whats-in-a-set"><code>list</code> vs. <code>tuple</code>, and whats in a <code>set</code></h2>
<p>All the way back in <a href="../01-working-with-data/03-python-data-types.html">1.3 Representing Data in Python</a>, we introduced two Python data types that could be used to represent ordered sequences, <code>list</code> and <code>tuple</code>. Weve been using them fairly interchangeably for the past few chapters, but are now ready to discuss the difference between them. <em>In Python, a <code>list</code> is mutable, but a <code>tuple</code> is immutable.</em> For example, we can modify a <code>list</code> value by adding an element with <code>list.append</code>, but there is no equivalent <code>tuple.append</code>, nor any other mutating method on tuples.</p>
<p>So why bother with tuples at all? Because in Python, <code>set</code>s may only contain <em>immutable</em> objects, and <code>dict</code>s may only contain <em>immutable keys</em>. So for example, we cannot have a <code>set</code> of <code>set</code>s or <code>set</code> of <code>list</code>s in Python, but we can have a <code>list</code> of <code>lists</code>, which is why studied nested lists in the last chapter.</p>
<p>Of course, from a theoretical standpoint a set can have elements that are other sets! So this restriction is a quirk of Pythons built-in data types that we just have to live with when using this programming language.<label for="sn-3" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-3" class="margin-toggle"/><span class="sidenote"> In case youre curious, there is another Python data type, <code>frozenset</code>, which is an immutable version of <code>set</code>. We just wont be using it in this course.</span></p>
<h2 id="reasoning-about-code-with-changing-values">Reasoning about code with changing values</h2>
<p>Variable reassignment and object mutation are distinct concepts. Reassignment will change which object a variable refers to, sometimes creating a brand new object (e.g., when we used a list accumulator in <code>squares</code>). Object mutation changes the object itself, independent of what variable(s) refer t othat object.</p>
<p>Yet we have presented them here in the same section because they share a fundamental similarity: they both result in variables changing values over the course of a program. To illustrate this point, consider the following hypothetical function definition:</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> my_function(...) <span class="op">-&gt;</span> ...:</span>
<span id="cb6-2"><a href="#cb6-2"></a> x <span class="op">=</span> <span class="dv">10</span></span>
<span id="cb6-3"><a href="#cb6-3"></a> y <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb6-4"><a href="#cb6-4"></a></span>
<span id="cb6-5"><a href="#cb6-5"></a> ... <span class="co"># Many lines of code</span></span>
<span id="cb6-6"><a href="#cb6-6"></a> ... <span class="co"># Many lines of code</span></span>
<span id="cb6-7"><a href="#cb6-7"></a> ... <span class="co"># Many lines of code</span></span>
<span id="cb6-8"><a href="#cb6-8"></a> ... <span class="co"># Many lines of code</span></span>
<span id="cb6-9"><a href="#cb6-9"></a> ... <span class="co"># Many lines of code</span></span>
<span id="cb6-10"><a href="#cb6-10"></a> ... <span class="co"># Many lines of code</span></span>
<span id="cb6-11"><a href="#cb6-11"></a></span>
<span id="cb6-12"><a href="#cb6-12"></a> <span class="cf">return</span> x <span class="op">*</span> <span class="bu">len</span>(y) <span class="op">+</span> ...</span></code></pre></div>
<p>Weve included for effect a large omitted “middle” section of the function body, showing only the initialization of two local variables at the start of the function and a final return statement at the end of the function.</p>
<p>If the omitted code does <em>not</em> contain any variable reassignment or object mutation, then we can be sure that in the return statement, <code>x</code> still refers to <code>10</code> and <code>y</code> still refers to <code>[1, 2, 3]</code>, regardless of what other computations occurred in the omitted lines! In other words, without reassignment and mutation, these assignment statements are universal across the function body: “for all points in the body of <code>my_function</code>, <code>x == 10</code> and <code>y == [1, 2, 3]</code>.” Such universal statements make our code easier to reason about, as we can determine the values of these variables from just the assignment statement that creates them.</p>
<p>Variable reassignment and object mutation weaken this property. For example, if we reassign <code>x</code> or <code>y</code> (e.g., <code>x = 100</code>) in the middle of the function body, the return statement obtains a different value for <code>x</code> than <code>10</code>. Similarly, if we mutate <code>y</code> (e.g., <code>list.append(y, 100)</code>), the reutn statement obtains a different value for <code>y</code> than <code>[1, 2, 3]</code>. <em>Introducing reassignment and mutation makes our code harder to reason about, as we need to track all changes to variable values line by line.</em></p>
<p>Because of this, you should avoid using variable reassignment and object mutation when possible, and use them in structured code patterns like we saw with the loop accumulator pattern. Over the course of this chapter, well study other situations where reassignment and mutation are useful, and introduce a new memory model to help us keep track of changing variable values in our code.</p>
</section>
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>
+208
View File
@@ -0,0 +1,208 @@
<!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>
@@ -0,0 +1,323 @@
<!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.3 The Python Memory Model: Introduction</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.3 The Python Memory Model: Introduction</h1>
</header>
<section>
<p>In [1.4 Storing Data in Variables], we introduced the <em>value-based memory model</em> to help keep track of variables and their values:</p>
<div class="memory-model-values">
<table>
<thead>
<tr class="header">
<th>Variable</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>distance1</code></td>
<td><code>1.118033988749895</code></td>
</tr>
<tr class="even">
<td><code>distance2</code></td>
<td><code>216.14809737770074</code></td>
</tr>
</tbody>
</table>
</div>
<p>From this table we can surmise that there are two variables (<code>distance1</code> and <code>distance2</code>), each associated with a <code>float</code> value. However, now that we know about reassignment and mutation, a more complex memory model is needed: the <em>object-based memory model</em>, which well simply call the <em>Python memory model</em>, as this is the “standard” representation Python stores data.</p>
<h2 id="representing-objects">Representing objects</h2>
<p>Recall that every piece of data is stored in a Python program in an <strong>object</strong>. But how are the objects themselves stored? Every computer program (whether written in Python or some other language) stores data in computer memory, which you can think of as a very long list of storage locations. Each storage location is labelled with a unique memory address. In Python, every object we use is stored in computer memory at a particular location, and it is the responsibility of the Python interpreter to keep track of which objects are stored at which memory locations.</p>
<p>As programmers, we cannot control which memory addresses are used to store objects, but we can access a representation of this memory address using the built-in <code>id</code> function:</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> <span class="bu">id</span>(<span class="dv">3</span>)</span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="dv">1635361280</span></span>
<span id="cb1-3"><a href="#cb1-3"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(<span class="st">&#39;words&#39;</span>)</span>
<span id="cb1-4"><a href="#cb1-4"></a><span class="dv">4297547872</span></span></code></pre></div>
<p>Formally, we define the <strong>id</strong> of a Python object as a unique <code>int</code> identifier to refer to this object.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote">The details of how Python translates memory addresses into the integers are not important to us.</span> Every object in Python has three important properties—<em>id</em>, <em>value</em>, and <em>type</em>—but of these three, only its <em>id</em> is guaranteed to be unique.</p>
<p>In Python, a variable is not an object and so does not actually store data; variables store an id that <em>refers</em> to an object that stores data. We also say that variables <em>contain</em> the id of an object. This is the case whether the data is something very simple like an <code>int</code> or more complex like a <code>str</code>. To make this distinction between variable and objects clear, we separate them in different parts of the Python memory model.</p>
<p>As an example, consider this code:</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> x <span class="op">=</span> <span class="dv">3</span></span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="op">&gt;&gt;&gt;</span> word <span class="op">=</span> <span class="st">&#39;bonjour&#39;</span></span></code></pre></div>
<p>In our value-based memory model we would have represented these variables in a table:</p>
<div class="memory-model-values">
<table>
<caption><code>__main__</code></caption>
<thead>
<tr class="header">
<th>Variable</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>x</code></td>
<td><code>3</code></td>
</tr>
<tr class="even">
<td><code>word</code></td>
<td><code>'bonjour'</code></td>
</tr>
</tbody>
</table>
</div>
<p>With the full object-based Python memory model, we instead draw one table-like structure on the left showing the mapping between variables and object ids, and then the objects on the right. Each object is represented as a box, with its id in the upper-left corner, type in the upper-right corner, and value in the middle. The actual object id reported by the <code>id</code> function has many digits, and its true value isnt important; we just need to know that each object has a unique identifier. So for our drawings we make up short identifiers such as <code>id92</code>.</p>
<p><img src="images/variables.png" alt="There are two variables, x and word. Each is a container holding just one thing: the id of an object. x contains the id of an int object, and that int object is a container holding the value 3. word contains the id of a str object, and that str object is a container holding the value bonjour." /><br />
</p>
<p>So there is no <code>3</code> inside the box for variable <code>x</code>. Instead, there is the <em>id</em> of an object whose value is 3. The same holds for variable <code>word</code>; it references an object whose value is <code>'bonjour'</code>.</p>
<p>Notice that we didnt draw any arrows. Programmers often draw an arrow when they want to show that one thing references another. This is great once you are very confident with a language and how references work. But in the early stages, you are much more likely to make correct predictions if you write down references (you can just make up id values) rather than arrows.</p>
<h3 id="assignment-statements-and-evaluating-expressions">Assignment statements and evaluating expressions</h3>
<p>Youve written code much more complex that whats above, but now that we have the full Python memory model, we can understand a few more details for fundamental Python operations. These details are foundational for writing and debugging the more complex code you will work on this year. So lets pause for a moment and be explicit about two things.</p>
<p><em>Evaluating an expression</em>. First, we said earlier that evaluating any Python expression produces a value. We now know that it is more precise to say that evaluating any Python expression produces <em>an id of an object representing the value of the expression</em>. Exactly what this object is depends on the kind of expression evaluated:</p>
<ul>
<li>If the expression is a literal, such as <code>176.4</code> or <code>'hello'</code>, Python creates an object of the appropriate type to hold the value.</li>
<li>If the expression is a variable, Python looks up the variable. If the variable doesnt exist, a <code>NameError</code> is raised. If it does exist, the expression produces the id stored in that variable.</li>
<li>If the expression is a binary operation, such as <code>+</code> or <code>%</code>, first Python evaluates the expressions two operands and applies the operator to the resulting values, creating a new object of the appropriate type to hold the resulting value. The expression produces the id of the new object.</li>
<li>There are additional rules for other types of expression, but these will do for now.</li>
</ul>
<p><em>Assignment statements.</em> Second, we said earlier that an assignment statement is executed by first evaluating the right-hand side expression, and then storing it in the left-hand side variable. Here is a more precise version of what happens:</p>
<ol type="1">
<li>Evaluate the expression on the right-hand side, yielding the id of an object.</li>
<li>If the variable on the left-hand side doesnt already exist, create it.</li>
<li>Store the id from the expression on the right-hand side in the variable on the left-hand side.</li>
</ol>
<h2 id="representing-compound-data">Representing compound data</h2>
<p>So far, the only objects weve looked at in the Python memory model are instances of primitive data types. What about compound data types like collections and data classes? Now that we have our object-based memory model, we are in a position to truly understand how Python represents these data types. <em>An instance of a compound data type does not store values directly; instead, it stores the ids of other objects.</em></p>
<p>Lets see what this means for some familiar collection data types.</p>
<ul>
<li><p><em>Lists</em>. Here is an object-based memory model diagram showing the state of memory after executing <code>lst = [1, 2, 3]</code>.</p>
<p><img src="images/list.png" style="width:100.0%" alt="List memory model diagram" /><br />
</p>
<p>Notice that there are four separate objects in this diagram: one for the each of the <code>int</code>s <code>1</code>, <code>2</code>, and <code>3</code>, and then one for the <code>list</code> itself.<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> This illustrates one of the trade-offs with the Python memory model. It is more accurate than our value-based memory model, but that accuracy comes at the cost of having more parts and therefore more time-consuming to create. </span></p></li>
<li><p><em>Sets</em>. Here is an object-based memory model diagram showing how Python represents the set <code>my_set = {1, 2, 3}</code>.</p>
<p><img src="images/set.png" style="width:100.0%" alt="Set memory model diagram" /><br />
</p></li>
<li><p><em>Dictionaries</em>. Here is an object-based memory model diagram showing the dictionary <code>my_dict = {'a': 1, 'b': 2}</code>. There are five objects in total!</p>
<p><img src="images/dict.png" style="width:100.0%" alt="Dictionary memory model diagram" /><br />
</p></li>
<li><p><em>Data classes</em>. All Python data classes are compound data types, and instances also store the ids of other objects. Unlike the collection data types we looked at above, these ids are not bundled in a collection, but instead each associated with a particular instance attribute. Here is how we represent our favourite <code>Person</code> object.</p>
<p><img src="images/person.png" style="width:100.0%" alt="Person data class memory model diagram" /><br />
</p></li>
</ul>
<p>You may have noticed one difference between how we drew the object boxes of the primitive vs. compound data types above. We will use the convention of drawing a <em>double box</em> around objects that are immutable. Think of it as signifying that you cant get in there and change anything.</p>
<h2 id="visualizing-variable-reassignment-and-object-mutation">Visualizing variable reassignment and object mutation</h2>
<p>Our last topic in this section will be to use our object-based memory model to visualize variable reassignment and object mutation in Python.</p>
<p>Consider this simple case of variable reassignment:</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> [<span class="dv">1</span>, <span class="dv">2</span>]</span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="op">&gt;&gt;&gt;</span> s <span class="op">=</span> [<span class="st">&#39;a&#39;</span>, <span class="st">&#39;b&#39;</span>]</span></code></pre></div>
<p>Here is what our memory model looks like after the first and second lines execute:</p>
<div class="fullwidth image-table">
<table>
<thead>
<tr class="header">
<th style="text-align: left;">Before reassignment</th>
<th style="text-align: left;">After reassignment</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;"><img src="images/reassignment1.png" alt="Before reassignment" /></td>
<td style="text-align: left;"><img src="images/reassignment2.png" alt="After reassignment" /></td>
</tr>
</tbody>
</table>
</div>
<p>Using this diagram, we can see what happens when we execute the reassignment <code>s = ['a', 'b']</code>: a new <code>list</code> object <code>['a', 'b']</code> is created, and variable <code>s</code> is assigned the id of the new object. The original list object <code>[1, 2]</code> is not mutated. Variable reassignment <em>does not mutate any objects</em>; instead, it changes what a variable refers to. We can see this in the interpreter by using the <code>id</code> function to tell what object <code>s</code> refers to before and after the reassignment:</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> s <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>]</span>
<span id="cb4-2"><a href="#cb4-2"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(s)</span>
<span id="cb4-3"><a href="#cb4-3"></a><span class="dv">1695325453760</span></span>
<span id="cb4-4"><a href="#cb4-4"></a><span class="op">&gt;&gt;&gt;</span> s <span class="op">=</span> [<span class="st">&#39;a&#39;</span>, <span class="st">&#39;b&#39;</span>]</span>
<span id="cb4-5"><a href="#cb4-5"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(s)</span>
<span id="cb4-6"><a href="#cb4-6"></a><span class="dv">1695325453248</span></span></code></pre></div>
<p>Notice that the ids are different, indicating that <code>s</code> refers to a new object.</p>
<p>Contrast this with using a mutating <code>list</code> method like <code>list.append</code>:</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> [<span class="dv">1</span>, <span class="dv">2</span>]</span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">list</span>.append(s, <span class="dv">3</span>)</span></code></pre></div>
<div class="fullwidth image-table">
<table>
<thead>
<tr class="header">
<th style="text-align: left;">Before mutation</th>
<th style="text-align: left;">After mutation</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;"><img src="images/mutation1.png" alt="Before mutation" /></td>
<td style="text-align: left;"><img src="images/mutation2.png" alt="After mutation" /></td>
</tr>
</tbody>
</table>
</div>
<p>In this case, no new <code>list</code> object is created, though a new <code>int</code> object is. Instead, the list object <code>[1, 2]</code> is mutated, and a third id is added at its end. Note that even changing the lists size doesnt change its id! Again, we can verify that <code>x</code> refers to the same <code>list</code> object by inspecting ids:</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> [<span class="dv">1</span>, <span class="dv">2</span>]</span>
<span id="cb6-2"><a href="#cb6-2"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(s)</span>
<span id="cb6-3"><a href="#cb6-3"></a><span class="dv">1695325453760</span></span>
<span id="cb6-4"><a href="#cb6-4"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">list</span>.append(s, <span class="dv">3</span>)</span>
<span id="cb6-5"><a href="#cb6-5"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(s)</span>
<span id="cb6-6"><a href="#cb6-6"></a><span class="dv">1695325453760</span></span></code></pre></div>
<p>And finally, one last example that blends assignment and mutation: assigning to part of a compound data type. Consider this 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> s <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>]</span>
<span id="cb7-2"><a href="#cb7-2"></a><span class="op">&gt;&gt;&gt;</span> s[<span class="dv">1</span>] <span class="op">=</span> <span class="dv">300</span></span></code></pre></div>
<p>What happens in this case?</p>
<div class="fullwidth image-table">
<table>
<thead>
<tr class="header">
<th style="text-align: left;">Before mutation</th>
<th style="text-align: left;">After mutation</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;"><img src="images/mutation1.png" alt="Before mutation" /></td>
<td style="text-align: left;"><img src="images/mutation3.png" alt="After mutation" /></td>
</tr>
</tbody>
</table>
</div>
<p>The statement <code>s[1] = 300</code> is also a form of reassignment, but rather than reassigning a variable, it reassigns an id that is part of an object. This means that this statement <em>does</em> mutate an object, and doesnt reassign any variables. We can verify that the id of <code>s</code> doesnt change after the index assignment.</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> s <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>]</span>
<span id="cb8-2"><a href="#cb8-2"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(s)</span>
<span id="cb8-3"><a href="#cb8-3"></a><span class="dv">1695325453760</span></span>
<span id="cb8-4"><a href="#cb8-4"></a><span class="op">&gt;&gt;&gt;</span> s[<span class="dv">1</span>] <span class="op">=</span> <span class="dv">300</span></span>
<span id="cb8-5"><a href="#cb8-5"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(s)</span>
<span id="cb8-6"><a href="#cb8-6"></a><span class="dv">1695325453760</span></span></code></pre></div>
</section>
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>
+312
View File
@@ -0,0 +1,312 @@
<!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.4 Aliasing and “Mutation at a Distance”</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.4 Aliasing and “Mutation at a Distance”</h1>
</header>
<section>
<p>Through our new object-based memory model, weve seen that the Python interpreter associates each variable with the <em>id</em> of an object. There is nothing stopping two or more variables from containing the same id, which means that two variables can refer to the same object. This causes some interesting situations when more than one variable refers to the same mutable object. In this section, we will use our memory model to better understand this specific (and common) situation.</p>
<h2 id="aliasing">Aliasing</h2>
<p>Let <code>v1</code> and <code>v2</code> be Python variables. We saw that <code>v1</code> and <code>v2</code> are <strong>aliases</strong> when they refer to the same object.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> The word “alias” is commonly used when a person is also known under a different name. For example, we might say “Eric Blair, alias George Orwell.” We have two names for the same thing, in this case a person.</span></p>
<p>Consider the following Python 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="op">&gt;&gt;&gt;</span> x <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="op">&gt;&gt;&gt;</span> y <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb1-3"><a href="#cb1-3"></a><span class="op">&gt;&gt;&gt;</span> z <span class="op">=</span> x</span></code></pre></div>
<p><code>x</code> and <code>z</code> are aliases, as they both reference the same object. As a result, they have the same id. You should think of the assignment statement <code>z = x</code> as saying “make <code>z</code> refer to the object that <code>x</code> refers to.” After doing so, they have the same id.</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> <span class="bu">id</span>(x)</span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="dv">4401298824</span></span>
<span id="cb2-3"><a href="#cb2-3"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(z)</span>
<span id="cb2-4"><a href="#cb2-4"></a><span class="dv">4401298824</span></span></code></pre></div>
<p>In contrast, <code>x</code> and <code>y</code> are not aliases. They each refer to a <code>list</code> object with <code>[1, 2, 3]</code> as its value, but they are two different list objects, stored separately in your computers memory. This is again reflected in their different ids.</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> <span class="bu">id</span>(x)</span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="dv">4401298824</span></span>
<span id="cb3-3"><a href="#cb3-3"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(y)</span>
<span id="cb3-4"><a href="#cb3-4"></a><span class="dv">4404546056</span></span></code></pre></div>
<p>Here is the state of memory after the code executes:</p>
<div class="fullscreen">
<p><img src="images/aliasing_intro.png" alt="Aliasing example. There are two different list objects. They have identical contents, but are distinct objects, each with their own id. There are three variables, x, y, and z. x and z both contain the same id, the id of one of the list objects. y contains the id of the other list object." /><br />
</p>
<h2 id="aliasing-and-mutation">Aliasing and mutation</h2>
<p>Aliasing is often a source of confusion for programmers because it allows “mutation at a distance”: the modification of a variables value without explicitly mentioning that variable. Heres an example:</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> x <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb4-2"><a href="#cb4-2"></a><span class="op">&gt;&gt;&gt;</span> y <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb4-3"><a href="#cb4-3"></a><span class="op">&gt;&gt;&gt;</span> z <span class="op">=</span> x</span>
<span id="cb4-4"><a href="#cb4-4"></a><span class="op">&gt;&gt;&gt;</span> z[<span class="dv">0</span>] <span class="op">=</span> <span class="op">-</span><span class="dv">999</span></span>
<span id="cb4-5"><a href="#cb4-5"></a><span class="op">&gt;&gt;&gt;</span> x <span class="co"># What is the value?</span></span></code></pre></div>
<p>The statement <code>x[0] = -999</code> line mutates the value of <code>z</code>. But without ever mentioning <code>x</code>, it also mutates the value of <code>x</code>!</p>
<p>Imprecise language can lead us into misunderstanding the code. We said above that “the third line mutates the value of <code>z</code>”. To be more precise, the third line mutates the object that <code>z</code> refers to. Of course we can also say that it mutates the object that <code>x</code> refers to—they are the same object.</p>
<div class="fullwidth">
<p><img src="images/aliasing_mutation1.png" alt="Aliasing with mutation, first example" /><br />
</p>
</div>
<p>The key thing to notice about this example is that just by looking at the line of code, <code>z[0] = -999</code>, you cant tell that <code>x</code> has changed. You need to know that on a previous line, <code>z</code> was made an alias of <code>x</code>. This is why you have to be careful when aliasing occurs.</p>
<p>Contrast the previous code with this sequence of statements instead:</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> x <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="op">&gt;&gt;&gt;</span> y <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb5-3"><a href="#cb5-3"></a><span class="op">&gt;&gt;&gt;</span> z <span class="op">=</span> x</span>
<span id="cb5-4"><a href="#cb5-4"></a><span class="op">&gt;&gt;&gt;</span> y[<span class="dv">0</span>] <span class="op">=</span> <span class="op">-</span><span class="dv">999</span></span>
<span id="cb5-5"><a href="#cb5-5"></a><span class="op">&gt;&gt;&gt;</span> x <span class="co"># What is the value?</span></span></code></pre></div>
<p>Can you predict the value of <code>x</code> on the last line? Here, the third line mutates the object that <code>y</code> refers to, but because it is not the same object that <code>x</code> refers to, we still see <code>[1, 2, 3]</code> if we evaluate <code>x</code>. Heres the state of memory after these lines execute:</p>
<div class="fullwidth">
<p><img src="images/aliasing_mutation2.png" alt="Aliasing with mutation, second example" /><br />
</p>
</div>
<h2 id="variable-reassignment-again">Variable reassignment, again</h2>
<p>What if we did this instead?</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> x <span class="op">=</span> (<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>)</span>
<span id="cb6-2"><a href="#cb6-2"></a><span class="op">&gt;&gt;&gt;</span> z <span class="op">=</span> x</span>
<span id="cb6-3"><a href="#cb6-3"></a><span class="op">&gt;&gt;&gt;</span> z <span class="op">=</span> (<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">40</span>)</span>
<span id="cb6-4"><a href="#cb6-4"></a><span class="op">&gt;&gt;&gt;</span> x <span class="co"># What is the value?</span></span></code></pre></div>
<p>Again, we have made <code>x</code> and <code>z</code> refer to the same object. So when we change <code>z</code> on the third line, does <code>x</code> also change? This time, the answer is an emphatic <strong>no</strong>, and it is because of the kind of change we make on the third line. Instead of mutating the object that <code>z</code> refers to, we reassign <code>z</code> refer to a new object. This obviously can have no effect on the object that <code>x</code> refers to (or <em>any</em> object). Even if we switched the example from using immutable tuples to using mutable lists, <code>x</code> would be unchanged.</p>
<p>Given two aliases <code>x</code> and <code>z</code>, if we reassign <code>x</code> to a new object, that has <em>no effect</em> on <code>z</code>. We say that reassigning <code>x</code> <em>breaks the aliasing</em>, as afterwards <code>x</code> and <code>z</code> no longer refer to the same object, and so are no longer aliases.</p>
<h2 id="aliasing-and-loop-variables">Aliasing and loop variables</h2>
<p>In Chapter 4, we saw two types of loops: element-based and index-based for loops. With index-based loops, the loop variable referred to an integer object that could be used as an index to a collection (typically a <code>list</code>). But in element-based for loops, the loop variable is an alias to one of the objects <em>within</em> the collection. Suppose we have the following element-based for loop:</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> numbers <span class="op">=</span> [<span class="dv">5</span>, <span class="dv">6</span>, <span class="dv">7</span>]</span>
<span id="cb7-2"><a href="#cb7-2"></a><span class="op">&gt;&gt;&gt;</span> <span class="cf">for</span> number <span class="kw">in</span> numbers:</span>
<span id="cb7-3"><a href="#cb7-3"></a>... number <span class="op">=</span> number <span class="op">+</span> <span class="dv">1</span></span>
<span id="cb7-4"><a href="#cb7-4"></a>...</span>
<span id="cb7-5"><a href="#cb7-5"></a><span class="op">&gt;&gt;&gt;</span> numbers</span>
<span id="cb7-6"><a href="#cb7-6"></a>[<span class="dv">5</span>, <span class="dv">6</span>, <span class="dv">7</span>]</span></code></pre></div>
<p>Notice how the values in the list <code>numbers</code> did not change (i.e., the for loop did not mutate <code>numbers</code>). This is because the loop variable <code>number</code> is an alias for the integer objects found inside <code>numbers</code>. The assignment statement inside the for loop simply changes what the loop variable refers to, but does not change what the contents of the list <code>numbers</code> refers to. If we would like to increment each object contained in the list, we must use an index-based for loop:</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> numbers</span>
<span id="cb8-2"><a href="#cb8-2"></a>[<span class="dv">5</span>, <span class="dv">6</span>, <span class="dv">7</span>]</span>
<span id="cb8-3"><a href="#cb8-3"></a><span class="op">&gt;&gt;&gt;</span> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">0</span>, <span class="bu">len</span>(numbers)):</span>
<span id="cb8-4"><a href="#cb8-4"></a>... numbers[i] <span class="op">=</span> numbers[i] <span class="op">+</span> <span class="dv">1</span></span>
<span id="cb8-5"><a href="#cb8-5"></a>...</span>
<span id="cb8-6"><a href="#cb8-6"></a><span class="op">&gt;&gt;&gt;</span> numbers</span>
<span id="cb8-7"><a href="#cb8-7"></a>[<span class="dv">6</span>, <span class="dv">7</span>, <span class="dv">8</span>]</span></code></pre></div>
<p>The assignment statement in the index-based for loop is fundamentally different from the assignment statement in the element-based for loop. Statements of the form <code>&lt;name&gt; = _______</code> are <em>reassign</em> the variable <code>&lt;name&gt;</code> to a new value. But assignment statements of the form <code>&lt;name&gt;[&lt;index&gt;] = ______</code> <em>mutate</em> the list object that <code>&lt;name&gt;</code> currently refers to.</p>
<h2 id="two-types-of-equality">Two types of equality</h2>
<p>Lets look one more time at this code:</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="op">&gt;&gt;&gt;</span> x <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb9-2"><a href="#cb9-2"></a><span class="op">&gt;&gt;&gt;</span> y <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb9-3"><a href="#cb9-3"></a><span class="op">&gt;&gt;&gt;</span> z <span class="op">=</span> x</span>
<span id="cb9-4"><a href="#cb9-4"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(x)</span>
<span id="cb9-5"><a href="#cb9-5"></a><span class="dv">4401298824</span></span>
<span id="cb9-6"><a href="#cb9-6"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(y)</span>
<span id="cb9-7"><a href="#cb9-7"></a><span class="dv">4404546056</span></span>
<span id="cb9-8"><a href="#cb9-8"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(z)</span>
<span id="cb9-9"><a href="#cb9-9"></a><span class="dv">4401298824</span></span></code></pre></div>
<p>What if we wanted to see whether <code>x</code> and <code>y</code>, for instance, were the same? Well, wed need to define precisely what we mean by “the same”. Our familiar <code>==</code> operator checks whether two objects have the same <em>value</em>. This is called <strong>value equality</strong>.</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> x <span class="op">==</span> y</span>
<span id="cb10-2"><a href="#cb10-2"></a><span class="va">True</span></span>
<span id="cb10-3"><a href="#cb10-3"></a><span class="op">&gt;&gt;&gt;</span> x <span class="op">==</span> z</span>
<span id="cb10-4"><a href="#cb10-4"></a><span class="va">True</span></span></code></pre></div>
<p>But there is another Python operator, <code>is</code>, which checks whether two objects have the same <em>ids</em>. This is called <strong>identity equality</strong>.</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> x <span class="kw">is</span> y</span>
<span id="cb11-2"><a href="#cb11-2"></a><span class="va">False</span></span>
<span id="cb11-3"><a href="#cb11-3"></a><span class="op">&gt;&gt;&gt;</span> x <span class="kw">is</span> z</span>
<span id="cb11-4"><a href="#cb11-4"></a><span class="va">True</span></span></code></pre></div>
<p>Identity equality is a <em>stronger</em> property than value equality: for all objects <code>a</code> and <code>b</code>, if <code>a is b</code> then <code>a == b</code>.<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> In Python it is technically possible to change the behaviour of <code>==</code> in unexpected ways (like always returning <code>False</code>), but this is a poor programming practice and we wont consider it in this course.</span> The converse is not true, as we see in the above example: <code>a == b</code> does not imply <code>a is b</code>.</p>
<h2 id="aliasing-with-immutable-data-types">Aliasing with immutable data types</h2>
<p>Aliasing also exists for immutable data types, but in this case there is never any “action at a distance”, precisely because immutable values can never change. In the example below, <code>x</code> and <code>z</code> are aliases of a tuple object. It is impossible to modify <code>x</code>s value by mutating the object <code>z</code> refers to, since we cant mutate tuples at all.</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb12-1"><a href="#cb12-1"></a><span class="op">&gt;&gt;&gt;</span> x <span class="op">=</span> (<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>)</span>
<span id="cb12-2"><a href="#cb12-2"></a><span class="op">&gt;&gt;&gt;</span> z <span class="op">=</span> x</span>
<span id="cb12-3"><a href="#cb12-3"></a><span class="op">&gt;&gt;&gt;</span> z[<span class="dv">0</span>] <span class="op">=</span> <span class="op">-</span><span class="dv">999</span></span>
<span id="cb12-4"><a href="#cb12-4"></a>Traceback (most recent call last):</span>
<span id="cb12-5"><a href="#cb12-5"></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="cb12-6"><a href="#cb12-6"></a><span class="pp">TypeError</span>: <span class="st">&#39;tuple&#39;</span> <span class="bu">object</span> does <span class="kw">not</span> support item assignment</span></code></pre></div>
<h3 id="automatic-aliasing-of-some-immutable-objects">Automatic aliasing of (some) immutable objects</h3>
<p>The above discussion actually has a very interesting implication for how we reason about variables referring to immutable objects: <em>if two variables have the same immutable value, the programs behaviour does not depend on whether the two variables are aliases or not</em>.</p>
<p>For example, consider the following two code snippets:</p>
<table style="width:75%;">
<colgroup>
<col style="width: 37%" />
<col style="width: 37%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="sourceCode" id="cb13"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1"></a><span class="op">&gt;&gt;&gt;</span> x <span class="op">=</span> (<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>)</span>
<span id="cb13-2"><a href="#cb13-2"></a><span class="op">&gt;&gt;&gt;</span> y <span class="op">=</span> (<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>)</span>
<span id="cb13-3"><a href="#cb13-3"></a><span class="op">&gt;&gt;&gt;</span> my_function(x, y)</span>
<span id="cb13-4"><a href="#cb13-4"></a><span class="dv">10</span></span></code></pre></div></td>
<td><div class="sourceCode" id="cb14"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb14-1"><a href="#cb14-1"></a><span class="op">&gt;&gt;&gt;</span> x <span class="op">=</span> (<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>)</span>
<span id="cb14-2"><a href="#cb14-2"></a><span class="op">&gt;&gt;&gt;</span> y <span class="op">=</span> x</span>
<span id="cb14-3"><a href="#cb14-3"></a><span class="op">&gt;&gt;&gt;</span> my_function(x, y)</span>
<span id="cb14-4"><a href="#cb14-4"></a><span class="dv">10</span></span></code></pre></div></td>
</tr>
</tbody>
</table>
<p>These two code snippets will always behave the same way, regardless of what <code>my_function</code> actually does! Because <code>x</code> and <code>y</code> refer to immutable values, the behaviour of <code>my_function</code> depends only on the values of the object, and not their ids.</p>
<p>This allows the Python interpreter to save a bit of computer memory by not creating new objects for some immutable values. For example, every occurrence of the boolean value <code>True</code> refers to the same object:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb15-1"><a href="#cb15-1"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(<span class="va">True</span>)</span>
<span id="cb15-2"><a href="#cb15-2"></a><span class="dv">1734328640</span></span>
<span id="cb15-3"><a href="#cb15-3"></a><span class="op">&gt;&gt;&gt;</span> x <span class="op">=</span> <span class="va">True</span></span>
<span id="cb15-4"><a href="#cb15-4"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(<span class="va">True</span>)</span>
<span id="cb15-5"><a href="#cb15-5"></a><span class="dv">1734328640</span></span>
<span id="cb15-6"><a href="#cb15-6"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(<span class="dv">10</span> <span class="op">&gt;</span> <span class="dv">3</span>)</span>
<span id="cb15-7"><a href="#cb15-7"></a><span class="dv">1734328640</span></span>
<span id="cb15-8"><a href="#cb15-8"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(<span class="kw">not</span> <span class="va">False</span>)</span>
<span id="cb15-9"><a href="#cb15-9"></a><span class="dv">1734328640</span></span></code></pre></div>
<p>A bit more surprisingly, “small” integers are automatically aliased, while “large” integers are not:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb16-1"><a href="#cb16-1"></a><span class="op">&gt;&gt;&gt;</span> x <span class="op">=</span> <span class="dv">43</span></span>
<span id="cb16-2"><a href="#cb16-2"></a><span class="op">&gt;&gt;&gt;</span> y <span class="op">=</span> <span class="dv">43</span></span>
<span id="cb16-3"><a href="#cb16-3"></a><span class="op">&gt;&gt;&gt;</span> x <span class="kw">is</span> y</span>
<span id="cb16-4"><a href="#cb16-4"></a><span class="va">True</span></span>
<span id="cb16-5"><a href="#cb16-5"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(x)</span>
<span id="cb16-6"><a href="#cb16-6"></a><span class="dv">1734453840</span></span>
<span id="cb16-7"><a href="#cb16-7"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(y)</span>
<span id="cb16-8"><a href="#cb16-8"></a><span class="dv">1734453840</span></span>
<span id="cb16-9"><a href="#cb16-9"></a><span class="op">&gt;&gt;&gt;</span> a <span class="op">=</span> <span class="dv">1000</span></span>
<span id="cb16-10"><a href="#cb16-10"></a><span class="op">&gt;&gt;&gt;</span> b <span class="op">=</span> <span class="dv">1000</span></span>
<span id="cb16-11"><a href="#cb16-11"></a><span class="op">&gt;&gt;&gt;</span> a <span class="kw">is</span> b</span>
<span id="cb16-12"><a href="#cb16-12"></a><span class="va">False</span></span>
<span id="cb16-13"><a href="#cb16-13"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(a)</span>
<span id="cb16-14"><a href="#cb16-14"></a><span class="dv">16727840</span></span>
<span id="cb16-15"><a href="#cb16-15"></a><span class="op">&gt;&gt;&gt;</span> <span class="bu">id</span>(b)</span>
<span id="cb16-16"><a href="#cb16-16"></a><span class="dv">16727856</span></span></code></pre></div>
<p>The other immutable data type where the Python interpret takes this object creation “shortcut” is with <em>some</em> string values:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb17-1"><a href="#cb17-1"></a><span class="op">&gt;&gt;&gt;</span> name1 <span class="op">=</span> <span class="st">&#39;David&#39;</span></span>
<span id="cb17-2"><a href="#cb17-2"></a><span class="op">&gt;&gt;&gt;</span> name2 <span class="op">=</span> <span class="st">&#39;David&#39;</span></span>
<span id="cb17-3"><a href="#cb17-3"></a><span class="op">&gt;&gt;&gt;</span> name1 <span class="kw">is</span> name2</span>
<span id="cb17-4"><a href="#cb17-4"></a><span class="va">True</span></span>
<span id="cb17-5"><a href="#cb17-5"></a><span class="op">&gt;&gt;&gt;</span> full_name1 <span class="op">=</span> <span class="st">&#39;David Liu&#39;</span></span>
<span id="cb17-6"><a href="#cb17-6"></a><span class="op">&gt;&gt;&gt;</span> full_name2 <span class="op">=</span> <span class="st">&#39;David Liu&#39;</span></span>
<span id="cb17-7"><a href="#cb17-7"></a><span class="op">&gt;&gt;&gt;</span> full_name1 <span class="kw">is</span> full_name2</span>
<span id="cb17-8"><a href="#cb17-8"></a><span class="va">False</span></span></code></pre></div>
<p>The exact rules for when the Python interpreter does and does not take this shortcut are beyond the scope of this course, and actually change from one version of Python to the next. For the purpose of writing Python code and doing object comparisons, the bottom line is:</p>
<ul>
<li>For <em>boolean</em> values, use <code>is</code> to compare for equality.<label for="sn-2" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-2" class="margin-toggle"/><span class="sidenote"> Though also keep in mind that you should never write <code>&lt;expr&gt; is True</code> or <code>&lt;expr&gt; is False</code>, since these are equivalent to the simpler <code>&lt;expr&gt;</code> and <code>not &lt;expr&gt;</code>, respectively.</span></li>
<li>For <em>non-boolean</em> <em>immutable</em> values, use <code>==</code> to compare for equality, as using <code>is</code> can lead to surprsing results.</li>
<li>For <em>mutable</em> values, use <code>==</code> to compare value equality (almost always what you want).</li>
<li>For <em>mutable</em> values, use <code>is</code> to check for aliasing (almost never what you want).</li>
</ul>
</section>
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>
@@ -0,0 +1,262 @@
<!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.5 The Full Python Memory Model: Function Calls</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.5 The Full Python Memory Model: Function Calls</h1>
</header>
<section>
<p>So far in this chapter, we have talked only about variables defined within the Python console. In <a href="../02-functions/03-function-scope.html">2.3 Local Variables and Function Scope</a>, we saw how to represent function scope in the value-based memory model using separate “tables of values” for each function call. In this section, well see how to represent function scope in the full Python memory model so that we can capture exactly how function scope works and impacts the variables we use throughout the lifetime of our programs.</p>
<h2 id="stack-frames">Stack frames</h2>
<p>Suppose we define the following function, and then call it in the Python console:</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">def</span> repeat(n: <span class="bu">int</span>, s: <span class="bu">str</span>) <span class="op">-&gt;</span> <span class="bu">str</span>:</span>
<span id="cb1-2"><a href="#cb1-2"></a> message <span class="op">=</span> s <span class="op">*</span> n</span>
<span id="cb1-3"><a href="#cb1-3"></a> <span class="cf">return</span> message</span>
<span id="cb1-4"><a href="#cb1-4"></a></span>
<span id="cb1-5"><a href="#cb1-5"></a></span>
<span id="cb1-6"><a href="#cb1-6"></a><span class="co"># In the Python console</span></span>
<span id="cb1-7"><a href="#cb1-7"></a><span class="op">&gt;&gt;&gt;</span> count <span class="op">=</span> <span class="dv">3</span></span>
<span id="cb1-8"><a href="#cb1-8"></a><span class="op">&gt;&gt;&gt;</span> word <span class="op">=</span> <span class="st">&#39;abc&#39;</span></span>
<span id="cb1-9"><a href="#cb1-9"></a><span class="op">&gt;&gt;&gt;</span> result <span class="op">=</span> repeat(count, word)</span></code></pre></div>
<p>Consider what the state of memory is when <code>repeat(count, word)</code> is called, <em>immediately before</em> the <code>return message</code> statement executes. Lets first recall how we would draw the <em>value-based</em> memory model for this point:</p>
<div class="memory-model-values">
<table>
<caption><code>__main__</code></caption>
<thead>
<tr class="header">
<th>Variable</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>count</code></td>
<td><code>3</code></td>
</tr>
<tr class="even">
<td><code>word</code></td>
<td><code>'abc'</code></td>
</tr>
</tbody>
</table>
<table>
<caption><mark><strong><code>repeat</code></strong></mark></caption>
<thead>
<tr class="header">
<th>Variable</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>n</code></td>
<td><code>3</code></td>
</tr>
<tr class="even">
<td><code>s</code></td>
<td><code>'abc'</code></td>
</tr>
<tr class="odd">
<td><code>message</code></td>
<td><code>'abcabcabc'</code></td>
</tr>
</tbody>
</table>
</div>
</div>
<p>This memory model shows two tables, showing the variables defined in the Python console (<code>count</code>, <code>word</code>), and the variables local to the function <code>repeat</code> (<code>n</code>, <code>s</code>, and <code>message</code>).</p>
<p>Here is how we would translate this into a full Python memory model diagram:</p>
<p><img src="images/call_stack_repeat.png" alt="Memory model diagram showing __main__ and repeat" /><br />
</p>
<p>As with the diagrams we saw in the previous sections of this chapter, our variables are on the left side of the diagram, and the objects on the right. The variables are separated into two separate boxes, one for the Python console and one for the function call for <code>repeat</code>. All variables, regardless of which box theyre in, store only ids that refer to objects on the right-hand side. Notice that <code>count</code> and <code>n</code> are aliases, as are <code>word</code> and <code>s</code>.</p>
<p>Now that we have this full diagram, well introduce a more formal piece of terminology. Each “box” on the left-hand side of our diagram represents a <strong>stack frame</strong> (or just <strong>frame</strong> for short), which is a special data type used by the Python interpreter to keep track of the functions that have been called in a program, and the variables defined within each function. We call the collection of stack frames the <strong>function call stack</strong>.</p>
<p>Every time we call a function, the Python interpreter does the following:</p>
<ol type="1">
<li>Create a new stack frame and add it to the call stack.</li>
<li>Evaluate the arguments in the function call, yielding the ids of objects (one per argument). Each of these ids is assigned to the corresponding parameter, as an entry in the new stack frame.</li>
<li>Execute the body of the function.</li>
<li>When a return statement is executed in the function body, the id of the returned object is saved and the stack frame for the function call is removed from the call stack.</li>
</ol>
<h2 id="argument-passing-and-aliasing">Argument passing and aliasing</h2>
<p>What we often call “parameter passing” is a special form of variable assignment in the Python interpreter. In the example above, when we called <code>repeat(count, word)</code>, it is as if we wrote</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1"></a>n <span class="op">=</span> count</span>
<span id="cb2-2"><a href="#cb2-2"></a>s <span class="op">=</span> word</span></code></pre></div>
<p>before executing the body of the function.</p>
<p>This aliasing is what allows us to define functions that mutate their argument values, and have that effect persist after the function ends. Here is an example:</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">def</span> emphasize(words: <span class="bu">list</span>[<span class="bu">str</span>]) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb3-2"><a href="#cb3-2"></a> <span class="co">&quot;&quot;&quot;Add emphasis to the end of a list of words.&quot;&quot;&quot;</span></span>
<span id="cb3-3"><a href="#cb3-3"></a> new_words <span class="op">=</span> [<span class="st">&#39;believe&#39;</span>, <span class="st">&#39;me!&#39;</span>]</span>
<span id="cb3-4"><a href="#cb3-4"></a> <span class="bu">list</span>.extend(words, new_words)</span>
<span id="cb3-5"><a href="#cb3-5"></a></span>
<span id="cb3-6"><a href="#cb3-6"></a></span>
<span id="cb3-7"><a href="#cb3-7"></a><span class="co"># In the Python console</span></span>
<span id="cb3-8"><a href="#cb3-8"></a><span class="op">&gt;&gt;&gt;</span> sentence <span class="op">=</span> [<span class="st">&#39;winter&#39;</span>, <span class="st">&#39;is&#39;</span>, <span class="st">&#39;coming&#39;</span>]</span>
<span id="cb3-9"><a href="#cb3-9"></a><span class="op">&gt;&gt;&gt;</span> emphasize(sentence)</span>
<span id="cb3-10"><a href="#cb3-10"></a><span class="op">&gt;&gt;&gt;</span> sentence</span>
<span id="cb3-11"><a href="#cb3-11"></a>[<span class="st">&#39;winter&#39;</span>, <span class="st">&#39;is&#39;</span>, <span class="st">&#39;coming&#39;</span>, <span class="st">&#39;believe&#39;</span>, <span class="st">&#39;me!&#39;</span>]</span></code></pre></div>
<p>When <code>emphasize(sentence)</code> is called in the Python console, this is the state of memory:</p>
<div class="fullwidth">
<p><img src="images/call_stack_mutation.png" alt="Memory model diagram for emphasize" /><br />
</p>
</div>
<p>In this case, <code>words</code> and <code>sentence</code> are aliases, and so mutating <code>words</code> within the function causes a change to occur in <code>__main__</code> as well.</p>
<p>On the other hand, consider what happens with this version of the function:</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> emphasize_v2(words: <span class="bu">list</span>[<span class="bu">str</span>]) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb4-2"><a href="#cb4-2"></a> <span class="co">&quot;&quot;&quot;Add emphasis to the end of a list of words.&quot;&quot;&quot;</span></span>
<span id="cb4-3"><a href="#cb4-3"></a> new_words <span class="op">=</span> [<span class="st">&#39;believe&#39;</span>, <span class="st">&#39;me!&#39;</span>]</span>
<span id="cb4-4"><a href="#cb4-4"></a> words <span class="op">=</span> words <span class="op">+</span> new_words</span>
<span id="cb4-5"><a href="#cb4-5"></a></span>
<span id="cb4-6"><a href="#cb4-6"></a></span>
<span id="cb4-7"><a href="#cb4-7"></a><span class="co"># In the Python console</span></span>
<span id="cb4-8"><a href="#cb4-8"></a><span class="op">&gt;&gt;&gt;</span> sentence <span class="op">=</span> [<span class="st">&#39;winter&#39;</span>, <span class="st">&#39;is&#39;</span>, <span class="st">&#39;coming&#39;</span>]</span>
<span id="cb4-9"><a href="#cb4-9"></a><span class="op">&gt;&gt;&gt;</span> emphasize_v2(sentence)</span>
<span id="cb4-10"><a href="#cb4-10"></a><span class="op">&gt;&gt;&gt;</span> sentence</span>
<span id="cb4-11"><a href="#cb4-11"></a>[<span class="st">&#39;winter&#39;</span>, <span class="st">&#39;is&#39;</span>, <span class="st">&#39;coming&#39;</span>]</span></code></pre></div>
<p>After we call <code>emphasize_v2</code> in the Python console, the value of <code>sentence</code> is unchanged! To understand why, lets look at two memory model diagrams. The first shows the state of memory immediately after <code>new_words = ['believe', 'me!']</code> is executed:</p>
<div class="fullwidth">
<p><img src="images/call_stack_reassignment1.png" alt="Diagram of emphasize_v2 after new_words = [believe, me!]." /><br />
</p>
</div>
<p>The next statement to execute is <code>words = words + new_words</code>. The key to understanding the next diagram is to recall <em>variable reassignment</em>: the right-hand side (<code>words + new_words</code>) is evaluated, and then the resulting object id is assigned to <code>words</code>. <em>List concatenation with <code>+</code> creates a new list object</em>.</p>
<div class="fullwidth">
<p><img src="images/call_stack_reassignment2.png" alt="Diagram of emphasize_v2 after words = words + new_words." /><br />
</p>
</div>
<p>Notice that in this diagram, <code>words</code> and <code>sentence</code> are no longer aliases! Instead, <code>words</code> has been assigned to a new list object, but <code>sentence</code> has remained unchanged.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> Remember the rule of variable reassignment: an assignment statement <code>&lt;name&gt; = ...</code> only changes what object the variable <code>&lt;name&gt;</code> refers to, but never changes any other variables.</span> This illustrates the importance of keeping variable reassignment and object mutation as distinct concepts. Even though the bodies of <code>emphasize</code> and <code>emphasize_v2</code> look very similar, the end result is very different: <code>emphasize</code> mutates its argument object, while <code>emphasize_v2</code> actually leaves it unchanged!</p>
</section>
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>
+233
View File
@@ -0,0 +1,233 @@
<!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.6 Testing Functions III: Testing Mutation</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.6 Testing Functions III: Testing Mutation</h1>
</header>
<section>
<p>The ability to mutate objects means that we have to be careful when writing functions that accept mutable types as parameters. In general, if a functions documentation does not specify that an object will be mutated, then it <strong>must not</strong> be mutated. How can we test that no mutation occured? And, for functions that intend to mutate an object, how can we test that the correct change occured? In this section, we will extend our study of writing tests to answer both of these questions.</p>
<h2 id="identifying-mutable-parameters">Identifying mutable parameters</h2>
<p>Consider the <code>squares</code> function we introduced at the beginning of the chapter:</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">def</span> squares(nums: <span class="bu">list</span>[<span class="bu">int</span>]) <span class="op">-&gt;</span> <span class="bu">list</span>[<span class="bu">int</span>]:</span>
<span id="cb1-2"><a href="#cb1-2"></a> <span class="co">&quot;&quot;&quot;Return a list of the squares of the given numbers.&quot;&quot;&quot;</span></span>
<span id="cb1-3"><a href="#cb1-3"></a> squares_so_far <span class="op">=</span> []</span>
<span id="cb1-4"><a href="#cb1-4"></a></span>
<span id="cb1-5"><a href="#cb1-5"></a> <span class="cf">for</span> num <span class="kw">in</span> nums:</span>
<span id="cb1-6"><a href="#cb1-6"></a> <span class="bu">list</span>.append(squares_so_far, num <span class="op">*</span> num)</span>
<span id="cb1-7"><a href="#cb1-7"></a></span>
<span id="cb1-8"><a href="#cb1-8"></a> <span class="cf">return</span> squares_so_far</span></code></pre></div>
<p>There are two lists in <code>squares</code>: the <code>nums</code> parameter, which is an input to the function; and the <code>squares_so_far</code> variable, which is an output of the function. Because <code>squares_so_far</code> is created by the function <code>squares</code>, it is okay that it is mutated (i.e., the call to <code>list.append</code> inside the for loop). However, the <code>nums</code> list is passed as an argument to <code>squares</code>. Because the docstring does not indicate that <code>nums</code> will be mutated, it is expected that the <code>squares</code> function will not mutate the list object referred to by <code>nums</code>.</p>
<p>We can contrast this with how we would document and implement a similar function that <em>does</em> mutate its input:</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> square_all(nums: <span class="bu">list</span>[<span class="bu">int</span>]) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb2-2"><a href="#cb2-2"></a> <span class="co">&quot;&quot;&quot;Modify nums by squaring each of its elements.&quot;&quot;&quot;</span></span>
<span id="cb2-3"><a href="#cb2-3"></a> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">0</span>, <span class="bu">len</span>(nums)):</span>
<span id="cb2-4"><a href="#cb2-4"></a> nums[i] <span class="op">=</span> nums[i] <span class="op">*</span> nums[i]</span></code></pre></div>
<h2 id="testing-for-no-mutation">Testing for no mutation</h2>
<p>Let us write a test that ensures the <code>squares</code> function does not mutate the list referred to by <code>nums</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">def</span> test_squares_no_mutation() <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb3-2"><a href="#cb3-2"></a> <span class="co">&quot;&quot;&quot;Confirm that squares does not mutate the list it is given.</span></span>
<span id="cb3-3"><a href="#cb3-3"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb3-4"><a href="#cb3-4"></a> lst <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb3-5"><a href="#cb3-5"></a> squares(lst)</span>
<span id="cb3-6"><a href="#cb3-6"></a></span>
<span id="cb3-7"><a href="#cb3-7"></a> <span class="co"># </span><span class="al">TODO</span><span class="co">: complete the test</span></span></code></pre></div>
<p>In order to test that a list is not mutated, we first create a list <code>lst</code>. Second, we call the <code>squares</code> function on <code>lst</code>; note that this function call returns a list of squares, but we do not assign the result to a variable because we dont actually care about the returned value for the purpose of this test.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> This might seem a bit strange, as all of our tests so far have been about checking the return value of the function being tested. In practice, we would have such unit/property-based tests for <code>squares</code> as well, we just arent showing them here.</span> We can now add an assertion that ensures <code>lst</code> has not been mutated:</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> test_squares_no_mutation() <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb4-2"><a href="#cb4-2"></a> <span class="co">&quot;&quot;&quot;Test that squares does not mutate the list it is given.</span></span>
<span id="cb4-3"><a href="#cb4-3"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb4-4"><a href="#cb4-4"></a> lst <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb4-5"><a href="#cb4-5"></a> squares(lst)</span>
<span id="cb4-6"><a href="#cb4-6"></a></span>
<span id="cb4-7"><a href="#cb4-7"></a> <span class="cf">assert</span> lst <span class="op">==</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span></code></pre></div>
<p>The variable <code>lst</code> originally had value <code>[1, 2, 3]</code>. So our assertion checks that <em>after</em> the call to <code>squares</code>, <code>lst</code> still has value <code>[1, 2, 3]</code>. Another way to accomplish this, without re-typing the list value, is by creating a copy of <code>lst</code> before the call to <code>squares</code>. We can do this using the <code>list.copy</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> test_squares_no_mutation() <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;Test that squares does not mutate the list it is given.</span></span>
<span id="cb5-3"><a href="#cb5-3"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb5-4"><a href="#cb5-4"></a> lst <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb5-5"><a href="#cb5-5"></a> lst_copy <span class="op">=</span> <span class="bu">list</span>.copy(lst) <span class="co"># Create a copy of lst (not an alias!)</span></span>
<span id="cb5-6"><a href="#cb5-6"></a> squares(lst)</span>
<span id="cb5-7"><a href="#cb5-7"></a></span>
<span id="cb5-8"><a href="#cb5-8"></a> <span class="cf">assert</span> lst <span class="op">==</span> lst_copy</span></code></pre></div>
<p>Note that the order of statements is very important when testing for mutation. We need to create the list and its copy before the call to <code>squares</code>. And we need to test for mutation (i.e., the assertion) after the call to <code>squares</code>.</p>
<h3 id="generalizing-this-test">Generalizing this test</h3>
<p>You might notice that the above <code>test_squares_no_mutation</code> test function doesnt actually use the specific elements of the list <code>lst</code>. That is, if we replaced <code>lst</code>s value with another list, the test would behave in the exact same way. That makes this test very suitable to be generalized into a <em>property-based test</em>, representing the following property:</p>
<blockquote>
<p>For all lists of integers <code>lst</code>, calling <code>squares(lst)</code> does not mutate <code>lst</code>.</p>
</blockquote>
<p>Here is how we could implement such a property-based test using the technique we learned in <a href="../03-logic/10-testing-fucntions-2.html">3.10 Testing Functions II: <code>hypothesis</code></a>.<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> Weve included the import statements to remind you about the ones from <code>hypothesis</code> you need for property-based tests.</span></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="im">from</span> hypothesis <span class="im">import</span> given</span>
<span id="cb6-2"><a href="#cb6-2"></a><span class="im">from</span> hypothesis.strategies <span class="im">import</span> lists, integers</span>
<span id="cb6-3"><a href="#cb6-3"></a></span>
<span id="cb6-4"><a href="#cb6-4"></a></span>
<span id="cb6-5"><a href="#cb6-5"></a><span class="at">@given</span>(lst<span class="op">=</span>lists(integers()))</span>
<span id="cb6-6"><a href="#cb6-6"></a><span class="kw">def</span> test_squares_no_mutation_general(lst: <span class="bu">list</span>[<span class="bu">int</span>]) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb6-7"><a href="#cb6-7"></a> <span class="co">&quot;&quot;&quot;Test that squares does not mutate the list it is given.</span></span>
<span id="cb6-8"><a href="#cb6-8"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb6-9"><a href="#cb6-9"></a> lst_copy <span class="op">=</span> <span class="bu">list</span>.copy(lst) <span class="co"># Create a copy of lst (not an alias!)</span></span>
<span id="cb6-10"><a href="#cb6-10"></a> squares(lst)</span>
<span id="cb6-11"><a href="#cb6-11"></a></span>
<span id="cb6-12"><a href="#cb6-12"></a> <span class="cf">assert</span> lst <span class="op">==</span> lst_copy</span></code></pre></div>
<h2 id="testing-for-mutation">Testing for mutation</h2>
<p>Now lets consider testing the <code>square_all</code> function. One common error students make when writing tests for mutating functions is to check the return value of the function.</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">def</span> test_square_all() <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb7-2"><a href="#cb7-2"></a> <span class="co">&quot;&quot;&quot;Test that square_all mutates the list it is given correctly.</span></span>
<span id="cb7-3"><a href="#cb7-3"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb7-4"><a href="#cb7-4"></a> lst <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb7-5"><a href="#cb7-5"></a> result <span class="op">=</span> square_all(lst)</span>
<span id="cb7-6"><a href="#cb7-6"></a></span>
<span id="cb7-7"><a href="#cb7-7"></a> <span class="cf">assert</span> result <span class="op">==</span> [<span class="dv">1</span>, <span class="dv">4</span>, <span class="dv">9</span>]</span></code></pre></div>
<p>This test fails because <code>square_all</code> returns <code>None</code>, and <code>None == [1, 4, 9]</code> is False. Using <code>result</code> in our assertion is not useful for testing if <code>lst</code> was mutated. Instead, we must test if the value of <code>lst</code> has changed:<label for="sn-2" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-2" class="margin-toggle"/><span class="sidenote"> Like <code>test_squares_no_mutation</code>, this test does not store the return value of the function being tested. But the reason is quite different!</span></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> test_square_all_mutation() <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;Test that square_all mutates the list it is given correctly.</span></span>
<span id="cb8-3"><a href="#cb8-3"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb8-4"><a href="#cb8-4"></a> lst <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
<span id="cb8-5"><a href="#cb8-5"></a> square_all(lst)</span>
<span id="cb8-6"><a href="#cb8-6"></a></span>
<span id="cb8-7"><a href="#cb8-7"></a> <span class="cf">assert</span> lst <span class="op">==</span> [<span class="dv">1</span>, <span class="dv">4</span>, <span class="dv">9</span>]</span></code></pre></div>
<p>We can again generalize this test into a property-based test by storing a copy of the original list and verifying the relationship between corresponding elements. Well leave it as an exercise for you to read through and understand the following property-based test:</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="at">@given</span>(lst<span class="op">=</span>lists(integers()))</span>
<span id="cb9-2"><a href="#cb9-2"></a><span class="kw">def</span> test_square_all_mutation_general(lst: <span class="bu">list</span>[<span class="bu">int</span>]) <span class="op">-&gt;</span> <span class="va">None</span>:</span>
<span id="cb9-3"><a href="#cb9-3"></a> <span class="co">&quot;&quot;&quot;Test that square_all mutates the list it is given correctly.</span></span>
<span id="cb9-4"><a href="#cb9-4"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb9-5"><a href="#cb9-5"></a> lst_copy <span class="op">=</span> <span class="bu">list</span>.copy(lst)</span>
<span id="cb9-6"><a href="#cb9-6"></a> square_all(lst)</span>
<span id="cb9-7"><a href="#cb9-7"></a></span>
<span id="cb9-8"><a href="#cb9-8"></a> <span class="cf">assert</span> <span class="bu">all</span>({lst[i] <span class="op">==</span> lst_copy[i] <span class="op">**</span> <span class="dv">2</span> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">0</span>, <span class="bu">len</span>(lst))})</span></code></pre></div>
</section>
<footer>
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
</footer>
</body>
</html>