1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
<!DOCTYPE html
PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>17.3. plural.py, stage 2</title>
<link rel="stylesheet" href="../diveintopython.css" type="text/css">
<link rev="made" href="mailto:f8dy@diveintopython.org">
<meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
<meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
<meta name="description" content="Python from novice to pro">
<link rel="home" href="../toc/index.html" title="Dive Into Python">
<link rel="up" href="index.html" title="Chapter 17. Dynamic functions">
<link rel="previous" href="stage1.html" title="17.2. plural.py, stage 1">
<link rel="next" href="stage3.html" title="17.4. plural.py, stage 3">
</head>
<body>
<table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
<tr>
<td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a> > <a href="../toc/index.html">Dive Into Python</a> > <a href="index.html">Dynamic functions</a> > <span class="thispage">plural.py, stage 2</span></td>
<td id="navigation" align="right" valign="top"> <a href="stage1.html" title="Prev: “plural.py, stage 1”"><<</a> <a href="stage3.html" title="Next: “plural.py, stage 3”">>></a></td>
</tr>
<tr>
<td colspan="3" id="logocontainer">
<h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
<p id="tagline">Python from novice to pro</p>
</td>
<td colspan="3" align="right">
<form id="search" method="GET" action="http://www.google.com/custom">
<p><label for="q" accesskey="4">Find: </label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
</form>
</td>
</tr>
</table>
<!--#include virtual="/inc/ads" -->
<div class="section" lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title"><a name="plural.stage2"></a>17.3. <tt class="filename">plural.py</tt>, stage 2
</h2>
</div>
</div>
<div></div>
</div>
<div class="abstract">
<p>Now you're going to add a level of abstraction. You started by defining a list of rules: if this, then do that, otherwise
go to the next rule. Let's temporarily complicate part of the program so you can simplify another part.
</p>
</div>
<div class="example"><a name="d0e37629"></a><h3 class="title">Example 17.6. <tt class="filename">plural2.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
import</span> re
<span class='pykeyword'>def</span><span class='pyclass'> match_sxz</span>(noun):
<span class='pykeyword'>return</span> re.search(<span class='pystring'>'[sxz]$'</span>, noun)
<span class='pykeyword'>def</span><span class='pyclass'> apply_sxz</span>(noun):
<span class='pykeyword'>return</span> re.sub(<span class='pystring'>'$'</span>, <span class='pystring'>'es'</span>, noun)
<span class='pykeyword'>def</span><span class='pyclass'> match_h</span>(noun):
<span class='pykeyword'>return</span> re.search(<span class='pystring'>'[^aeioudgkprt]h$'</span>, noun)
<span class='pykeyword'>def</span><span class='pyclass'> apply_h</span>(noun):
<span class='pykeyword'>return</span> re.sub(<span class='pystring'>'$'</span>, <span class='pystring'>'es'</span>, noun)
<span class='pykeyword'>def</span><span class='pyclass'> match_y</span>(noun):
<span class='pykeyword'>return</span> re.search(<span class='pystring'>'[^aeiou]y$'</span>, noun)
<span class='pykeyword'>def</span><span class='pyclass'> apply_y</span>(noun):
<span class='pykeyword'>return</span> re.sub(<span class='pystring'>'y$'</span>, <span class='pystring'>'ies'</span>, noun)
<span class='pykeyword'>def</span><span class='pyclass'> match_default</span>(noun):
<span class='pykeyword'>return</span> 1
<span class='pykeyword'>def</span><span class='pyclass'> apply_default</span>(noun):
<span class='pykeyword'>return</span> noun + <span class='pystring'>'s'</span>
rules = ((match_sxz, apply_sxz),
(match_h, apply_h),
(match_y, apply_y),
(match_default, apply_default)
) <a name="plural.stage2.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
<span class='pykeyword'>def</span><span class='pyclass'> plural</span>(noun):
<span class='pykeyword'>for</span> matchesRule, applyRule <span class='pykeyword'>in</span> rules: <a name="plural.stage2.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
<span class='pykeyword'>if</span> matchesRule(noun): <a name="plural.stage2.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
<span class='pykeyword'>return</span> applyRule(noun) <a name="plural.stage2.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
</pre><div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td width="12" valign="top" align="left"><a href="#plural.stage2.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
</td>
<td valign="top" align="left">This version looks more complicated (it's certainly longer), but it does exactly the same thing: try to match four different
rules, in order, and apply the appropriate regular expression when a match is found. The difference is that each individual
match and apply rule is defined in its own function, and the functions are then listed in this <tt class="varname">rules</tt> variable, which is a tuple of tuples.
</td>
</tr>
<tr>
<td width="12" valign="top" align="left"><a href="#plural.stage2.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
</td>
<td valign="top" align="left">Using a <tt class="literal">for</tt> loop, you can pull out the match and apply rules two at a time (one match, one apply) from the <tt class="varname">rules</tt> tuple. On the first iteration of the <tt class="literal">for</tt> loop, <tt class="varname">matchesRule</tt> will get <tt class="function">match_sxz</tt>, and <tt class="varname">applyRule</tt> will get <tt class="function">apply_sxz</tt>. On the second iteration (assuming you get that far), <tt class="varname">matchesRule</tt> will be assigned <tt class="function">match_h</tt>, and <tt class="varname">applyRule</tt> will be assigned <tt class="function">apply_h</tt>.
</td>
</tr>
<tr>
<td width="12" valign="top" align="left"><a href="#plural.stage2.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
</td>
<td valign="top" align="left">Remember that <a href="../getting_to_know_python/everything_is_an_object.html" title="2.4. Everything Is an Object">everything in <span class="application">Python</span> is an object</a>, including functions. <tt class="varname">rules</tt> contains actual functions; not names of functions, but actual functions. When they get assigned in the <tt class="literal">for</tt> loop, then <tt class="varname">matchesRule</tt> and <tt class="varname">applyRule</tt> are actual functions that you can call. So on the first iteration of the <tt class="literal">for</tt> loop, this is equivalent to calling <tt class="function">matches_sxz(noun)</tt>.
</td>
</tr>
<tr>
<td width="12" valign="top" align="left"><a href="#plural.stage2.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
</td>
<td valign="top" align="left">On the first iteration of the <tt class="literal">for</tt> loop, this is equivalent to calling <tt class="function">apply_sxz(noun)</tt>, and so forth.
</td>
</tr>
</table>
</div>
</div>
<p>If this additional level of abstraction is confusing, try unrolling the function to see the equivalence. This <tt class="literal">for</tt> loop is equivalent to the following:
</p>
<div class="example"><a name="d0e37727"></a><h3 class="title">Example 17.7. Unrolling the <tt class="function">plural</tt> function
</h3><pre class="programlisting"><span class='pykeyword'>
def</span> plural(noun):
<span class='pykeyword'>if</span> match_sxz(noun):
<span class='pykeyword'>return</span> apply_sxz(noun)
<span class='pykeyword'>if</span> match_h(noun):
<span class='pykeyword'>return</span> apply_h(noun)
<span class='pykeyword'>if</span> match_y(noun):
<span class='pykeyword'>return</span> apply_y(noun)
<span class='pykeyword'>if</span> match_default(noun):
<span class='pykeyword'>return</span> apply_default(noun)
</pre></div>
<p>The benefit here is that that <tt class="function">plural</tt> function is now simplified. It takes a list of rules, defined elsewhere, and iterates through them in a generic fashion.
Get a match rule; does it match? Then call the apply rule. The rules could be defined anywhere, in any way. The <tt class="function">plural</tt> function doesn't care.
</p>
<p>Now, was adding this level of abstraction worth it? Well, not yet. Let's consider what it would take to add a new rule to
the function. Well, in the previous example, it would require adding an <tt class="literal">if</tt> statement to the <tt class="function">plural</tt> function. In this example, it would require adding two functions, <tt class="function">match_foo</tt> and <tt class="function">apply_foo</tt>, and then updating the <tt class="varname">rules</tt> list to specify where in the order the new match and apply functions should be called relative to the other rules.
</p>
<p>This is really just a stepping stone to the next section. Let's move on.</p>
</div>
<table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
<tr>
<td width="35%" align="left"><br><a class="NavigationArrow" href="stage1.html"><< plural.py, stage 1</a></td>
<td width="30%" align="center"><br> <span class="divider">|</span> <a href="index.html#plural.divein" title="17.1. Diving in">1</a> <span class="divider">|</span> <a href="stage1.html" title="17.2. plural.py, stage 1">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="stage3.html" title="17.4. plural.py, stage 3">4</a> <span class="divider">|</span> <a href="stage4.html" title="17.5. plural.py, stage 4">5</a> <span class="divider">|</span> <a href="stage5.html" title="17.6. plural.py, stage 5">6</a> <span class="divider">|</span> <a href="stage6.html" title="17.7. plural.py, stage 6">7</a> <span class="divider">|</span> <a href="summary.html" title="17.8. Summary">8</a> <span class="divider">|</span>
</td>
<td width="35%" align="right"><br><a class="NavigationArrow" href="stage3.html">plural.py, stage 3 >></a></td>
</tr>
<tr>
<td colspan="3"><br></td>
</tr>
</table>
<div class="Footer">
<p class="copyright">Copyright © 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
</div>
</body>
</html>
|