deploy
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
<!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>2.1 Python’s Built-In Functions</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">2.1 Python’s Built-In Functions</h1>
|
||||
</header>
|
||||
<section>
|
||||
<p>In the previous chapter, we began our study of programming in Python by studying three main ingredients: literals, operators, and variables. We can express complex computations using just these forms of Python code, but as the tasks we want to perform grow more complex, so too does the code we need to write. In this chapter, we’ll learn about using <em>functions</em> in Python to organize our code into useful logical blocks that can be worked on separately and reused again and again in our programs.</p>
|
||||
<h2 id="review-functions-in-mathematics">Review: Functions in mathematics</h2>
|
||||
<p>Before looking at functions in Python, we’ll first review some of the mathematical definitions related to functions from the <a href="https://q.utoronto.ca/courses/160038/pages/sets-and-functions-review">First-Year CS Summer Prep</a>.</p>
|
||||
<p>Let <span class="math inline">\(A\)</span> and <span class="math inline">\(B\)</span> be sets. A <strong>function</strong> <span class="math inline">\(f : A \to B\)</span> is a mapping from elements in <span class="math inline">\(A\)</span> to elements in <span class="math inline">\(B\)</span>. <span class="math inline">\(A\)</span> is called the <strong>domain</strong> of the function, and <span class="math inline">\(B\)</span> is called the <strong>codomain</strong> of the function.</p>
|
||||
<p>Functions can have more than one input. For sets <span class="math inline">\(A_1, A_2, \dots, A_k\)</span> and <span class="math inline">\(B\)</span>, a <span class="math inline">\(k\)</span>-ary function <span class="math inline">\(f: A_1 \times A_2 \times \dots \times A_k \to B\)</span> is a function that takes <span class="math inline">\(k\)</span> arguments, where for each <span class="math inline">\(i\)</span> between <span class="math inline">\(1\)</span> and <span class="math inline">\(k\)</span>, the <span class="math inline">\(i\)</span>-th argument of <span class="math inline">\(f\)</span> must be an element of <span class="math inline">\(A_i\)</span>, and where <span class="math inline">\(f\)</span> returns an element of <span class="math inline">\(B\)</span>. We have common English terms for small values of <span class="math inline">\(k\)</span>: unary, binary, and ternary functions take one, two, and three inputs, respectively. For example, the addition operator <span class="math inline">\(+ : \R \times \R \to \R\)</span> is a <em>binary</em> function that takes two real numbers and returns their sum. For readability, we usually write this function as <span class="math inline">\(x+y\)</span> instead of <span class="math inline">\(+(x,y)\)</span>.</p>
|
||||
<h2 id="pythons-built-in-functions-in-python">Python’s built-in functions in Python</h2>
|
||||
<p>We’ve seen that Python has many operators, like <code>+</code> that can be used on various data types. These operators are actually functions represented by symbols (e.g., addition through the <code>+</code> symbol). But there aren’t enough symbols to represent every function we could ever want. So Python also defines several functions that we can use to perform additional operations; these functions are called <strong>built-in functions</strong>, as they are made automatically available to us anywhere in a Python program. For example, the Python function <code>abs</code> takes a single numeric input and returns its absolute value. But how do we actually use it?</p>
|
||||
<p>A Python expression that uses a function to operate on a given input is called a <strong>function call</strong>, and has the same syntax as mathematics: <code><function_name>(<argument>, <argument>, ...)</code>. For example, here are two examples of a function call expressions that call <code>abs</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">>>></span> <span class="bu">abs</span>(<span class="op">-</span><span class="dv">10</span>) <span class="co"># Returns the absolute value of -10.</span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2"></a><span class="dv">10</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3"></a><span class="op">>>></span> <span class="bu">abs</span>(<span class="dv">100</span>)</span>
|
||||
<span id="cb1-4"><a href="#cb1-4"></a><span class="dv">100</span></span></code></pre></div>
|
||||
<p>Function calls are central to programming, and come with some new terminology that we’ll introduce now and use throughout the next year.</p>
|
||||
<ul>
|
||||
<li>In a function call expression, the input expressions are called <strong>arguments</strong> to the function call. <em>Example</em>: in the expression <code>abs(-10)</code>, the <code>-10</code> is the argument of the function call.</li>
|
||||
<li>When we evaluate a function call, we say that the arguments are <strong>passed</strong> to the function. <em>Example</em>: in <code>abs(-10)</code>, we say that <code>-10</code> is passed to <code>abs</code>.</li>
|
||||
<li>When the function call produces a value, we say that the function call <strong>returns</strong> a value, and refer to this value as the <strong>return value</strong> of the function call expression. <em>Example</em>: the return value of <code>abs(-10)</code> is <code>10</code>.</li>
|
||||
</ul>
|
||||
<p>In your mathematical studies so far, you’ve mainly studied <em>unary numeric</em> functions, i.e., functions that take in just one numeric argument and return another number.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> Examples include the sin and log functions.</span> In programming, however, it is very common to work with functions that operate on a wide variety of data types, and a wide number of arguments. Here are a few examples of built-in functions that go beyond taking a single numeric argument:</p>
|
||||
<ul>
|
||||
<li><p>The <code>len</code> function takes a string or collection data type (e.g., <code>set</code>, <code>list</code>) and returns the size of its input.<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> While we defined “size” of these data types back in Section 1.1, we didn’t cover them in Python in the last chapter because we were waiting to get to functions.</span></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">>>></span> <span class="bu">len</span>({<span class="dv">10</span>, <span class="dv">20</span>, <span class="dv">30</span>})</span>
|
||||
<span id="cb2-2"><a href="#cb2-2"></a><span class="dv">3</span></span>
|
||||
<span id="cb2-3"><a href="#cb2-3"></a><span class="op">>>></span> <span class="bu">len</span>(<span class="st">''</span>)</span>
|
||||
<span id="cb2-4"><a href="#cb2-4"></a><span class="dv">0</span></span>
|
||||
<span id="cb2-5"><a href="#cb2-5"></a><span class="op">>>></span> <span class="bu">len</span>([<span class="st">'a'</span>, <span class="st">'b'</span>, <span class="st">'c'</span>, <span class="st">'d'</span>, <span class="st">'e'</span>])</span>
|
||||
<span id="cb2-6"><a href="#cb2-6"></a><span class="dv">5</span></span>
|
||||
<span id="cb2-7"><a href="#cb2-7"></a><span class="op">>>></span> <span class="bu">len</span>({<span class="st">'David'</span>: <span class="dv">100</span>, <span class="st">'Mario'</span>: <span class="dv">0</span>})</span>
|
||||
<span id="cb2-8"><a href="#cb2-8"></a><span class="dv">2</span></span></code></pre></div></li>
|
||||
<li><p>The <code>sum</code> function takes a collection of numbers (e.g., a <code>set</code> or <code>list</code> whose elements are all numbers) and returns the sum of the numbers.</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">>>></span> <span class="bu">sum</span>({<span class="dv">10</span>, <span class="dv">20</span>, <span class="dv">30</span>})</span>
|
||||
<span id="cb3-2"><a href="#cb3-2"></a><span class="dv">60</span></span>
|
||||
<span id="cb3-3"><a href="#cb3-3"></a><span class="op">>>></span> <span class="bu">sum</span>([<span class="op">-</span><span class="fl">4.5</span>, <span class="op">-</span><span class="dv">10</span>, <span class="dv">2</span>, <span class="dv">0</span>])</span>
|
||||
<span id="cb3-4"><a href="#cb3-4"></a><span class="op">-</span><span class="fl">12.5</span></span></code></pre></div></li>
|
||||
<li><p>The <code>sorted</code> function takes a collection and returns a <code>list</code> that contains the same elements as the input collection, sorted in ascending order.</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">>>></span> <span class="bu">sorted</span>([<span class="dv">10</span>, <span class="dv">3</span>, <span class="dv">20</span>, <span class="op">-</span><span class="dv">4</span>])</span>
|
||||
<span id="cb4-2"><a href="#cb4-2"></a>[<span class="op">-</span><span class="dv">4</span>, <span class="dv">3</span>, <span class="dv">10</span>, <span class="dv">20</span>]</span>
|
||||
<span id="cb4-3"><a href="#cb4-3"></a><span class="op">>>></span> <span class="bu">sorted</span>({<span class="dv">10</span>, <span class="dv">3</span>, <span class="dv">20</span>, <span class="op">-</span><span class="dv">4</span>}) <span class="co"># Works with sets, too!</span></span>
|
||||
<span id="cb4-4"><a href="#cb4-4"></a>[<span class="op">-</span><span class="dv">4</span>, <span class="dv">3</span>, <span class="dv">10</span>, <span class="dv">20</span>]</span></code></pre></div></li>
|
||||
<li><p>The <code>max</code> function is a bit special, because there are two ways it can be used. When it is called with two or more inputs, those inputs must be numeric, and in this case <code>max</code> returns the largest one.</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">>>></span> <span class="bu">max</span>(<span class="dv">2</span>, <span class="dv">3</span>)</span>
|
||||
<span id="cb5-2"><a href="#cb5-2"></a><span class="dv">3</span></span>
|
||||
<span id="cb5-3"><a href="#cb5-3"></a><span class="op">>>></span> <span class="bu">max</span>(<span class="op">-</span><span class="dv">2</span>, <span class="dv">10</span>, <span class="dv">3</span>, <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">7</span>)</span>
|
||||
<span id="cb5-4"><a href="#cb5-4"></a><span class="dv">10</span></span></code></pre></div>
|
||||
<p>But <code>max</code> can also be called with just a single argument, a non-empty collection of numbers. In this case, <code>max</code> returns the largest number in the collection.</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">>>></span> <span class="bu">max</span>({<span class="dv">2</span>, <span class="dv">3</span>})</span>
|
||||
<span id="cb6-2"><a href="#cb6-2"></a><span class="dv">3</span></span>
|
||||
<span id="cb6-3"><a href="#cb6-3"></a><span class="op">>>></span> <span class="bu">max</span>([<span class="op">-</span><span class="dv">2</span>, <span class="dv">10</span>, <span class="dv">3</span>, <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">7</span>])</span>
|
||||
<span id="cb6-4"><a href="#cb6-4"></a><span class="dv">10</span></span></code></pre></div></li>
|
||||
<li><p>The <code>range</code> function we saw in the last chapter takes in two integers <code>start</code> and <code>stop</code> and returns a value representing a range of consecutive numbers between <code>start</code> and <code>stop - 1</code>, inclusive. For example, <code>range(5, 10)</code> represents the sequence of numbers <code>5</code>, <code>6</code>, <code>7</code>, <code>8</code>, <code>9</code>. If <code>start >= end</code>, then <code>range(start, end)</code> represents an <em>empty</em> sequence.</p></li>
|
||||
</ul>
|
||||
<h3 id="one-special-function-type">One special function: <code>type</code></h3>
|
||||
<p>The last built-in function we’ll cover in this section is <code>type</code>, which takes <em>any</em> Python value and returns its type. Let’s check it out:<label for="sn-2" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-2" class="margin-toggle"/><span class="sidenote"> The term <code>class</code> that you see returned here is the name Python uses to refer to mean “data type”. More on this later.</span></p>
|
||||
<div class="sourceCode" id="cb7"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1"></a><span class="op">>>></span> <span class="bu">type</span>(<span class="dv">3</span>)</span>
|
||||
<span id="cb7-2"><a href="#cb7-2"></a><span class="op"><</span><span class="kw">class</span> <span class="st">'int'</span><span class="op">></span></span>
|
||||
<span id="cb7-3"><a href="#cb7-3"></a><span class="op">>>></span> <span class="bu">type</span>(<span class="fl">3.0</span>)</span>
|
||||
<span id="cb7-4"><a href="#cb7-4"></a><span class="op"><</span><span class="kw">class</span> <span class="st">'float'</span><span class="op">></span></span>
|
||||
<span id="cb7-5"><a href="#cb7-5"></a><span class="op">>>></span> <span class="bu">type</span>(<span class="st">'David'</span>)</span>
|
||||
<span id="cb7-6"><a href="#cb7-6"></a><span class="op"><</span><span class="kw">class</span> <span class="st">'str'</span><span class="op">></span></span>
|
||||
<span id="cb7-7"><a href="#cb7-7"></a><span class="op">>>></span> <span class="bu">type</span>([<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>])</span>
|
||||
<span id="cb7-8"><a href="#cb7-8"></a><span class="op"><</span><span class="kw">class</span> <span class="st">'list'</span><span class="op">></span></span>
|
||||
<span id="cb7-9"><a href="#cb7-9"></a><span class="op">>>></span> <span class="bu">type</span>({<span class="st">'a'</span>: <span class="dv">1</span>, <span class="st">'b'</span>: <span class="dv">2</span>})</span>
|
||||
<span id="cb7-10"><a href="#cb7-10"></a><span class="op"><</span><span class="kw">class</span> <span class="st">'dict'</span><span class="op">></span></span></code></pre></div>
|
||||
<p>If you’re ever unsure about the type of a particular value or variable, you can always call <code>type</code> on it to check!</p>
|
||||
<h3 id="nested-function-calls">Nested function calls</h3>
|
||||
<p>Just like other Python expressions, you can write function calls within each other, or mix them with other kinds of expressions.</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">>>></span> <span class="bu">max</span>(<span class="bu">abs</span>(<span class="op">-</span><span class="dv">100</span>), <span class="dv">15</span>, <span class="dv">3</span> <span class="op">*</span> <span class="dv">20</span>)</span>
|
||||
<span id="cb8-2"><a href="#cb8-2"></a><span class="dv">100</span></span></code></pre></div>
|
||||
<p>However, just as we saw with deeply nested arithmetic expressions earlier, too much nesting can make Python expressions difficult to read and understand, and so it is a good practice to break down a complex series of function calls into intermediate steps using variables:</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">>>></span> v1 <span class="op">=</span> <span class="bu">abs</span>(<span class="op">-</span><span class="dv">100</span>)</span>
|
||||
<span id="cb9-2"><a href="#cb9-2"></a><span class="op">>>></span> v2 <span class="op">=</span> <span class="dv">15</span></span>
|
||||
<span id="cb9-3"><a href="#cb9-3"></a><span class="op">>>></span> v3 <span class="op">=</span> <span class="dv">3</span> <span class="op">*</span> <span class="dv">20</span></span>
|
||||
<span id="cb9-4"><a href="#cb9-4"></a><span class="op">>>>></span> <span class="bu">max</span>(v1, v2, v3)</span>
|
||||
<span id="cb9-5"><a href="#cb9-5"></a><span class="dv">100</span></span></code></pre></div>
|
||||
<h2 id="methods-functions-belonging-to-data-types">Methods: functions belonging to data types</h2>
|
||||
<p>The built-in functions we’ve studied so far all have one interesting property in common: they can all be given arguments of at least two different data types: for example, <code>abs</code> works with both <code>int</code> and <code>float</code>, <code>len</code> and <code>sorted</code> work with <code>set</code> <code>list</code> (and others), and <code>type</code> works with values of absolutely any data type. In fact, this is true for almost all built-in functions in Python, as part of the design of the language itself.</p>
|
||||
<p>However, Python’s data types also support operations that are specific that that particular data type: for example, there are many operations we can perform on strings that a specific to textual data, and that wouldn’t make sense for other data types.</p>
|
||||
<p>Python comes with many functions that perform these operations, but handles them a bit differently than the built-in functions we’ve seen so far. A function that is defined as part of a data type is called a <strong>method</strong>.<label for="sn-3" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-3" class="margin-toggle"/><span class="sidenote"> The terms <em>function</em> and <em>method</em> are sometimes blurred in programming, particularly from language to language, but for us these terms have precise and distinct meanings!</span> All methods are functions, but not all functions are methods. For example, the built-in functions we looked at above are all <em>not</em> methods. We refer to functions that are not methods as <strong>top-level functions</strong>. We’ll see later how we define functions and methods in Python, but for now let’s look at a few examples of methods.</p>
|
||||
<p>One <code>str</code> method in Python is called <code>lower</code>, and has the effect of taking a string like <code>'David'</code> and returning a new string with all uppercase letters turned into lowercase: <code>'david'</code>. To call this method, we refer to it by first specifying the name of the data type it belongs to (<code>str</code>), followed by a period (<code>.</code>) and then the name of the method.</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">>>></span> <span class="bu">str</span>.lower(<span class="st">'David'</span>)</span>
|
||||
<span id="cb10-2"><a href="#cb10-2"></a><span class="co">'david'</span></span></code></pre></div>
|
||||
<p>Here are a few other examples of methods for different data types, just to give you a sense of the kinds of operations that are allowed.</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">>>></span> <span class="bu">str</span>.split(<span class="st">'David wuz hear'</span>) <span class="co"># str.split splits a string into words</span></span>
|
||||
<span id="cb11-2"><a href="#cb11-2"></a>[<span class="st">'David'</span>, <span class="st">'wuz'</span>, <span class="st">'hear'</span>]</span>
|
||||
<span id="cb11-3"><a href="#cb11-3"></a><span class="op">>>></span> <span class="bu">set</span>.union({<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>}, {<span class="dv">2</span>, <span class="dv">10</span>, <span class="dv">20</span>}) <span class="co"># set.union performs the set union operation</span></span>
|
||||
<span id="cb11-4"><a href="#cb11-4"></a>{<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">20</span>, <span class="dv">10</span>}</span>
|
||||
<span id="cb11-5"><a href="#cb11-5"></a><span class="op">>>></span> <span class="bu">list</span>.count([<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">4</span>, <span class="dv">2</span>], <span class="dv">2</span>) <span class="co"># list.count counts the number of times a value appears in a list</span></span>
|
||||
<span id="cb11-6"><a href="#cb11-6"></a><span class="dv">3</span> <span class="co"># (remember, a list can have duplicates!)</span></span></code></pre></div>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li>CSC108 videos: Functions (<a href="https://youtu.be/gbyIl_NFOaQ">Part 1</a>, <a href="https://youtu.be/gH7R03lh5PM">Part 2</a>, <a href="https://youtu.be/DvbCym5XHAs">Part 3</a>)</li>
|
||||
<li><a href="../A-python-builtins/02-builtins.md">Appendix A.1 Python Built-In Function Reference</a></li>
|
||||
<li><a href="../A-python-builtins/02-types.md">Appendix A.2 Python Built-In Data Types Reference</a> (includes descriptions of methods)</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,300 @@
|
||||
<!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>2.2 Defining Our Own Functions</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">2.2 Defining Our Own Functions</h1>
|
||||
</header>
|
||||
<section>
|
||||
<p>Python provides many built-in top-level functions and methods for us, but as we start writing more code, it is essential for us to be able to create our own functions specific to the problem we are solving. In this section, we’ll learn how to define our own top-level functions in Python.<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> And later on, we’ll study how to define our own data types and methods as well.</span></p>
|
||||
<p>First, let’s recall how we define a function in mathematics. We first specify the function name, domain, and codomain: for example, <span class="math inline">\(f: \R \to \R\)</span>. Then, we write the function header and body, usually in a single line: for example, <span class="math inline">\(f(x) = x^2\)</span>. We do this so often in mathematics that we often take parts of this for granted, for example leaving out the domain/codomain specification, and usually choosing <span class="math inline">\(f\)</span> as the function name and <span class="math inline">\(x\)</span> as the parameter name. However, the functions we’ll implement in Python are much more diverse, and so it will be important to be explicit in every part of this process.</p>
|
||||
<h2 id="defining-a-python-function">Defining a Python function</h2>
|
||||
<p>Here is the complete definition of a “squaring” function in Python. Take a moment to read through the whole definition, and then continue reading to learn about this definition’s different parts.</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> square(x: <span class="bu">float</span>) <span class="op">-></span> <span class="bu">float</span>:</span>
|
||||
<span id="cb1-2"><a href="#cb1-2"></a> <span class="co">"""Return x squared.</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3"></a></span>
|
||||
<span id="cb1-4"><a href="#cb1-4"></a><span class="co"> >>> square(3.0)</span></span>
|
||||
<span id="cb1-5"><a href="#cb1-5"></a><span class="co"> 9.0</span></span>
|
||||
<span id="cb1-6"><a href="#cb1-6"></a><span class="co"> >>> square(2.5)</span></span>
|
||||
<span id="cb1-7"><a href="#cb1-7"></a><span class="co"> 6.25</span></span>
|
||||
<span id="cb1-8"><a href="#cb1-8"></a><span class="co"> """</span></span>
|
||||
<span id="cb1-9"><a href="#cb1-9"></a> <span class="cf">return</span> x <span class="op">**</span> <span class="dv">2</span></span></code></pre></div>
|
||||
<p>This function definition is the most complex form of Python code we’ve seen so far, so let’s break this down part by part.</p>
|
||||
<ol type="1">
|
||||
<li><p>The first line, <code>def square(x: float) -> float:</code> is called the <strong>function header</strong>. Its purpose is to convey the following pieces of information:</p>
|
||||
<ul>
|
||||
<li>The function’s name (<code>square</code>).</li>
|
||||
<li>The number and type of arguments the function expects. A <strong>parameter</strong> is a variable in a function definition that refers to a argument when the function is called. In this example, the function has one parameter with name <code>x</code> and type <code>float</code>.</li>
|
||||
<li>The function’s <strong>return type</strong>, which is the type following the <code>-></code>, <code>float</code>.<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> In this example, the function’s parameter and return type are the same, but this won’t always be the case. </span></li>
|
||||
</ul>
|
||||
<p>The syntax for a function header for a unary function is:</p>
|
||||
<div class="sourceCode" id="cb2"><pre class="sourceCode python fullwidth"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">def</span> <span class="op"><</span>function_name<span class="op">></span>(<span class="op"><</span>parameter_name<span class="op">></span>: <span class="op"><</span>parameter_type<span class="op">></span>) <span class="op">-></span> <span class="op"><</span>return_type<span class="op">></span>:</span></code></pre></div>
|
||||
<p>Compared to our mathematical version, there are two main differences. First, we chose the name <code>square</code> rather than <code>f</code> as the function name; in Python, we will always pick descriptive names for our functions rather than relying on the conventional “<span class="math inline">\(f\)</span>”. And second, we use data types to specify the function domain and codomain: the code <code>x: float</code> specifies that the parameter <code>x</code> must be a <code>float</code> value, and the code <code>-> float</code> specifies that this function always returns a <code>float</code> value.</p>
|
||||
<p>We can express this restriction in an analogous way to <span class="math inline">\(f: \R \to \R\)</span> by writing <code>float -> float</code>; we call <code>float -> float</code> the <strong>type contract</strong> of the <code>square</code> function.</p></li>
|
||||
<li><p>The next seven lines, which start and end with triple-quotes (<code>"""</code>), is called the <strong>function docstring</strong>. This is another way of writing a comment in Python: text that is meant to be read by humans, but not executed as Python code. The goal of the function docstring is to communicate what the function does.</p>
|
||||
<p>The first part of the docstring, <code>Return x squared.</code>, is an English description of the function. The second part might look a bit funny at first, since it seems like Python code:<label for="sn-2" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-2" class="margin-toggle"/><span class="sidenote">Or more precisely, it looks like the Python console!</span></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">>>></span> square(<span class="fl">3.0</span>)</span>
|
||||
<span id="cb3-2"><a href="#cb3-2"></a><span class="fl">9.0</span></span>
|
||||
<span id="cb3-3"><a href="#cb3-3"></a><span class="op">>>></span> square(<span class="fl">2.5</span>)</span>
|
||||
<span id="cb3-4"><a href="#cb3-4"></a><span class="fl">6.25</span></span></code></pre></div>
|
||||
<p>This part of the docstring shows example uses of the function, just like the examples we showed of built-in functions in the previous section. You can read the first example literally as “when you type <code>square(3.0)</code> into the Python console, <code>9.0</code> is returned” and the second as “when you type <code>square(2.5)</code> into the Python console, <code>6.25</code> is returned”. These examples are called <strong>doctest examples</strong>, for a reason we’ll see in a future section. While a English description may technically be enough to specify the function’s behaviour, doctest examples are invaluable for aiding understanding of the function behaviour (which is why we use them in teaching as well!).</p>
|
||||
<p>The function docstring is indented inside the function header, as a visual indicator that it is part of the overall function definition.<label for="sn-3" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-3" class="margin-toggle"/><span class="sidenote"> Unlike many other programming languages, this kind of indentation in Python is <strong>mandatory</strong> rather than merely recommended. Python’s designers felt strongly enough about indentation improving readability of Python programs that they put indentation requirements like this into the language itself.</span></p></li>
|
||||
<li><p>The final line, <code>return x ** 2</code>, is called the <strong>body</strong> of the function, and is the code that is executed when the function is called. Like the function docstring, the function body is also indented so that it is “inside” the function definition.</p>
|
||||
<p>This code uses another keyword, <code>return</code>, which signals a new kind of statement: the <strong>return statement</strong>, which has the form:</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="cf">return</span> <span class="op"><</span>expression<span class="op">></span></span></code></pre></div>
|
||||
<p>When a return statement is executed, the following happens:</p>
|
||||
<ol type="1">
|
||||
<li>The <code><expression></code> is evaluated, producing a value.</li>
|
||||
<li>That value is then returned to wherever the function was called. No more code in the function body is executed after this point.</li>
|
||||
</ol></li>
|
||||
</ol>
|
||||
<h2 id="what-happens-when-a-function-is-called">What happens when a function is called?</h2>
|
||||
<p>In the previous section, we called built-in functions, and took for granted that they worked properly, without worrying about how they work. Now that we’re able to define our own functions, we are ready to fully understand what happens when a function is called.</p>
|
||||
<p>As an example, suppose we’ve defined <code>square</code> as above, and then call it in the Python console:</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">>>></span> square(<span class="fl">2.5</span>)</span></code></pre></div>
|
||||
<p>When we press Enter, the Python interpreter evaluates the function call by doing the following:</p>
|
||||
<ol type="1">
|
||||
<li>Evaluate the argument <code>2.5</code>, and then assign <code>2.5</code> to the function parameter <code>x</code>.</li>
|
||||
<li>Evaluate the body of the <code>square</code> function, by doing:
|
||||
<ol type="a">
|
||||
<li>First evaluate <code>x ** 2</code>, which is <code>6.25</code> (since <code>x</code> refers to the value <code>2.5</code>).</li>
|
||||
<li>Then stop executing the function body, and return the value <code>6.25</code> back to the Python console.</li>
|
||||
</ol></li>
|
||||
<li>The function call <code>square(2.5)</code> evaluates to <code>6.25</code>, and this is displayed on the screen.</li>
|
||||
</ol>
|
||||
<p>As we observed in the previous section, we can combine multiple function calls within a single expression. What happens when we call <code>square</code> twice in the same expression? For example:</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">>>></span> square(<span class="fl">2.5</span>) <span class="op">+</span> square(<span class="op">-</span><span class="fl">1.0</span>)</span></code></pre></div>
|
||||
<p>We can step through this as well; notice how we’ve duplicated the text from before to illustrate the similarities between calling <code>square(2.5)</code> and <code>-square(-1.0)</code>.</p>
|
||||
<ol type="1">
|
||||
<li>Python evaluates the operands to <code>+</code> in left-to-right order, so evaluate <code>square(2.5)</code> first.
|
||||
<ol type="i">
|
||||
<li>Evaluate <code>2.5</code>, and then assign <code>2.5</code> to the function parameter <code>x</code>.</li>
|
||||
<li>Evaluate the body of the <code>square</code> function, by doing:
|
||||
<ol type="a">
|
||||
<li>First evaluate <code>x ** 2</code>, which is <code>6.25</code> (since <code>x</code> refers to <code>2.5</code>).</li>
|
||||
<li>Then stop executing the function body, and return the value <code>6.25</code> back to the Python console.</li>
|
||||
</ol></li>
|
||||
</ol></li>
|
||||
<li>Nothing is displayed yet! There’s still <code>square(-1.0)</code> to be evaluated.
|
||||
<ol type="i">
|
||||
<li>Evaluate <code>-1.0</code>, and then assign <code>-1.0</code> to the function parameter <code>x</code>.</li>
|
||||
<li>Evaluate the body of the <code>square</code> function, by doing:
|
||||
<ol type="a">
|
||||
<li>First evaluate <code>x ** 2</code>, which is <code>1.0</code> (since <code>x</code> refers to <code>-1.0</code>).</li>
|
||||
<li>Then stop executing the function body, and return the value <code>1.0</code> back to the Python console.</li>
|
||||
</ol></li>
|
||||
</ol></li>
|
||||
<li>Now the expression to evaluate has been simplified to <code>6.25 + 1.0</code>, which evaluates to <code>7.25</code>. This value is displayed on the screen.</li>
|
||||
</ol>
|
||||
<h2 id="defining-functions-in-files">Defining functions in files</h2>
|
||||
<p>While it is possible to define functions directly in the Python console, this isn’t a good approach: every time we restart the Python console, we lose all our previous definitions. So instead, we save functions in files so that we can reuse them across multiple sessions in the Python console (and in other files).</p>
|
||||
<p>For example, suppose we have the following file called <code>my_functions.py</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="kw">def</span> square(x: <span class="bu">float</span>) <span class="op">-></span> <span class="bu">float</span>:</span>
|
||||
<span id="cb7-2"><a href="#cb7-2"></a> <span class="co">"""Return x squared.</span></span>
|
||||
<span id="cb7-3"><a href="#cb7-3"></a></span>
|
||||
<span id="cb7-4"><a href="#cb7-4"></a><span class="co"> >>> square(3.0)</span></span>
|
||||
<span id="cb7-5"><a href="#cb7-5"></a><span class="co"> 9.0</span></span>
|
||||
<span id="cb7-6"><a href="#cb7-6"></a><span class="co"> >>> square(2.5)</span></span>
|
||||
<span id="cb7-7"><a href="#cb7-7"></a><span class="co"> 6.25</span></span>
|
||||
<span id="cb7-8"><a href="#cb7-8"></a><span class="co"> """</span></span>
|
||||
<span id="cb7-9"><a href="#cb7-9"></a> <span class="cf">return</span> x <span class="op">**</span> <span class="dv">2</span></span></code></pre></div>
|
||||
<p>In PyCharm, we can right-click and select “Run File in Python Console”. This will start the Python console and run our file, which then allows us to call our function <code>square</code> just like any built-in function:</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">>>></span> square(<span class="fl">3.0</span>)</span>
|
||||
<span id="cb8-2"><a href="#cb8-2"></a><span class="fl">9.0</span></span></code></pre></div>
|
||||
<p><video src="videos/running_file_demo.webm" controls=""><a href="videos/running_file_demo.webm">Demo of running Python file in PyCharm</a></video><br />
|
||||
</p>
|
||||
<h2 id="defining-functions-with-multiple-parameters">Defining functions with multiple parameters</h2>
|
||||
<p>Let’s now look at a more complex example that will illustrate a function definition that takes in more than one parameter.</p>
|
||||
<p>Recall the <a href="../01-working-with-data/04-variables.html">distance formula from Section 1.4</a> to calculate the distance between two points <span class="math inline">\((x_1, y_1), (x_2, y_2)\)</span> in the Cartesian plane: <span class="math display">\[d = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}\]</span></p>
|
||||
<p>We’ll now write a function in Python that calculates this formula. This function will take two inputs, where each input is a <code>tuple</code> of two <code>float</code>s, representing the <span class="math inline">\(x\)</span>- and <span class="math inline">\(y\)</span>-coordinates of each point. When we define a function with multiple parameters, we write the name and type of each parameter using the same format we saw earlier, with parameters separated by commas from each other. Here is the function header and docstring:</p>
|
||||
<div class="sourceCode" id="cb9"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1"></a><span class="kw">def</span> calculate_distance(p1: <span class="bu">tuple</span>, p2: <span class="bu">tuple</span>) <span class="op">-></span> <span class="bu">float</span>:</span>
|
||||
<span id="cb9-2"><a href="#cb9-2"></a> <span class="co">"""Return the distance between points p1 and p2.</span></span>
|
||||
<span id="cb9-3"><a href="#cb9-3"></a></span>
|
||||
<span id="cb9-4"><a href="#cb9-4"></a><span class="co"> p1 and p2 are tuples of the form (x, y), where the x- and y-coordinates are points.</span></span>
|
||||
<span id="cb9-5"><a href="#cb9-5"></a></span>
|
||||
<span id="cb9-6"><a href="#cb9-6"></a><span class="co"> >>> calculate_distance((0, 0), (3.0, 4.0))</span></span>
|
||||
<span id="cb9-7"><a href="#cb9-7"></a><span class="co"> 5.0</span></span>
|
||||
<span id="cb9-8"><a href="#cb9-8"></a><span class="co"> """</span></span></code></pre></div>
|
||||
<p>In order to use the above formula, we need to extract the coordinates from each point. This is a good reminder of <code>tuple</code> indexing, and the fact that function bodies can consist of more than one statement.<label for="sn-4" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-4" class="margin-toggle"/><span class="sidenote"> Remember: the function body’s statements are executed one at a time until a <code>return</code> statement is executed.</span></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="co"># The start of the body of calculate_distance</span></span>
|
||||
<span id="cb10-2"><a href="#cb10-2"></a> x1 <span class="op">=</span> p1[<span class="dv">0</span>]</span>
|
||||
<span id="cb10-3"><a href="#cb10-3"></a> y1 <span class="op">=</span> p1[<span class="dv">1</span>]</span>
|
||||
<span id="cb10-4"><a href="#cb10-4"></a> x2 <span class="op">=</span> p2[<span class="dv">0</span>]</span>
|
||||
<span id="cb10-5"><a href="#cb10-5"></a> y2 <span class="op">=</span> p2[<span class="dv">1</span>]</span></code></pre></div>
|
||||
<p>Now that we have the four coordinates, we can apply the above formula and return the result</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="co"># Continuing the function body</span></span>
|
||||
<span id="cb11-2"><a href="#cb11-2"></a> <span class="cf">return</span> ((x1 <span class="op">-</span> x2) <span class="op">**</span> <span class="dv">2</span> <span class="op">+</span> (y1 <span class="op">-</span> y2) <span class="op">**</span> <span class="dv">2</span>) <span class="op">**</span> <span class="fl">0.5</span></span></code></pre></div>
|
||||
<p>Putting this all together, we have:</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="kw">def</span> calculate_distance(p1: <span class="bu">tuple</span>, p2: <span class="bu">tuple</span>) <span class="op">-></span> <span class="bu">float</span>:</span>
|
||||
<span id="cb12-2"><a href="#cb12-2"></a> <span class="co">"""Return the distance between points p1 and p2.</span></span>
|
||||
<span id="cb12-3"><a href="#cb12-3"></a></span>
|
||||
<span id="cb12-4"><a href="#cb12-4"></a><span class="co"> p1 and p2 are tuples of the form (x, y), where the x- and y-coordinates are points.</span></span>
|
||||
<span id="cb12-5"><a href="#cb12-5"></a></span>
|
||||
<span id="cb12-6"><a href="#cb12-6"></a><span class="co"> >>> calculate_distance((0, 0), (3.0, 4.0))</span></span>
|
||||
<span id="cb12-7"><a href="#cb12-7"></a><span class="co"> 5.0</span></span>
|
||||
<span id="cb12-8"><a href="#cb12-8"></a><span class="co"> """</span></span>
|
||||
<span id="cb12-9"><a href="#cb12-9"></a> x1 <span class="op">=</span> p1[<span class="dv">0</span>]</span>
|
||||
<span id="cb12-10"><a href="#cb12-10"></a> y1 <span class="op">=</span> p1[<span class="dv">1</span>]</span>
|
||||
<span id="cb12-11"><a href="#cb12-11"></a> x2 <span class="op">=</span> p2[<span class="dv">0</span>]</span>
|
||||
<span id="cb12-12"><a href="#cb12-12"></a> y2 <span class="op">=</span> p2[<span class="dv">1</span>]</span>
|
||||
<span id="cb12-13"><a href="#cb12-13"></a> <span class="cf">return</span> ((x1 <span class="op">-</span> x2) <span class="op">**</span> <span class="dv">2</span> <span class="op">+</span> (y1 <span class="op">-</span> y2) <span class="op">**</span> <span class="dv">2</span>) <span class="op">**</span> <span class="fl">0.5</span></span></code></pre></div>
|
||||
<h2 id="function-reuse">Function reuse</h2>
|
||||
<p>Our above function body is perfectly correct, but you might notice that the <code>** 2</code> expressions exactly mimic the body of the first function we defined in this section: <code>square</code>. And so we can reuse the <code>square</code> function inside the body of <code>calculate_distance</code>:</p>
|
||||
<div class="sourceCode" id="cb13"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1"></a><span class="kw">def</span> calculate_distance(p1: <span class="bu">tuple</span>, p2: <span class="bu">tuple</span>) <span class="op">-></span> <span class="bu">float</span>:</span>
|
||||
<span id="cb13-2"><a href="#cb13-2"></a> <span class="co">"""Return the distance between points p1 and p2.</span></span>
|
||||
<span id="cb13-3"><a href="#cb13-3"></a></span>
|
||||
<span id="cb13-4"><a href="#cb13-4"></a><span class="co"> p1 and p2 are tuples of the form (x, y), where the x- and y-coordinates are points.</span></span>
|
||||
<span id="cb13-5"><a href="#cb13-5"></a></span>
|
||||
<span id="cb13-6"><a href="#cb13-6"></a><span class="co"> >>> calculate_distance((0, 0), (3.0, 4.0))</span></span>
|
||||
<span id="cb13-7"><a href="#cb13-7"></a><span class="co"> 5.0</span></span>
|
||||
<span id="cb13-8"><a href="#cb13-8"></a><span class="co"> """</span></span>
|
||||
<span id="cb13-9"><a href="#cb13-9"></a> x1 <span class="op">=</span> p1[<span class="dv">0</span>]</span>
|
||||
<span id="cb13-10"><a href="#cb13-10"></a> y1 <span class="op">=</span> p1[<span class="dv">1</span>]</span>
|
||||
<span id="cb13-11"><a href="#cb13-11"></a> x2 <span class="op">=</span> p2[<span class="dv">0</span>]</span>
|
||||
<span id="cb13-12"><a href="#cb13-12"></a> y2 <span class="op">=</span> p2[<span class="dv">1</span>]</span>
|
||||
<span id="cb13-13"><a href="#cb13-13"></a> <span class="cf">return</span> (square(x1 <span class="op">-</span> x2) <span class="op">+</span> square(y1 <span class="op">-</span> y2)) <span class="op">**</span> <span class="fl">0.5</span></span></code></pre></div>
|
||||
<p>This example of function reuse is quite small, but as our programs grow larger, it will be essential to organize our code into different functions. We’ll explore this idea in more detail, and other principles of good function and program design, throughout this course.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li>CSC108 videos: Defining Functions (<a href="https://www.youtube.com/watch?v=5xajzCaBWAs">Part 1</a>, <a href="https://www.youtube.com/watch?v=8V9SQtHo-Z0">Part 2</a>)</li>
|
||||
<li>CSC108 videos: Docstrings and Function <code>help</code> (<a href="https://www.youtube.com/watch?v=4LDodz_Bwx0">Video</a>)</li>
|
||||
<li>CSC108 videos: Function Reuse (<a href="https://www.youtube.com/watch?v=H2mKu9Vfyxs">Part 1</a>, <a href="https://www.youtube.com/watch?v=c9o7Q81TqW0">Part 2</a>, <a href="https://www.youtube.com/watch?v=WvwDSMZW_r8">Example</a>)</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,608 @@
|
||||
<!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>2.3 Local Variables and Function Scope</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">2.3 Local Variables and Function Scope</h1>
|
||||
</header>
|
||||
<section>
|
||||
<p>One of the key purposes of functions is to separate different computations in a program, so that we don’t have to worry about them all at once. When we write our code in separate functions, we can focus on working with just a single function, and ignore the rest of the code in other functions.</p>
|
||||
<p>One way in which Python support this way of designing programs is through separating the variables in each functions so that <em>a function call can only access its own variables, but not variables defined within other functions</em>. In this section, we’ll explore how this works, learning more about how Python keep track of function calls and variables.</p>
|
||||
<h2 id="example-1-introducing-local-variable-scope">Example 1: introducing local variable scope</h2>
|
||||
<p>Consider the example from the previous section:</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> square(x: <span class="bu">float</span>) <span class="op">-></span> <span class="bu">float</span>:</span>
|
||||
<span id="cb1-2"><a href="#cb1-2"></a> <span class="co">"""Return x squared.</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3"></a></span>
|
||||
<span id="cb1-4"><a href="#cb1-4"></a><span class="co"> >>> square(3.0)</span></span>
|
||||
<span id="cb1-5"><a href="#cb1-5"></a><span class="co"> 9.0</span></span>
|
||||
<span id="cb1-6"><a href="#cb1-6"></a><span class="co"> >>> square(2.5)</span></span>
|
||||
<span id="cb1-7"><a href="#cb1-7"></a><span class="co"> 6.25</span></span>
|
||||
<span id="cb1-8"><a href="#cb1-8"></a><span class="co"> """</span></span>
|
||||
<span id="cb1-9"><a href="#cb1-9"></a> <span class="cf">return</span> x <span class="op">**</span> <span class="dv">2</span></span></code></pre></div>
|
||||
<p>The parameter <code>x</code> is a <em>variable</em> that is assigned a value based on when the function was called. Because this variable is only useful inside the function body, Python does not allow it to be accessible from outside the body. We say that <code>x</code> is a <strong>local variable</strong> of <code>square</code> because it is limited to the function body. Here is another way to put it, using an important new definition. The <strong>scope</strong> of a variable is the places in the code where that variable can be accessed. A <em>local variable</em> of a function is a variable whose scope is the body of that function.</p>
|
||||
<p>Let’s illustrate by first creating a variable in the Python console, and then calling <code>square</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">>>></span> n <span class="op">=</span> <span class="fl">10.0</span></span>
|
||||
<span id="cb2-2"><a href="#cb2-2"></a><span class="op">>>></span> result <span class="op">=</span> square(n <span class="op">+</span> <span class="fl">3.5</span>)</span></code></pre></div>
|
||||
<p>We know that when <code>square</code> is called, its argument expression <code>n + 3.5</code> is evaluated first, producing the value <code>13.5</code>, which is then assigned to the parameter <code>x</code>. Now let’s consider what the memory model looks like when the <code>return</code> statement is evaluated. A naive diagram would simply show the two variables <code>n</code> and <code>x</code> and their corresponding values:<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> We do not show <code>result</code> because it hasn’t been assigned a value yet; this only happens <em>after</em> <code>square</code> returns.</span></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>n</code></td>
|
||||
<td><code>10.0</code></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>x</code></td>
|
||||
<td><code>13.5</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p>But this is very misleading! In our memory model diagrams, we group the variables together based on whether they are introduced in the Python console or inside a function:</p>
|
||||
<div class="memory-model-values">
|
||||
<table>
|
||||
<caption><code>__main__</code> (console)</caption>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
<th>Variable</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><code>n</code></td>
|
||||
<td><code>10.0</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<caption><code>square</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>13.5</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p>We use the name <code>__main__</code> to label the table for variables defined in the Python console.<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> This is a special name in Python—more on this later.</span> Inside the body of <code>square</code>, the <em>only</em> variable that can be used is <code>x</code>, and the outside in the Python console, the <em>only</em> variable that can be used is <code>n</code>. This may seem a tricky at first, but these memory model diagrams are a good way to visualize what’s going on. At the point that the body of square is evaluated, only the “<code>square</code>” table in the memory model is active:</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>n</code></td>
|
||||
<td><code>10.0</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<caption><mark><strong><code>square</code></strong></mark></caption>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
<th>Variable</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><code>x</code></td>
|
||||
<td><code>13.5</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p>But after <code>square</code> returns and we’re back to the Python console, the “<code>square</code>” table is no longer accessible, and only the <code>__main__</code> table is active:</p>
|
||||
<div class="memory-model-values">
|
||||
<table>
|
||||
<caption><mark><strong><code>__main__</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>10.0</code></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>result</code></td>
|
||||
<td><code>182.25</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="memory-model-values-inactive">
|
||||
<table>
|
||||
<caption><code>square</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>13.5</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<p>Trying to access variable <code>x</code> from the Python console results in an error:</p>
|
||||
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1"></a><span class="op">>>></span> n <span class="op">=</span> <span class="fl">10.0</span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2"></a><span class="op">>>></span> square(n <span class="op">+</span> <span class="fl">3.5</span>)</span>
|
||||
<span id="cb3-3"><a href="#cb3-3"></a><span class="fl">182.25</span></span>
|
||||
<span id="cb3-4"><a href="#cb3-4"></a><span class="op">>>></span> x</span>
|
||||
<span id="cb3-5"><a href="#cb3-5"></a>Traceback (most recent call last):</span>
|
||||
<span id="cb3-6"><a href="#cb3-6"></a> File <span class="st">"<stdin>"</span>, line <span class="dv">1</span>, <span class="kw">in</span> <span class="op"><</span>module<span class="op">></span></span>
|
||||
<span id="cb3-7"><a href="#cb3-7"></a><span class="pp">NameError</span>: name <span class="st">'x'</span> <span class="kw">is</span> <span class="kw">not</span> defined</span></code></pre></div>
|
||||
<h2 id="example-2-duplicate-variable-names">Example 2: duplicate variable names</h2>
|
||||
<p>The principle of “separate tables” in our memory model applies even when we use the same variable name in two different places. Suppose we modify our example above to use <code>x</code> instead of <code>n</code> in the Python console:</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">>>></span> x <span class="op">=</span> <span class="fl">10.0</span></span>
|
||||
<span id="cb4-2"><a href="#cb4-2"></a><span class="op">>>></span> result <span class="op">=</span> square(x <span class="op">+</span> <span class="fl">3.5</span>)</span></code></pre></div>
|
||||
<p>Following the same reasoning as above, the argument expression <code>x + 3.5</code> is evaluated to produce <code>13.5</code>, which is then assigned to the parameter <code>x</code>. Does this modify the <code>x</code> variable in the Python console? No! They are different variables even though they share the same name.</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>10.0</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<caption><code>square</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>13.5</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p>We can confirm this after the function call is evaluated by checking the value of the original <code>x</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">>>></span> x <span class="op">=</span> <span class="fl">10.0</span></span>
|
||||
<span id="cb5-2"><a href="#cb5-2"></a><span class="op">>>></span> result <span class="op">=</span> square(x <span class="op">+</span> <span class="fl">3.5</span>)</span>
|
||||
<span id="cb5-3"><a href="#cb5-3"></a><span class="op">>>></span> result</span>
|
||||
<span id="cb5-4"><a href="#cb5-4"></a><span class="fl">182.25</span></span>
|
||||
<span id="cb5-5"><a href="#cb5-5"></a><span class="op">>>></span> x</span>
|
||||
<span id="cb5-6"><a href="#cb5-6"></a><span class="fl">10.0</span></span></code></pre></div>
|
||||
<p>Here is what our memory model looks like after <code>square</code> has returned:</p>
|
||||
<div class="memory-model-values">
|
||||
<table>
|
||||
<caption><mark><strong><code>__main__</code></strong></mark></caption>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
<th>Variable</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><code>x</code></td>
|
||||
<td><code>10.0</code></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>result</code></td>
|
||||
<td><code>182.25</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="memory-model-values-inactive">
|
||||
<table>
|
||||
<caption><code>square</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>13.5</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h2 id="example-3-not-accessing-another-functions-variables">Example 3: (not) accessing another function’s variables</h2>
|
||||
<p>Our last example in this section involves two functions, one of which calls the other:</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> square(x: <span class="bu">float</span>) <span class="op">-></span> <span class="bu">float</span>:</span>
|
||||
<span id="cb6-2"><a href="#cb6-2"></a> <span class="co">"""Return x squared.</span></span>
|
||||
<span id="cb6-3"><a href="#cb6-3"></a></span>
|
||||
<span id="cb6-4"><a href="#cb6-4"></a><span class="co"> >>> square(3.0)</span></span>
|
||||
<span id="cb6-5"><a href="#cb6-5"></a><span class="co"> 9.0</span></span>
|
||||
<span id="cb6-6"><a href="#cb6-6"></a><span class="co"> >>> square(2.5)</span></span>
|
||||
<span id="cb6-7"><a href="#cb6-7"></a><span class="co"> 6.25</span></span>
|
||||
<span id="cb6-8"><a href="#cb6-8"></a><span class="co"> """</span></span>
|
||||
<span id="cb6-9"><a href="#cb6-9"></a> <span class="cf">return</span> x <span class="op">**</span> <span class="dv">2</span></span>
|
||||
<span id="cb6-10"><a href="#cb6-10"></a></span>
|
||||
<span id="cb6-11"><a href="#cb6-11"></a></span>
|
||||
<span id="cb6-12"><a href="#cb6-12"></a><span class="kw">def</span> square_of_sum(numbers: <span class="bu">list</span>) <span class="op">-></span> <span class="bu">float</span>:</span>
|
||||
<span id="cb6-13"><a href="#cb6-13"></a> <span class="co">"""Return the square of the sum of the given numbers."""</span></span>
|
||||
<span id="cb6-14"><a href="#cb6-14"></a> total <span class="op">=</span> <span class="bu">sum</span>(numbers)</span>
|
||||
<span id="cb6-15"><a href="#cb6-15"></a> <span class="cf">return</span> square(total)</span></code></pre></div>
|
||||
<p>Let’s first call our new function <code>square_of_sum</code> in the Python console:</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">>>></span> nums <span class="op">=</span> [<span class="fl">1.5</span>, <span class="fl">2.5</span>]</span>
|
||||
<span id="cb7-2"><a href="#cb7-2"></a><span class="op">>>></span> result <span class="op">=</span> square_of_sum(nums)</span>
|
||||
<span id="cb7-3"><a href="#cb7-3"></a><span class="op">>>></span> result</span>
|
||||
<span id="cb7-4"><a href="#cb7-4"></a><span class="fl">16.0</span></span></code></pre></div>
|
||||
<p>We can trace what happens at three points when we call <code>square_of_sum</code>:</p>
|
||||
<table class="fullwidth" style="border: 1px solid black;">
|
||||
<tr>
|
||||
<td>
|
||||
Right before <code>square_of_sum</code> is called (from console)
|
||||
</td>
|
||||
<td>
|
||||
Right before <code>square</code> is called (from <code>square_of_sum</code>)
|
||||
</td>
|
||||
<td>
|
||||
Right before <code>square</code> returns
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="memory-model-values">
|
||||
<table>
|
||||
<caption><mark><strong><code>__main__</code></strong></mark></caption>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
<th>Variable</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><code>nums</code></td>
|
||||
<td><code>[1.5, 2.5]</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<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>nums</code></td>
|
||||
<td><code>[1.5, 2.5]</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<caption><mark><strong><code>square_of_sum</code></strong></mark></caption>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
<th>Variable</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><code>numbers</code></td>
|
||||
<td><code>[1.5, 2.5]</code></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>total</code></td>
|
||||
<td><code>4.0</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<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>nums</code></td>
|
||||
<td><code>[1.5, 2.5]</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<caption><code>square_of_sum</code></caption>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
<th>Variable</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><code>numbers</code></td>
|
||||
<td><code>[1.5, 2.5]</code></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>total</code></td>
|
||||
<td><code>4.0</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<caption><mark><strong><code>square</code></strong></mark></caption>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
<th>Variable</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><code>x</code></td>
|
||||
<td><code>4.0</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>From these diagrams, we see how the list <code>[1.5, 2.5]</code> is passed from the console to <code>square_of_sum</code>, and how the number <code>4.0</code> is passed from <code>square_of_sum</code> to <code>square</code>.</p>
|
||||
<p>Now suppose we wanted to do something a bit silly: have <code>square</code> access <code>total</code> instead of <code>x</code>. We know from our memory model that these variables should be assigned the same value, so the program’s behaviour shouldn’t change, right?</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> square(x: <span class="bu">float</span>) <span class="op">-></span> <span class="bu">float</span>:</span>
|
||||
<span id="cb8-2"><a href="#cb8-2"></a> <span class="co">"""Return x squared.</span></span>
|
||||
<span id="cb8-3"><a href="#cb8-3"></a></span>
|
||||
<span id="cb8-4"><a href="#cb8-4"></a><span class="co"> >>> square(3.0)</span></span>
|
||||
<span id="cb8-5"><a href="#cb8-5"></a><span class="co"> 9.0</span></span>
|
||||
<span id="cb8-6"><a href="#cb8-6"></a><span class="co"> >>> square(2.5)</span></span>
|
||||
<span id="cb8-7"><a href="#cb8-7"></a><span class="co"> 6.25</span></span>
|
||||
<span id="cb8-8"><a href="#cb8-8"></a><span class="co"> """</span></span>
|
||||
<span id="cb8-9"><a href="#cb8-9"></a> <span class="cf">return</span> total <span class="op">**</span> <span class="dv">2</span> <span class="co"># Now we're using total instead of x</span></span>
|
||||
<span id="cb8-10"><a href="#cb8-10"></a></span>
|
||||
<span id="cb8-11"><a href="#cb8-11"></a></span>
|
||||
<span id="cb8-12"><a href="#cb8-12"></a><span class="kw">def</span> square_of_sum(numbers: <span class="bu">list</span>) <span class="op">-></span> <span class="bu">float</span>:</span>
|
||||
<span id="cb8-13"><a href="#cb8-13"></a> <span class="co">"""Return the square of the sum of the given numbers."""</span></span>
|
||||
<span id="cb8-14"><a href="#cb8-14"></a> total <span class="op">=</span> <span class="bu">sum</span>(numbers)</span>
|
||||
<span id="cb8-15"><a href="#cb8-15"></a> <span class="cf">return</span> square(total)</span></code></pre></div>
|
||||
<p>Let’s see what happens when we try to call <code>square_of_sum</code> in the Python console now:</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">>>></span> nums <span class="op">=</span> [<span class="fl">1.5</span>, <span class="fl">2.5</span>]</span>
|
||||
<span id="cb9-2"><a href="#cb9-2"></a><span class="op">>>></span> square_of_sum(nums)</span>
|
||||
<span id="cb9-3"><a href="#cb9-3"></a>Traceback (most recent call last):</span>
|
||||
<span id="cb9-4"><a href="#cb9-4"></a> File <span class="st">"<input>"</span>, line <span class="dv">1</span>, <span class="kw">in</span> <span class="op"><</span>module<span class="op">></span></span>
|
||||
<span id="cb9-5"><a href="#cb9-5"></a> File <span class="st">"<input>"</span>, line <span class="dv">15</span>, <span class="kw">in</span> square_of_sum</span>
|
||||
<span id="cb9-6"><a href="#cb9-6"></a> File <span class="st">"<input>"</span>, line <span class="dv">9</span>, <span class="kw">in</span> square</span>
|
||||
<span id="cb9-7"><a href="#cb9-7"></a><span class="pp">NameError</span>: name <span class="st">'total'</span> <span class="kw">is</span> <span class="kw">not</span> defined</span></code></pre></div>
|
||||
<p>An error occurs! Let’s take a look at the state of memory when <code>square</code> is called (this is the same as above):</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>nums</code></td>
|
||||
<td><code>[1.5, 2.5]</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<caption><code>square_of_sum</code></caption>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
<th>Variable</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><code>numbers</code></td>
|
||||
<td><code>[1.5, 2.5]</code></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>total</code></td>
|
||||
<td><code>4.0</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<caption><mark><strong><code>square</code></strong></mark></caption>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
<th>Variable</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><code>x</code></td>
|
||||
<td><code>4.0</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p>Well, there is indeed both a <code>total</code> variable and an <code>x</code> variable with the same value, <code>4.0</code>. So why are we getting this error? Python’s rule for local scope: <em>a local variable can only be accessed in the function body it is defined</em>. Here, the statement <code>return total ** 2</code> is in the body of <code>square</code>, but attempts to access the local variable of a different function (<code>square_of_sum</code>). When the Python interpreter attempts to retrive the value of <code>total</code>, it looks only in the scope of <code>square</code>, and doesn’t find <code>total</code>, resulting in a <code>NameError</code>.</p>
|
||||
<p>The somewhat non-intuitive point about this behaviour is that this happens <em>even when <code>square_of_sum</code> is still active</em>. In our example, <code>square</code> is called from within <code>square_of_sum</code>, and so the variable <code>total</code> <em>does</em> exist in Python’s memory—it just isn’t accessible. While this might seem like a limitation of the language, it’s actually a good thing: this prevents you from accidentally using a variable from a completely different function when working on a function.</p>
|
||||
<h2 id="summary">Summary</h2>
|
||||
<p>In this section, we learned about how Python handles <em>local variables</em>, by making them accessible only from within the function that they are defined. Though we hope this makes intuitive sense, some of the details and diagrams we presented here were fairly technical. We recommend coming back to this section in a few days and reviewing this material, perhaps by explaining in your own words what’s happening in each example. You can also practice drawing this style of memory model diagram for future code that you write.</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,181 @@
|
||||
<!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>2.4 Importing Modules</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">2.4 Importing Modules</h1>
|
||||
</header>
|
||||
<section>
|
||||
<p>So far we have learned about Python’s built-in functions and various data type methods. But these form a small fraction of all the functions that the Python programming language comes with. Python’s other functions (and even other data types) are separated into various <strong>modules</strong>, which is another name we give to Python code files. Unlike the functions and data types we’ve seen so far, these modules are not automatically loaded when run the Python interpreter, as they contain more specialized functions and data types. So in this section, we’re going to learn how to load one of these modules and use their definitions.</p>
|
||||
<h2 id="the-import-statement">The <code>import</code> statement</h2>
|
||||
<p>To load a Python module, we use a piece of code called an <strong>import statement</strong>, which has the following syntax:</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="im">import</span> <span class="op"><</span>module_name<span class="op">></span></span></code></pre></div>
|
||||
<p>For example, here is how we could load the <code>math</code> module in the Python console:</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">>>></span> <span class="im">import</span> math</span></code></pre></div>
|
||||
<p>Like the other statements we’ve seen so far, import statements do not produce a value, but they do have an important effect. An <code>import</code> statement introduces a new variable (the name of the module being imported) that can be used to refer to all definitions from that module.</p>
|
||||
<p>For example, the <code>math</code> module defines a function <code>log2</code> which computes the base-2 logarithm of a number. To access this function, we use dot notation:<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> This notation is the same as accessing data type methods, but <code>log2</code> is <em>not</em> a method. It’s a top-level function, just one that happens to be defined in the <code>math</code> module.</span></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">>>></span> math.log2(<span class="dv">1024</span>)</span>
|
||||
<span id="cb3-2"><a href="#cb3-2"></a><span class="fl">10.0</span></span></code></pre></div>
|
||||
<p>What other functions are contained in the <code>math</code> module? We’ll make use of a few other later in this course, but if you’re curious you can call the special built-in function <code>dir</code> on the the module (or any other module) to see a list of functions and other variables defined in the module:</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">>>></span> <span class="bu">dir</span>(math)</span>
|
||||
<span id="cb4-2"><a href="#cb4-2"></a>[<span class="st">'__doc__'</span>, <span class="st">'__loader__'</span>, <span class="st">'__name__'</span>, <span class="st">'__package__'</span>, <span class="st">'__spec__'</span>, <span class="st">'acos'</span>, <span class="st">'acosh'</span>, <span class="st">'asin'</span>, <span class="st">'asinh'</span>, <span class="st">'atan'</span>, <span class="st">'atan2'</span>, <span class="st">'atanh'</span>, <span class="st">'ceil'</span>, <span class="st">'comb'</span>, <span class="st">'copysign'</span>, <span class="st">'cos'</span>, <span class="st">'cosh'</span>, <span class="st">'degrees'</span>, <span class="st">'dist'</span>, <span class="st">'e'</span>, <span class="st">'erf'</span>, <span class="st">'erfc'</span>, <span class="st">'exp'</span>, <span class="st">'expm1'</span>, <span class="st">'fabs'</span>, <span class="st">'factorial'</span>, <span class="st">'floor'</span>, <span class="st">'fmod'</span>, <span class="st">'frexp'</span>, <span class="st">'fsum'</span>, <span class="st">'gamma'</span>, <span class="st">'gcd'</span>, <span class="st">'hypot'</span>, <span class="st">'inf'</span>, <span class="st">'isclose'</span>, <span class="st">'isfinite'</span>, <span class="st">'isinf'</span>, <span class="st">'isnan'</span>, <span class="st">'isqrt'</span>, <span class="st">'ldexp'</span>, <span class="st">'lgamma'</span>, <span class="st">'log'</span>, <span class="st">'log10'</span>, <span class="st">'log1p'</span>, <span class="st">'log2'</span>, <span class="st">'modf'</span>, <span class="st">'nan'</span>, <span class="st">'perm'</span>, <span class="st">'pi'</span>, <span class="st">'pow'</span>, <span class="st">'prod'</span>, <span class="st">'radians'</span>, <span class="st">'remainder'</span>, <span class="st">'sin'</span>, <span class="st">'sinh'</span>, <span class="st">'sqrt'</span>, <span class="st">'tan'</span>, <span class="st">'tanh'</span>, <span class="st">'tau'</span>, <span class="st">'trunc'</span>]</span></code></pre></div>
|
||||
<p>Ignoring the first few with the double underscore, we see some familiar looking names, like <code>ceil</code>, <code>floor</code>, <code>pi</code>, and <code>sin</code>. We’ve linked to the documentation for the <code>math</code> module in the <a href="#references">References</a> section below.</p>
|
||||
<h2 id="the-datetime-module">The <code>datetime</code> module</h2>
|
||||
<p>Python comes with far more modules than we’ll have time to learn about in this course. However, just to illustrate the breadth of these modules, we’ll briefly introduce one more that will be useful occasionally throughout the course.</p>
|
||||
<p>The <code>datetime</code> module provides not just functions but new <em>data types</em> for representing time-based data. The first data type we’ll study here is <code>date</code>, which is a data type that represents a specific date.</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">>>></span> <span class="im">import</span> datetime</span>
|
||||
<span id="cb5-2"><a href="#cb5-2"></a><span class="op">>>></span> canada_day <span class="op">=</span> datetime.date(<span class="dv">1867</span>, <span class="dv">7</span>, <span class="dv">1</span>) <span class="co"># Create a new date</span></span>
|
||||
<span id="cb5-3"><a href="#cb5-3"></a><span class="op">>>></span> <span class="bu">type</span>(canada_day)</span>
|
||||
<span id="cb5-4"><a href="#cb5-4"></a><span class="op"><</span><span class="kw">class</span> <span class="st">'datetime.date'</span><span class="op">></span></span>
|
||||
<span id="cb5-5"><a href="#cb5-5"></a><span class="op">>>></span> term_start <span class="op">=</span> datetime.date(<span class="dv">2020</span>, <span class="dv">9</span>, <span class="dv">10</span>)</span>
|
||||
<span id="cb5-6"><a href="#cb5-6"></a><span class="op">>>></span> datetime.date.weekday(term_start) <span class="co"># Return the day of the week of the date</span></span>
|
||||
<span id="cb5-7"><a href="#cb5-7"></a><span class="dv">3</span> <span class="co"># 0 = Monday, 1 = Tuesday, etc.</span></span></code></pre></div>
|
||||
<p>Note the double use of dot notation in that last expression. <code>datetime.date</code> is the data type being accessed, and <code>.weekday</code> accesses a method of that data type.</p>
|
||||
<p>We can compare dates for equality using <code>==</code> and chronological order (e.g., <code><</code> for comparing one date comes before another). We can also subtract dates, which is pretty cool:</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">>>></span> term_start <span class="op">-</span> canada_day</span>
|
||||
<span id="cb6-2"><a href="#cb6-2"></a>datetime.timedelta(days<span class="op">=</span><span class="dv">55954</span>)</span></code></pre></div>
|
||||
<p>The difference between two dates is an instance of the <code>datetime.timedelta</code> data type, which is used to represent an interval of time. What the above expression tells us is that 55,954 days have passed between the first day of the fall semester and the day of Canada’s confederation.<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> Fun fact: Canada’s confederation first consisted of only four provinces: Ontario, Quebec, Nova Scotia, and New Brunswick.</span></p>
|
||||
<h2 id="theres-a-lot-of-python-out-theredont-worry">There’s a lot of Python out there—don’t worry!</h2>
|
||||
<p>Up to this point, we’ve covered several different data types, functions, methods, and now modules in Python. It might be starting to feel a bit daunting, and we wanted to take a moment to pause and look at the bigger picture. Our goal in showing you these elements of Python is not to overwhelm you, but instead to give you a taste of the language’s powerful computational capabilities. But this course is not about memorizing different functions, data types, and modules in Python! All throughout this course, you’ll have access to references and documentation that describe the functionality of these different elements, and will have lots of opportunities to practice using them. For now, all we want you to know is simply that these capabilities exist, how to experiment with them in the Python console, and how to look up information about them.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://docs.python.org/3/library/datetime.html"><code>datetime</code> module documentation</a></li>
|
||||
<li><a href="https://docs.python.org/3/library/math.html"><code>math</code> module documentation</a></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,224 @@
|
||||
<!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>2.5 The Function Design Recipe</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">2.5 The Function Design Recipe</h1>
|
||||
</header>
|
||||
<section>
|
||||
<p>Often when beginners are tasked with writing a program to solve a problem, they jump immediately to writing code. Doesn’t matter whether the code is correct or not, or even if they fully understand the problem: somehow the allure of filling up the screen with text is too tempting. So before we go further in our study of the Python programming language, we’ll introduce the <em>Function Design Recipe</em>, a structured process for taking a problem description and designing and implementing a function in Python to solve this problem.</p>
|
||||
<h2 id="the-function-design-recipe-by-example">The Function Design Recipe by example</h2>
|
||||
<p>Consider the following example problem: write a function to determine whether or not a number is even. We’ll use this example to illustrate the five steps of the Function Design Recipe.</p>
|
||||
<div class="fullwidth">
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 63%" />
|
||||
<col style="width: 36%" />
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><p><strong>1. Write example uses.</strong></p>
|
||||
<p>Pick a name for the function (often a verb or verb phrase). Sometimes a good name is a short answer to the question “What does your function do?” Write one or two examples of calls to your function and the expected returned values. Include an example of a standard case (as opposed to a tricky case). Put the examples inside a triple-quoted string that you’ve indented since it will be the beginning of the docstring.</p></td>
|
||||
<td><div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1"></a> <span class="co">"""</span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2"></a><span class="co"> >>> is_even(2)</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3"></a><span class="co"> True</span></span>
|
||||
<span id="cb1-4"><a href="#cb1-4"></a><span class="co"> >>> is_even(17)</span></span>
|
||||
<span id="cb1-5"><a href="#cb1-5"></a><span class="co"> False</span></span>
|
||||
<span id="cb1-6"><a href="#cb1-6"></a><span class="co"> """</span></span></code></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><p><strong>2. Write the function header.</strong></p>
|
||||
<p>Write the function header above the docstring (not indented). Choose a meaningful name for each parameter (often nouns). Include the type contract (the types of the parameters and return value).</p></td>
|
||||
<td><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> is_even(value: <span class="bu">int</span>) <span class="op">-></span> <span class="bu">bool</span>:</span>
|
||||
<span id="cb2-2"><a href="#cb2-2"></a> <span class="co">"""</span></span>
|
||||
<span id="cb2-3"><a href="#cb2-3"></a><span class="co"> >>> is_even(2)</span></span>
|
||||
<span id="cb2-4"><a href="#cb2-4"></a><span class="co"> True</span></span>
|
||||
<span id="cb2-5"><a href="#cb2-5"></a><span class="co"> >>> is_even(17)</span></span>
|
||||
<span id="cb2-6"><a href="#cb2-6"></a><span class="co"> False</span></span>
|
||||
<span id="cb2-7"><a href="#cb2-7"></a><span class="co"> """</span></span></code></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><p><strong>3. Write the function description.</strong></p>
|
||||
<p>Before the examples, add a description of what the function does and mention each parameter by name or otherwise make sure the purpose of each parameter is clear. Describe the return value.</p></td>
|
||||
<td><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> is_even(value: <span class="bu">int</span>) <span class="op">-></span> <span class="bu">bool</span>:</span>
|
||||
<span id="cb3-2"><a href="#cb3-2"></a> <span class="co">"""Return whether value is even.</span></span>
|
||||
<span id="cb3-3"><a href="#cb3-3"></a></span>
|
||||
<span id="cb3-4"><a href="#cb3-4"></a><span class="co"> >>> is_even(2)</span></span>
|
||||
<span id="cb3-5"><a href="#cb3-5"></a><span class="co"> True</span></span>
|
||||
<span id="cb3-6"><a href="#cb3-6"></a><span class="co"> >>> is_even(17)</span></span>
|
||||
<span id="cb3-7"><a href="#cb3-7"></a><span class="co"> False</span></span>
|
||||
<span id="cb3-8"><a href="#cb3-8"></a><span class="co"> """</span></span></code></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><p><strong>4. Implement the function body.</strong></p>
|
||||
<p>Write the body of the function and indent it to match the docstring. To help yourself write the body, review your examples from the first step and consider how you determined the return values. You may find it helpful to write a few more example calls.</p></td>
|
||||
<td><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> is_even(value: <span class="bu">int</span>) <span class="op">-></span> <span class="bu">bool</span>:</span>
|
||||
<span id="cb4-2"><a href="#cb4-2"></a> <span class="co">"""Return whether value is even.</span></span>
|
||||
<span id="cb4-3"><a href="#cb4-3"></a></span>
|
||||
<span id="cb4-4"><a href="#cb4-4"></a><span class="co"> >>> is_even(2)</span></span>
|
||||
<span id="cb4-5"><a href="#cb4-5"></a><span class="co"> True</span></span>
|
||||
<span id="cb4-6"><a href="#cb4-6"></a><span class="co"> >>> is_even(17)</span></span>
|
||||
<span id="cb4-7"><a href="#cb4-7"></a><span class="co"> False</span></span>
|
||||
<span id="cb4-8"><a href="#cb4-8"></a><span class="co"> """</span></span>
|
||||
<span id="cb4-9"><a href="#cb4-9"></a> <span class="cf">return</span> value <span class="op">%</span> <span class="dv">2</span> <span class="op">==</span> <span class="dv">0</span></span></code></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><p><strong>5. Test the function.</strong></p>
|
||||
<p>Test your function on all your example cases including any additional cases you created in the previous step. Additionally, try it on extra tricky or corner cases.</p>
|
||||
<p>One simple way to test your function is by calling it in the Python console. In the next section, we’ll discuss more powerful ways of testing your code.</p>
|
||||
<p>If you encounter any errors/incorrect return values, first make sure that your tests are correct, and then go back to Step 4 and try to identify and fix any possible errors in your code. This is called <em>debugging</em> your code, a process we’ll discuss throughout this course.</p></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<h2 id="the-importance-of-documenting-your-functions">The importance of documenting your functions</h2>
|
||||
<p>The Function Design Recipe places a large emphasis on developing a precise and detailed function header and docstring before writing any code for the function body. There are two main benefits to doing this.</p>
|
||||
<p>First, when you are given a programming task—“Write a function to do X”—you want to make sure you fully understand the goal of that function before trying to solve it. Forcing yourself to write out the function header and docstring, with examples, is an excellent way to reinforce your understanding about what you need to do.</p>
|
||||
<p>Second, as you begin to work on larger projects and writing dozens or hundreds of functions, it is easy to lose track of what each function does. The function header and docstring serve as <em>documentation</em> for the function, communicating to others–and to your future self—what that function is supposed to to. Your choices for the function’s name, its parameter names, its type contract, its docstring examples, and its description, can make the difference between code that is easy to work on and maintain, and code that is undecipherable.</p>
|
||||
<p>So the bottom line is you should follow this process for all of the functions you’ll write in this course, and beyond—trust us, it will save you lots of time and headaches!</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li>CSC108 videos: Function Design Recipe (<a href="https://youtu.be/v63oukRbJHE">Part 1</a>, <a href="https://youtu.be/ntZEFEp3xVY">Part 2</a>)</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,242 @@
|
||||
<!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>2.6 Testing Functions I: doctest and pytest</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">2.6 Testing Functions I: <code>doctest</code> and <code>pytest</code></h1>
|
||||
</header>
|
||||
<section>
|
||||
<p>The last step of the <a href="05-the-function-design-recipe.html">Function Design Recipe</a> is to test your code—but how? In this section, we’ll discuss the different strategies for testing code that you’ll use during the term, and beyond. As you write more and more complex programs in this course, it will be vital to maintain good habits to support you in your programming. One of these habits is developing good tests that will ensure your code is correct, and—often overlooked—using good <em>tools</em> to make those tests as easy to run as possible. You want to get in the habit of writing tests early in the process of programming, and running them as often as possible to detect coding errors as soon as you make them.</p>
|
||||
<h2 id="doctests-basic-examples-in-docstrings">Doctests: basic examples in docstrings</h2>
|
||||
<p>By following the Function Design Recipe, you naturally create a few tests for each function in the form of <em>doctest examples</em>, the examples you write in the function docstring. The simplest form of testing your function is import your function into the Python console, and then manually evaluate each doctest example one at a time and compare the output with the expected output in the docstring. This is a form of <strong>manual testing</strong>, as it requires human interaction to complete. Manual testing is often tedious and error-prone, so while it may be good for a quick check, we can certainly do better.</p>
|
||||
<p>Our first improvement is to use the Python library <code>doctest</code>, which can automatically extract doctest examples from docstrings and convert them into runnable tests. To use <code>doctest</code>, you can add the following code to the very bottom of any Python file:<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> Don’t worry about the <code>if __name__ == '__main__'</code> part for now; we will discuss this later on.</span></p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1"></a><span class="cf">if</span> <span class="va">__name__</span> <span class="op">==</span> <span class="st">'__main__'</span>:</span>
|
||||
<span id="cb1-2"><a href="#cb1-2"></a> <span class="im">import</span> doctest <span class="co"># import the doctest library</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3"></a> doctest.testmod() <span class="co"># run the tests</span></span></code></pre></div>
|
||||
<p>Then when you run the file, all of the doctest examples are automatically run, and you receive a report about which tests failed.</p>
|
||||
<p><video src="videos/doctests_passing_default_runner.webm" controls=""><a href="videos/doctests_passing_default_runner.webm">Video demo of running doctests</a></video><br />
|
||||
</p>
|
||||
<p>One warning: in order to use <code>doctest</code>, your docstring examples must be correctly formatted and valid Python code. For more information about the <code>doctest</code> module, check out <a href="../B-python-libraries/01-doctest.html">Appendix B.1 <code>doctest</code></a>.</p>
|
||||
<h2 id="creating-test-suites-with-pytest">Creating test suites with <code>pytest</code></h2>
|
||||
<p>Though <code>doctest</code> is an extremely useful module, the examples we write in docstrings are only simple cases meant to illustrate typical uses of the function. As functions get more complex, we’ll require more extensive tests to verify that they are correct. We could put all these tests into the function docstrings, but that would make the docstrings far too long.</p>
|
||||
<p>So instead, we will use another Python library, <code>pytest</code>, to write our tests in a separate file, and so include an exhaustive set of tests without cluttering our code files. Let’s illustrate this with an example. Suppose we have defined the following function in a files <code>trues.py</code>:<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> We’ve not included the body of this function, as we do not need to know how a function is implemented in order to write tests for it!</span></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="co"># In file trues.py</span></span>
|
||||
<span id="cb2-2"><a href="#cb2-2"></a></span>
|
||||
<span id="cb2-3"><a href="#cb2-3"></a><span class="kw">def</span> has_more_trues(booleans: <span class="bu">list</span>) <span class="op">-></span> <span class="bu">bool</span>:</span>
|
||||
<span id="cb2-4"><a href="#cb2-4"></a> <span class="co">"""Return whether booleans contains more True values than False values.</span></span>
|
||||
<span id="cb2-5"><a href="#cb2-5"></a></span>
|
||||
<span id="cb2-6"><a href="#cb2-6"></a><span class="co"> >>> has_more_trues([True, False, True])</span></span>
|
||||
<span id="cb2-7"><a href="#cb2-7"></a><span class="co"> True</span></span>
|
||||
<span id="cb2-8"><a href="#cb2-8"></a><span class="co"> >>> has_more_trues([True, False, False])</span></span>
|
||||
<span id="cb2-9"><a href="#cb2-9"></a><span class="co"> False</span></span>
|
||||
<span id="cb2-10"><a href="#cb2-10"></a><span class="co"> """</span></span>
|
||||
<span id="cb2-11"><a href="#cb2-11"></a> <span class="co"># Function body omitted</span></span></code></pre></div>
|
||||
<p>Now, we’ll see how to write tests for this function in a new file, which we’ll call <code>test_trues.py</code>.<label for="sn-2" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-2" class="margin-toggle"/><span class="sidenote"> By convention, all Python modules which contain tests are named with the prefix <code>test_</code>.</span> Now let us introduce some terminology. A <strong>unit test</strong> is a block of code that checks for the correct behaviour of a function for one specific input. A <strong>test suite</strong> is a collection of tests that check the behaviour of a function or (usually small) set of functions. Every test file contains a test suite.</p>
|
||||
<p>In Python, we express a unit test as a function whose name starts with the prefix <code>test_</code>. The body of the function contains an <code>assert</code> statement, which is a new form of Python statement used to check whether some boolean expression is <code>True</code> or <code>False</code>. Here are two examples of unit tests we could write that are direct translations of the doctest examples from above:</p>
|
||||
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1"></a><span class="co"># In file test_trues.py</span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2"></a></span>
|
||||
<span id="cb3-3"><a href="#cb3-3"></a><span class="im">from</span> trues <span class="im">import</span> has_more_trues</span>
|
||||
<span id="cb3-4"><a href="#cb3-4"></a></span>
|
||||
<span id="cb3-5"><a href="#cb3-5"></a></span>
|
||||
<span id="cb3-6"><a href="#cb3-6"></a><span class="kw">def</span> test_mixture_one_more_true() <span class="op">-></span> <span class="va">None</span>:</span>
|
||||
<span id="cb3-7"><a href="#cb3-7"></a> <span class="co">"""Test has_more_trues on a list with a mixture of True and False,</span></span>
|
||||
<span id="cb3-8"><a href="#cb3-8"></a><span class="co"> with one more True than False.</span></span>
|
||||
<span id="cb3-9"><a href="#cb3-9"></a><span class="co"> """</span></span>
|
||||
<span id="cb3-10"><a href="#cb3-10"></a> <span class="cf">assert</span> has_more_trues([<span class="va">True</span>, <span class="va">False</span>, <span class="va">True</span>])</span>
|
||||
<span id="cb3-11"><a href="#cb3-11"></a></span>
|
||||
<span id="cb3-12"><a href="#cb3-12"></a></span>
|
||||
<span id="cb3-13"><a href="#cb3-13"></a><span class="kw">def</span> test_mixture_one_more_false() <span class="op">-></span> <span class="va">None</span>:</span>
|
||||
<span id="cb3-14"><a href="#cb3-14"></a> <span class="co">"""Test has_more_trues on a list with a mixture of True and False,</span></span>
|
||||
<span id="cb3-15"><a href="#cb3-15"></a><span class="co"> with one more False than True.</span></span>
|
||||
<span id="cb3-16"><a href="#cb3-16"></a><span class="co"> """</span></span>
|
||||
<span id="cb3-17"><a href="#cb3-17"></a> <span class="cf">assert</span> <span class="kw">not</span> has_more_trues([<span class="va">True</span>, <span class="va">False</span>, <span class="va">False</span>])</span></code></pre></div>
|
||||
<p>These unit test functions are similar to the functions we’ve defined previously, with a few differences:</p>
|
||||
<ul>
|
||||
<li>Each test name and docstring documents what the test is by describing the test input.</li>
|
||||
<li>The return type of the test function is <code>None</code>, which is a special type that indicates that no value at all is returned by the function.<label for="sn-3" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-3" class="margin-toggle"/><span class="sidenote"> Python’s <code>None</code> is a bit special, and we’ll see more of this later in the course.</span> In the body of the test function, there is indeed no <code>return</code> statement—instead, there’s an <code>assert</code>.</li>
|
||||
</ul>
|
||||
<p>So what exactly does an <code>assert</code> statement do? In Python, an <code>assert</code> statement has the form <code>assert <expression></code>, and when executed it does the following:</p>
|
||||
<ol type="1">
|
||||
<li><p>First, it evaluates <code><expression></code>, which should produce a boolean value.</p></li>
|
||||
<li><p>If the value is <code>True</code>, nothing else happens, and the program continues onto the next statement.</p>
|
||||
<p>But if the value is <code>False</code>, an <code>AssertionError</code> is raised. This signals to <code>pytest</code> that the test has failed.</p></li>
|
||||
</ol>
|
||||
<p>So when <code>pytest</code> “runs” a unit test, what’s actually going on is it calls a test function like <code>test_mixture_one_more_true</code>. If the function call ends without raising an <code>AssertionError</code>, the test <em>passes</em>; if the function call does raise an <code>AssertionError</code>, the test <em>fails</em>. A single unit test function can contain multiple <code>assert</code> statements; the test passes if all of the <code>assert</code> statements pass, and fails if any of the <code>assert</code> statements raise an error.</p>
|
||||
<p>Finally, how do we use <code>pytest</code> to actually run our unit test functions? Similar to <code>doctest</code>, we need to first import <code>pytest</code> and then call a specific test 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="co"># At the bottom of test_trues.py</span></span>
|
||||
<span id="cb4-2"><a href="#cb4-2"></a></span>
|
||||
<span id="cb4-3"><a href="#cb4-3"></a><span class="cf">if</span> <span class="va">__name__</span> <span class="op">==</span> <span class="st">'__main__'</span>:</span>
|
||||
<span id="cb4-4"><a href="#cb4-4"></a> <span class="im">import</span> pytest</span>
|
||||
<span id="cb4-5"><a href="#cb4-5"></a> pytest.main([<span class="st">'test_trues.py'</span>])</span></code></pre></div>
|
||||
<p>Now if we run this file, we see that our two unit test functions are run:</p>
|
||||
<p><video src="videos/pytests_passing_pytest_runner.webm" controls=""><a href="videos/pytests_passing_pytest_runner.webm">Video demo of running pytest</a></video><br />
|
||||
</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li>CSC108 videos: Doctest (<a href="https://youtu.be/R1rDpZjfzZg">Part 1</a>, <a href="https://youtu.be/imLlb6Gyziw">Part 2</a>)</li>
|
||||
<li>CSC108 videos: Writing a ‘<code>__main__</code>’ program (<a href="https://youtu.be/7KnXMIf6Z90">Part 1</a>, <a href="https://youtu.be/k7Hr0sfYUrM">Part 2</a>) <!-- - Unittest (CSC108 videos - [Part 1](https://youtu.be/9J6-PEtwuGs), [Part 2](https://youtu.be/W1dOdRqQ-M4)) --> <!-- Note that there are also videos in "choosing test cases", but they're not linked because that section might be moved --></li>
|
||||
<li><a href="../B-python-libraries/01-doctest.html">Appendix B.1 <code>doctest</code></a></li>
|
||||
<li><a href="../B-python-libraries/02-pytest.html">Appendix B.2 <code>pytest</code></a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<!-- TODO: introduce assert statement with message -->
|
||||
<!--
|
||||
ODO: move to new section
|
||||
|
||||
## Choosing test cases
|
||||
|
||||
|
||||
We said earlier that keeping our tests in separate files from our source code enables us to write an exhaustive set of tests without worrying about length.
|
||||
But what exactly do we mean by "exhaustive?"
|
||||
In general, it is actually a pretty hard problem to choose test cases to verify the correctness of your program.
|
||||
You want to capture every possible scenario, while avoiding writing redundant tests.
|
||||
A good rule of thumb is to structure your tests around **properties of the inputs**.
|
||||
For example:
|
||||
|
||||
- *integers*: 0, 1, positive, negative, "small", "large"
|
||||
- *lists*: empty, length 1, no duplicates, duplicates, sorted, unsorted
|
||||
- *strings*: empty, length 1, alphanumeric characters only, special characters like punctuation marks
|
||||
|
||||
For functions that take in multiple inputs, we often also choose properties based on the *relationships between the inputs*.
|
||||
For example, for a function that takes two numbers as input, we might have a test for when the first is larger than the second, and another for when the second is larger than the first.
|
||||
For an input of one object and a list, we might have a test for when the object is in the list, and another for when the object isn't.
|
||||
|
||||
And finally, keep in mind that these are rules of thumb only;
|
||||
none of these properties will always be relevant to a given function.
|
||||
For a complete set of tests, you must understand *exactly* what the function does, to be able to identify what properties of the inputs really matter. -->
|
||||
<footer>
|
||||
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,206 @@
|
||||
<!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>2.7 Type Conversion Functions</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">2.7 Type Conversion Functions</h1>
|
||||
</header>
|
||||
<section>
|
||||
<p>There is another useful set of built-in functions that we have not yet discussed: functions that allow us to convert values between different data types. For example, given a string <code>'10'</code>, can we convert it into the integer <code>10</code>? Or given a list <code>[1, 2, 3]</code>, can we convert it into a set <code>{1, 2, 3}</code>?</p>
|
||||
<p>The answer to these questions is yes, and the way to do so in Python is quite elegant. Each data type that we have learned about so far, from <code>int</code> to <code>dict</code>, is also a function that takes an argument and attempts to convert it to a value of that data type.</p>
|
||||
<p>Here are some examples:<label for="sn-0" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-0" class="margin-toggle"/><span class="sidenote"> Some of these are more “obvious” than others. Don’t worry about the exact rules for conversions between types, as you won’t be expected to memorize them. Instead, we just want you to know that these conversions are possible using data types as functions.</span></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">>>></span> <span class="bu">int</span>(<span class="st">'10'</span>)</span>
|
||||
<span id="cb1-2"><a href="#cb1-2"></a><span class="dv">10</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3"></a><span class="op">>>></span> <span class="bu">float</span>(<span class="st">'10'</span>)</span>
|
||||
<span id="cb1-4"><a href="#cb1-4"></a><span class="fl">10.0</span></span>
|
||||
<span id="cb1-5"><a href="#cb1-5"></a><span class="op">>>></span> <span class="bu">bool</span>(<span class="dv">1000</span>)</span>
|
||||
<span id="cb1-6"><a href="#cb1-6"></a><span class="va">True</span></span>
|
||||
<span id="cb1-7"><a href="#cb1-7"></a><span class="op">>>></span> <span class="bu">bool</span>(<span class="dv">0</span>)</span>
|
||||
<span id="cb1-8"><a href="#cb1-8"></a><span class="va">False</span></span>
|
||||
<span id="cb1-9"><a href="#cb1-9"></a><span class="op">>>></span> <span class="bu">list</span>({<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>})</span>
|
||||
<span id="cb1-10"><a href="#cb1-10"></a>[<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span>
|
||||
<span id="cb1-11"><a href="#cb1-11"></a><span class="op">>>></span> <span class="bu">set</span>([<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>])</span>
|
||||
<span id="cb1-12"><a href="#cb1-12"></a>{<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>}</span>
|
||||
<span id="cb1-13"><a href="#cb1-13"></a><span class="op">>>></span> <span class="bu">set</span>() <span class="co"># Giving set no arguments results in the empty set</span></span>
|
||||
<span id="cb1-14"><a href="#cb1-14"></a><span class="bu">set</span>()</span>
|
||||
<span id="cb1-15"><a href="#cb1-15"></a><span class="op">>>></span> <span class="bu">dict</span>([(<span class="st">'a'</span>, <span class="dv">1</span>), (<span class="st">'b'</span>, <span class="dv">2</span>), (<span class="st">'c'</span>, <span class="dv">3</span>)])</span>
|
||||
<span id="cb1-16"><a href="#cb1-16"></a>{<span class="st">'a'</span>: <span class="dv">1</span>, <span class="st">'b'</span>: <span class="dv">2</span>, <span class="st">'c'</span>: <span class="dv">3</span>}</span></code></pre></div>
|
||||
<p>In particular, <code>str</code> is the most versatile of these data types. <em>Every</em> value of the data types we’ve studied so far has a string represention which corresponds directly to how you would write the value as a Python literal.</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">>>></span> <span class="bu">str</span>(<span class="dv">10</span>)</span>
|
||||
<span id="cb2-2"><a href="#cb2-2"></a><span class="co">'10'</span></span>
|
||||
<span id="cb2-3"><a href="#cb2-3"></a><span class="op">>>></span> <span class="bu">str</span>(<span class="op">-</span><span class="fl">5.5</span>)</span>
|
||||
<span id="cb2-4"><a href="#cb2-4"></a><span class="co">'-5.5'</span></span>
|
||||
<span id="cb2-5"><a href="#cb2-5"></a><span class="op">>>></span> <span class="bu">str</span>(<span class="va">True</span>)</span>
|
||||
<span id="cb2-6"><a href="#cb2-6"></a><span class="co">'True'</span></span>
|
||||
<span id="cb2-7"><a href="#cb2-7"></a><span class="op">>>></span> <span class="bu">str</span>({<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>})</span>
|
||||
<span id="cb2-8"><a href="#cb2-8"></a><span class="co">'{1, 2, 3}'</span></span>
|
||||
<span id="cb2-9"><a href="#cb2-9"></a><span class="op">>>></span> <span class="bu">str</span>([<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>])</span>
|
||||
<span id="cb2-10"><a href="#cb2-10"></a><span class="co">'[1, 2, 3]'</span></span>
|
||||
<span id="cb2-11"><a href="#cb2-11"></a><span class="op">>>></span> <span class="bu">str</span>({<span class="st">'a'</span>: <span class="dv">1</span>, <span class="st">'b'</span>: <span class="dv">2</span>})</span>
|
||||
<span id="cb2-12"><a href="#cb2-12"></a><span class="co">"{'a': 1, 'b': 2}"</span></span></code></pre></div>
|
||||
<h2 id="warning-conversion-errors">Warning: conversion errors</h2>
|
||||
<p>You often have to be careful when attempting to convert between different data types, as not all values of one type can be converted into another. Attempting to convert an “invalid” value often results in a Python exception to be raised:<label for="sn-1" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-1" class="margin-toggle"/><span class="sidenote"> These exceptions typically have type <code>ValueError</code> or <code>TypeError</code>.</span></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">>>></span> <span class="bu">int</span>(<span class="st">'David'</span>)</span>
|
||||
<span id="cb3-2"><a href="#cb3-2"></a>Traceback (most recent call last):</span>
|
||||
<span id="cb3-3"><a href="#cb3-3"></a> File <span class="st">"<stdin>"</span>, line <span class="dv">1</span>, <span class="kw">in</span> <span class="op"><</span>module<span class="op">></span></span>
|
||||
<span id="cb3-4"><a href="#cb3-4"></a><span class="pp">ValueError</span>: invalid literal <span class="cf">for</span> <span class="bu">int</span>() <span class="cf">with</span> base <span class="dv">10</span>: <span class="st">'David'</span></span>
|
||||
<span id="cb3-5"><a href="#cb3-5"></a><span class="op">>>></span> <span class="bu">list</span>(<span class="dv">1000</span>)</span>
|
||||
<span id="cb3-6"><a href="#cb3-6"></a>Traceback (most recent call last):</span>
|
||||
<span id="cb3-7"><a href="#cb3-7"></a> File <span class="st">"<stdin>"</span>, line <span class="dv">1</span>, <span class="kw">in</span> <span class="op"><</span>module<span class="op">></span></span>
|
||||
<span id="cb3-8"><a href="#cb3-8"></a><span class="pp">TypeError</span>: <span class="st">'int'</span> <span class="bu">object</span> <span class="kw">is</span> <span class="kw">not</span> iterable</span></code></pre></div>
|
||||
<h2 id="preview-creating-values-of-arbitrary-data-types">Preview: creating values of arbitrary data types</h2>
|
||||
<p>The ability to create values of a given type by calling the data type as a function is not unique to the built-in data types in this section. We’ve actually seen two examples of doing this so far in the course!</p>
|
||||
<h3 id="range-revisited"><code>range</code> revisited</h3>
|
||||
<p>Earlier, we saw that we could call <code>range</code> to create a sequence of numbers. But if you just try calling <code>range</code> by itself in the Python console, you see something kind of funny:</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">>>></span> <span class="bu">range</span>(<span class="dv">5</span>, <span class="dv">10</span>)</span>
|
||||
<span id="cb4-2"><a href="#cb4-2"></a><span class="bu">range</span>(<span class="dv">5</span>, <span class="dv">10</span>)</span></code></pre></div>
|
||||
<p>Whereas you might have expected to see a list (<code>[5, 6, 7, 8, 9]</code>), in the Python console output it looks like nothing happened at all! This is because <code>range</code> is actually a type conversion function: Python also has a <code>range</code> data type that is distinct from lists (or other collection data types).</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">>>></span> five_to_nine <span class="op">=</span> <span class="bu">range</span>(<span class="dv">5</span>, <span class="dv">10</span>)</span>
|
||||
<span id="cb5-2"><a href="#cb5-2"></a><span class="op">>>></span> <span class="bu">type</span>(five_to_nine)</span>
|
||||
<span id="cb5-3"><a href="#cb5-3"></a><span class="op"><</span><span class="kw">class</span> <span class="st">'range'</span><span class="op">></span></span>
|
||||
<span id="cb5-4"><a href="#cb5-4"></a><span class="op">>>></span> five_to_nine <span class="op">==</span> [<span class="dv">5</span>, <span class="dv">6</span>, <span class="dv">7</span>, <span class="dv">8</span>, <span class="dv">9</span>]</span>
|
||||
<span id="cb5-5"><a href="#cb5-5"></a><span class="va">False</span></span></code></pre></div>
|
||||
<h3 id="datetime.date-revisited"><code>datetime.date</code> revisited</h3>
|
||||
<p>Recall an example from the last section in <a href="04-importing-modules.html">Section 2.4 Importing Modules</a>:</p>
|
||||
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1"></a><span class="op">>>></span> <span class="im">import</span> datetime</span>
|
||||
<span id="cb6-2"><a href="#cb6-2"></a><span class="op">>>></span> canada_day <span class="op">=</span> datetime.date(<span class="dv">1867</span>, <span class="dv">7</span>, <span class="dv">1</span>) <span class="co"># Create a new date</span></span>
|
||||
<span id="cb6-3"><a href="#cb6-3"></a><span class="op">>>></span> <span class="bu">type</span>(canada_day)</span>
|
||||
<span id="cb6-4"><a href="#cb6-4"></a><span class="op"><</span><span class="kw">class</span> <span class="st">'datetime.date'</span><span class="op">></span></span></code></pre></div>
|
||||
<p>In this case, the data type is <code>datetime.date</code>, and it is called on three arguments instead of one. In this context, <code>datetime.date</code> is called to <em>create</em> a new <code>date</code> value given three arguments (the year, month, and day).<label for="sn-2" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-2" class="margin-toggle"/><span class="sidenote"> This is a more general form of type “conversion”, which created a data type of a new value given a single argument.</span> And of course, this behaviour isn’t unique to <code>datetime.date</code> either. As we’ll see a bit later in this course, you’ll be able to take <em>any</em> data type—even ones you define yourself—and create values of that type by calling the data type as a function.</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,205 @@
|
||||
<!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>2.8 Application: Representing Text</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">2.8 Application: Representing Text</h1>
|
||||
</header>
|
||||
<section>
|
||||
<p>We have mentioned that computers use a series of 0s and 1s to store data. These 0s and 1s represent numbers. So then, how can numbers represent textual data (i.e., a string)? The answer is functions.</p>
|
||||
<p>Once upon a time, humans interacted with computers through punched paper tape (or simply punched tape). A hole (or the lack of a hole) at a particular location on the tape represented a 0 or a 1 (i.e., binary). Today we would call each 0 or 1 a <strong>bit</strong>. Obviously, this is much more tedious than using our modern input peripherals: keyboards, mice, touch screens, etc. Eventually, a standard for representing characters (e.g., letters, numbers) with holes was settled on. Using only 7 locations on the tape, 128 different characters could be represented (<span class="math inline">\(2^7 = 128\)</span>).</p>
|
||||
<p>The standard was called ASCII (pronounced ass-key) and it persists to this day. You can think of the ASCII standard as a function with domain <span class="math inline">\(\{0, 1, \dots, 127\}\)</span>, whose codomain is the set of all possible characters. This function is <em>one-to-one</em>, meaning no two numbers map to the same character—this would be redundant for the purpose of encoding the characters. This standard covered all English letters (lowercase and uppercase), digits, punctuation, and various others (e.g., to communicate a new line). For example, the number 65 mapped to the letter <code>'A'</code> and the number 126 mapped to the punctuation mark <code>'~'</code>.</p>
|
||||
<p>But what about other languages? Computer scientists extended ASCII from length-7 to length-8 sequences of bits, and hence its domain increased to size 256 (<span class="math inline">\(\{0, 1, \dots, 255\}\)</span>). This allowed “extended ASCII” to support some other characters used in similar Latin-based languages, such as <code>'é'</code> (233), <code>'ö'</code> (246), <code>'€'</code> (128), and other useful symbols like <code>'©'</code> (169) and <code>'½'</code> (189). But what about characters used in very different languages (e.g., Greek, Mandarin, Arabic)?</p>
|
||||
<p>The latest standard, Unicode, uses <strong>up to 32 bits</strong> that gives us a domain of <span class="math inline">\(\{0, 1, \dots, 2^{32} - 1\}\)</span>, over 4 billion different numbers. This number is in fact larger than the number of distinct characters in use across all different languages! There are several <em>unused numbers</em> in the domain of Unicode—Unicode is not technically a function defined over <span class="math inline">\(\{0, 1, \dots, 2^{32} - 1\}\)</span> because of this.</p>
|
||||
<p>But with the pervasiveness of the Internet, these unused numbers are being used to <a href="https://home.unicode.org/emoji/emoji-frequency/">map to emojis</a>. Of course, this can cause some lost-in-translation issues. The palm tree emoji may appear different on your device than a friend’s. In extreme cases, your friend’s device may not see a palm tree at all or see a completely different emoji. Part of the process involves <a href="https://unicode.org/emoji/proposals.html">submitting a proposal for a new emoji</a>. But the second half of that process means that computer scientists need to support newly approved emojis by updating their software. And, of course, in order to do that computer scientists need to have a firm understanding of functions!</p>
|
||||
<h2 id="pythons-unicode-conversion-functions">Python’s Unicode conversion functions</h2>
|
||||
<p>Python has two built-in functions that implement the (partial) mapping between characters and their Unicode number. The first is <code>ord</code>, which takes a single-character string and returns its Unicode number as an <code>int</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">>>></span> <span class="bu">ord</span>(<span class="st">'A'</span>)</span>
|
||||
<span id="cb1-2"><a href="#cb1-2"></a><span class="dv">65</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3"></a><span class="op">>>></span> <span class="bu">ord</span>(<span class="st">'é'</span>)</span>
|
||||
<span id="cb1-4"><a href="#cb1-4"></a><span class="dv">233</span></span>
|
||||
<span id="cb1-5"><a href="#cb1-5"></a><span class="op">>>></span> <span class="bu">ord</span>(<span class="st">'♥'</span>)</span>
|
||||
<span id="cb1-6"><a href="#cb1-6"></a><span class="dv">9829</span></span></code></pre></div>
|
||||
<p>The second is <code>chr</code>, which computes the <em>inverse</em> of <code>ord</code>: given an integer representing a Unicode number, <code>chr</code> returns a string containing the corresponding character.</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">>>></span> <span class="bu">chr</span>(<span class="dv">65</span>)</span>
|
||||
<span id="cb2-2"><a href="#cb2-2"></a><span class="co">'A'</span></span>
|
||||
<span id="cb2-3"><a href="#cb2-3"></a><span class="op">>>></span> <span class="bu">chr</span>(<span class="dv">233</span>)</span>
|
||||
<span id="cb2-4"><a href="#cb2-4"></a><span class="co">'é'</span></span>
|
||||
<span id="cb2-5"><a href="#cb2-5"></a><span class="op">>>></span> <span class="bu">chr</span>(<span class="dv">9829</span>)</span>
|
||||
<span id="cb2-6"><a href="#cb2-6"></a><span class="co">'♥'</span></span></code></pre></div>
|
||||
<p>Unicode representations are a source of one common source of surprise for Python programmers: string ordering comparisons (<code><</code>, <code>></code>) are based on Unicode numeric values! For example, the Unicode value of <code>'Z'</code> is 90 and the Unicode value of <code>'a'</code> is 97, and so the following holds:</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">>>></span> <span class="st">'Z'</span> <span class="op"><</span> <span class="st">'a'</span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2"></a><span class="va">True</span></span>
|
||||
<span id="cb3-3"><a href="#cb3-3"></a><span class="op">>>></span> <span class="st">'Zebra'</span> <span class="op"><</span> <span class="st">'animal'</span></span>
|
||||
<span id="cb3-4"><a href="#cb3-4"></a><span class="va">True</span></span></code></pre></div>
|
||||
<p>This means that sorting a collection of strings can seem alphabetical, but treats lowercase and uppercase letters differently:</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">>>></span> <span class="bu">sorted</span>({<span class="st">'David'</span>, <span class="st">'Mario'</span>, <span class="st">'Jacqueline'</span>})</span>
|
||||
<span id="cb4-2"><a href="#cb4-2"></a>[<span class="st">'David'</span>, <span class="st">'Jacqueline'</span>, <span class="st">'Mario'</span>]</span>
|
||||
<span id="cb4-3"><a href="#cb4-3"></a><span class="op">>>></span> <span class="bu">sorted</span>({<span class="st">'david'</span>, <span class="st">'Mario'</span>, <span class="st">'Jacqueline'</span>})</span>
|
||||
<span id="cb4-4"><a href="#cb4-4"></a>[<span class="st">'Jacqueline'</span>, <span class="st">'Mario'</span>, <span class="st">'david'</span>]</span></code></pre></div>
|
||||
<!-- Python also provides us with a built-in function to convert an integer value into a binary value.
|
||||
This lets us see the sequence of 0s and 1s that would have been used decades ago when making holes in punch tape.
|
||||
The built-in function is called `bin`, and we need to pass it an integer.
|
||||
|
||||
```python
|
||||
>>> bin(0)
|
||||
'0b0'
|
||||
>>> bin(1)
|
||||
'0b1'
|
||||
>>> bin(2)
|
||||
'0b10'
|
||||
```
|
||||
|
||||
The result is a string where a sequence of 0s and 1s are prefixed with `'0b'`.
|
||||
Let us now use this to find out the binary sequence of the letters `A` and `a`.
|
||||
|
||||
```python
|
||||
>>> unicode_A = ord('A')
|
||||
>>> bin(unicode_A)
|
||||
'0b1000001'
|
||||
>>> bin(ord('a'))
|
||||
'0b1100001'
|
||||
``` -->
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://www.ascii-code.com/">ASCII Code: The extended ASCII table</a></li>
|
||||
<li><a href="https://unicode-table.com/en/">Unicode Character Table</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<footer>
|
||||
<a href="https://www.teach.cs.toronto.edu/~csc110y/fall/notes/">CSC110 Course Notes Home</a>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user