mirror of
https://github.com/kennethreitz/dive-into-python3.git
synced 2026-06-05 15:00:18 +00:00
finished "your first python program", wrote synchronized highlighting script for callouts within a [pre], moved scripts to common .js file
This commit is contained in:
@@ -8,10 +8,11 @@
|
||||
<style type="text/css">
|
||||
body{counter-reset:h1 19}
|
||||
</style>
|
||||
<script type="text/javascript" src="dip3.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p class="skip"><a href="#divingin">skip to main content</a>
|
||||
<form action="http://www.google.com/cse" id="search"><div><input type="hidden" name="cx" value="014021643941856155761:l5eihuescdw"><input type="hidden" name="ie" value="UTF-8"> <input name="q" size="31"> <input type="submit" name="sa" value="Search"></div><p>You are here: <a href="index.html">Dive Into Python 3</a> <span>‣</span> <b>Chapter 20</b></form>
|
||||
<form action="http://www.google.com/cse" id="search"><div><input type="hidden" name="cx" value="014021643941856155761:l5eihuescdw"><input type="hidden" name="ie" value="UTF-8"> <input name="q" size="31"> <input type="submit" name="sa" value="Search"></div><p>You are here: <a href="index.html">Dive Into Python 3</a> <span>‣</span> <b>Chapter 20</b></p></form>
|
||||
<h1>Case study: porting <code class="filename">chardet</code> to Python 3</h1>
|
||||
<blockquote class="q">
|
||||
<p><span>❝</span> Words, words. They’re all we have to go on. <span>❞</span><br>— <cite>Rosencrantz and Guildenstern are Dead</cite>
|
||||
|
||||
@@ -7,14 +7,16 @@ a:visited{color:darkorchid}
|
||||
h1 a,h2 a,h3 a,#nav a{color:inherit !important}
|
||||
abbr,acronym{letter-spacing:0.1em;text-transform:lowercase;font-variant:small-caps}
|
||||
h1,h2,h3,p,ul,ol,#search{margin:1.75em 0}
|
||||
#search div{float:right}
|
||||
form div{float:right}
|
||||
li ol{margin:0}
|
||||
h1,h2,h3{font-size:medium}
|
||||
h1,h2,h3{font-size:medium;clear:both}
|
||||
h1{background:papayawhip;color:#000;width:100%;margin:0}
|
||||
pre{white-space:pre-wrap;margin:2.154em 0;padding:0 0 0 2.154em;border-left:1px dotted}
|
||||
pre,kbd,code,samp{font-family:Consolas,Inconsolata,Monaco,monospace;font-size:medium;line-height:2.154}
|
||||
pre,kbd,code,samp{font-family:Consolas,Inconsolata,Monaco,monospace;font-size:medium;line-height:2.154;word-spacing:0}
|
||||
pre a{display:inline;padding:0.4375em 0;border:0}
|
||||
pre a:hover{border:0}
|
||||
kbd{font-weight:bold}
|
||||
samp.prompt{color:#667}/*the neighbor of the beast*/
|
||||
.prompt{color:#667}/*the neighbor of the beast*/
|
||||
td pre{margin:0;padding:0;border:0}
|
||||
.c{text-align:center;font-size:small}
|
||||
p.fancy:first-letter{float:left;background:transparent;color:gainsboro;padding:0.11em 4px 0 0;font:normal 4em/0.68 serif}
|
||||
@@ -31,9 +33,9 @@ span,tr + tr th:first-child{font-family:'Arial Unicode MS',sans-serif;font-style
|
||||
.note{margin-left:4.94em}
|
||||
.note span{display:block;float:left;font-size:xx-large;line-height:0.875em;margin:0 0.22em 0 -1.22em}
|
||||
table.simple th{font-family:inherit !important}
|
||||
.fr{width:auto;margin-top:4.308em;border:1px dotted}
|
||||
.fr{width:100%;margin:2.154em 0;border:1px dotted}
|
||||
.fr h4{margin-top:-1.2em;margin-left:-1em;width:8.5em;border:1px dotted;padding: 3px 3px 3px 13px;background:#fff;color:inherit;position:relative}
|
||||
tr.hover,li.hover{background:#eee;color:inherit;cursor:default}
|
||||
.hover{background:#eee;color:inherit;cursor:default}
|
||||
body{counter-reset:h1}
|
||||
h1:before{counter-increment:h1;content:counter(h1) ". "}
|
||||
h1{counter-reset:h2}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
window.onload = function() {
|
||||
// synchronized highlighting for code blocks with callouts
|
||||
var arPre = document.getElementsByTagName('pre');
|
||||
for (var i = arPre.length - 1; i >= 0; i--) {
|
||||
var elmPre = arPre[i];
|
||||
var arCallout = elmPre.getElementsByTagName('span');
|
||||
if (arCallout.length == 0) { continue; }
|
||||
var elmCalloutList = elmPre.nextSibling;
|
||||
while (elmCalloutList && (elmCalloutList.nodeType != 1)) {
|
||||
elmCalloutList = elmCalloutList.nextSibling;
|
||||
}
|
||||
if (elmCalloutList.nodeName.toLowerCase() != 'ol') { continue; }
|
||||
var arCalloutListItem = elmCalloutList.getElementsByTagName('li');
|
||||
if (arCalloutListItem.length != arCallout.length) {
|
||||
alert('Number of callouts != number of callout list items:\n' + elmPre.innerHTML);
|
||||
continue;
|
||||
}
|
||||
for (var j = arCallout.length - 1; j >= 0; j--) {
|
||||
var elmCallout = arCallout[j].parentNode;
|
||||
var elmCalloutListItem = arCalloutListItem[j];
|
||||
elmCallout._li = elmCalloutListItem;
|
||||
elmCalloutListItem._div = elmCallout;
|
||||
elmCallout.onmouseover = function() {
|
||||
this.className = 'hover';
|
||||
this._li.className = 'hover';
|
||||
};
|
||||
elmCalloutListItem.onmouseover = function() {
|
||||
this.className = 'hover';
|
||||
this._div.className = 'hover';
|
||||
};
|
||||
elmCallout.onmouseout = function() {
|
||||
this.className = '';
|
||||
this._li.className = '';
|
||||
};
|
||||
elmCalloutListItem.onmouseout = function() {
|
||||
this.className = '';
|
||||
this._div.className = '';
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// synchronized highlighting for tables with callouts
|
||||
var arTables = document.getElementsByTagName('table');
|
||||
for (var i = arTables.length - 1; i >= 0; i--) {
|
||||
var elmTable = arTables[i];
|
||||
var olNotes = document.getElementById("skip" + elmTable.id);
|
||||
if (!olNotes) { continue; }
|
||||
var arNotes = olNotes.getElementsByTagName('li');
|
||||
var arTableRows = elmTable.getElementsByTagName('tr');
|
||||
if (arNotes.length == 0) { continue; }
|
||||
for (var j = arTableRows.length - 1; j >= 1; j--) {
|
||||
var elmTableRow = arTableRows[j];
|
||||
var elmNote = arNotes[j - 1];
|
||||
elmTableRow._li = elmNote;
|
||||
elmNote._tr = elmTableRow;
|
||||
elmTableRow.onmouseover = function() {
|
||||
this.className = 'hover';
|
||||
this._li.className = 'hover';
|
||||
};
|
||||
elmNote.onmouseover = function() {
|
||||
this.className = 'hover';
|
||||
this._tr.className = 'hover';
|
||||
};
|
||||
elmTableRow.onmouseout = function() {
|
||||
this.className = '';
|
||||
this._li.className = '';
|
||||
};
|
||||
elmNote.onmouseout = function() {
|
||||
this.className = '';
|
||||
this._tr.className = '';
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-7
@@ -6,6 +6,7 @@
|
||||
<link rel="alternate" type="application/atom+xml" href="http://hg.diveintopython3.org/atom-log">
|
||||
<link rel="stylesheet" type="text/css" href="dip3.css">
|
||||
<style type="text/css">
|
||||
body{counter-reset:h1 -1}
|
||||
h2{margin-left:1.75em}
|
||||
h3{margin-left:3.5em}
|
||||
.appendix h1:before{content:""}
|
||||
@@ -13,9 +14,9 @@ h3{margin-left:3.5em}
|
||||
</head>
|
||||
<body>
|
||||
<form action="http://www.google.com/cse" id="search"><div><input type="hidden" name="cx" value="014021643941856155761:l5eihuescdw"><input type="hidden" name="ie" value="UTF-8"><input name="q" size="31"> <input type="submit" name="sa" value="Search"></div></form>
|
||||
<p style="clear:both;margin-top:0;padding-top:1.75em"><cite>Dive Into Python 3</cite> will cover Python 3 and its differences from Python 2. Compared to the original <cite><a href="http://diveintopython.org/">Dive Into Python</a></cite>, it will be about 50% revised and 50% new material. I will publish drafts online as I go. The final book will be published on paper by Apress. The book will remain online under the <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">CC-BY-3.0</a> license.
|
||||
<p>There is a <a href="http://hg.diveintopython3.org/">changelog</a>, a <a rel="alternate" type="application/atom+xml" href="http://hg.diveintopython3.org/atom-log">feed</a>, and <a href="http://www.reddit.com/search?q=%22Dive+Into+Python+3%22">discussion on Reddit</a>. The final version will offer HTML and PDF downloads. During development, the only way to download it is to clone the Mercurial repository:
|
||||
<pre><samp class="prompt">you@localhost:~$ </samp><kbd>hg clone http://hg.diveintopython3.org/ dip3</kbd></pre>
|
||||
<p style="clear:both;margin-top:0;padding-top:1.75em"><cite>Dive Into Python 3</cite> will cover Python 3 and its differences from Python 2. Compared to the original <cite><a href="http://diveintopython.org/">Dive Into Python</a></cite>, it will be about 50% revised and 50% new material. I will publish drafts online as I go. The final version will be published on paper by Apress. The book will remain online under the <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">CC-BY-3.0</a> license.
|
||||
<p>There is a <a href="http://hg.diveintopython3.org/">changelog</a>, a <a rel="alternate" type="application/atom+xml" href="http://hg.diveintopython3.org/atom-log">feed</a>, and <a href="http://www.reddit.com/search?q=%22Dive+Into+Python+3%22">discussion on Reddit</a>. The final version will be downloadable as HTML and PDF. During development, the only way to download it is to clone the Mercurial repository:
|
||||
<pre><samp class="prompt">you@localhost:~$ </samp><kbd>hg clone http://hg.diveintopython3.org/ diveintopython3</kbd></pre>
|
||||
<p>Below is the draft table of contents. It is <b>not finalized</b>. Only a few chapters have been written so far. The rest is just stubs and random notes to myself.
|
||||
<h1>Installing Python</h1>
|
||||
<h2>Python on Windows</h2>
|
||||
@@ -31,17 +32,13 @@ h3{margin-left:3.5em}
|
||||
<h2>Writing readable code</h2>
|
||||
<h3>Why bother?</h3>
|
||||
<h3>Docstrings</h3>
|
||||
<!-- http://www.python.org/dev/peps/pep-0257/ -->
|
||||
<h3>Function annotations</h3>
|
||||
<h3>Style conventions</h3>
|
||||
<!-- http://www.python.org/dev/peps/pep-0008/ -->
|
||||
<h3>...</h3>
|
||||
<h2>Everything is an object</h2>
|
||||
<h3>The import search path</h3>
|
||||
<h3>What's an object?</h3>
|
||||
<h2>Indenting code</h2>
|
||||
<h2>Testing modules</h2>
|
||||
</section>
|
||||
<h2>Summary</h2>
|
||||
<h1>Native Python datatypes</h1>
|
||||
<!-- "Lists and tuples and sets, oh my!" -->
|
||||
|
||||
@@ -10,10 +10,11 @@ h1:before{counter-increment:h1;content:"Appendix A. "}
|
||||
h2:before{counter-increment:h2;content:"A." counter(h2) ". "}
|
||||
h3:before{counter-increment:h3;content:"A." counter(h2) "." counter(h3) ". "}
|
||||
</style>
|
||||
<script type="text/javascript" src="dip3.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p class="skip"><a href="#divingin">skip to main content</a>
|
||||
<form action="http://www.google.com/cse" id="search"><div><input type="hidden" name="cx" value="014021643941856155761:l5eihuescdw"><input type="hidden" name="ie" value="UTF-8"> <input name="q" size="31"> <input type="submit" name="sa" value="Search"></div><p>You are here: <a href="index.html">Dive Into Python 3</a> <span>‣</span> <b>Appendix A</b></form>
|
||||
<form action="http://www.google.com/cse" id="search"><div><input type="hidden" name="cx" value="014021643941856155761:l5eihuescdw"><input type="hidden" name="ie" value="UTF-8"> <input name="q" size="31"> <input type="submit" name="sa" value="Search"></div><p>You are here: <a href="index.html">Dive Into Python 3</a> <span>‣</span> <b>Appendix A</b></p></form>
|
||||
<h1>Porting code to Python 3 with <code>2to3</code></h1>
|
||||
<blockquote class="q">
|
||||
<p><span>❝</span> Life is pleasant. Death is peaceful. It’s the transition that’s troublesome. <span>❞</span><br>— Isaac Asimov (attributed)
|
||||
@@ -144,8 +145,8 @@ h3:before{counter-increment:h3;content:"A." counter(h2) "." counter(h3) ". "}
|
||||
</table>
|
||||
<p id="skipcompareunicode">
|
||||
<h2 id="long"><code>long</code> data type</h2>
|
||||
<p>Python 2 had separate <code>int</code> and <code>long</code> types for non-floating-point numbers. An <code>int</code> could not be any larger than <a href="#renames"><code>sys.maxint</code></a>, which varied by platform. Longs were defined by appending an <code>L</code> to the end of the number, and they could be, well, longer than ints. In Python 3, there is only one integer type, called <code>int</code>, which mostly behaves like the <code>long</code> type in Python 2. Further reading: <a href="http://www.python.org/dev/peps/pep-0237/">PEP 237: Unifying Long Integers and Integers</a>.
|
||||
<p>Since there are no longer two types, there is no need for special syntax to distinguish them.
|
||||
<p>Python 2 had separate <code>int</code> and <code>long</code> types for non-floating-point numbers. An <code>int</code> could not be any larger than <a href="#renames"><code>sys.maxint</code></a>, which varied by platform. Longs were defined by appending an <code>L</code> to the end of the number, and they could be, well, longer than ints. In Python 3, there is only one integer type, called <code>int</code>, which mostly behaves like the <code>long</code> type in Python 2. Since there are no longer two types, there is no need for special syntax to distinguish them.
|
||||
<p>Further reading: <a href="http://www.python.org/dev/peps/pep-0237/">PEP 237: Unifying Long Integers and Integers</a>.
|
||||
<p class="skip"><a href="#skipcomparelong">skip over this table</a>
|
||||
<table id="comparelong">
|
||||
<tr><th>Notes</th>
|
||||
@@ -1271,40 +1272,5 @@ do_stuff(a_list)</code></pre></td></tr>
|
||||
<p id="skipcompareidioms">
|
||||
<p>FIXME: once the rest of the book is written, this appendix should contain copious links back to any chapter or section that touches on these features.
|
||||
<p class="c">© 2001-4, 2009 <span>ℳ</span>ark Pilgrim, <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">CC-BY-3.0</a>
|
||||
<script type="text/javascript">
|
||||
window.onload = function() {
|
||||
var arTables = document.getElementsByTagName('table');
|
||||
for (var i = arTables.length - 1; i >= 0; i--) {
|
||||
var elmTable = arTables[i];
|
||||
var olNotes = document.getElementById("skip" + elmTable.id);
|
||||
if (!olNotes) { continue; }
|
||||
var arNotes = olNotes.getElementsByTagName('li');
|
||||
var arTableRows = elmTable.getElementsByTagName('tr');
|
||||
if (arNotes.length == 0) { continue; }
|
||||
for (var j = arTableRows.length - 1; j >= 1; j--) {
|
||||
var elmTableRow = arTableRows[j];
|
||||
var elmNote = arNotes[j - 1];
|
||||
elmTableRow._li = elmNote;
|
||||
elmNote._tr = elmTableRow;
|
||||
elmTableRow.onmouseover = function() {
|
||||
this.className = 'hover';
|
||||
this._li.className = 'hover';
|
||||
};
|
||||
elmNote.onmouseover = function() {
|
||||
this.className = 'hover';
|
||||
this._tr.className = 'hover';
|
||||
};
|
||||
elmTableRow.onmouseout = function() {
|
||||
this.className = '';
|
||||
this._li.className = '';
|
||||
};
|
||||
elmNote.onmouseout = function() {
|
||||
this.className = '';
|
||||
this._tr.className = '';
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+128
-10
@@ -6,12 +6,13 @@
|
||||
<link rel="alternate" type="application/atom+xml" href="http://hg.diveintopython3.org/atom-log">
|
||||
<link rel="stylesheet" type="text/css" href="dip3.css">
|
||||
<style type="text/css">
|
||||
body{counter-reset:h1 1}
|
||||
body{counter-reset:h1 0}
|
||||
</style>
|
||||
<script type="text/javascript" src="dip3.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p class="skip"><a href="#divingin">skip to main content</a>
|
||||
<form action="http://www.google.com/cse" id="search"><div><input type="hidden" name="cx" value="014021643941856155761:l5eihuescdw"><input type="hidden" name="ie" value="UTF-8"> <input name="q" size="31"> <input type="submit" name="sa" value="Search"></div><p>You are here: <a href="index.html">Dive Into Python 3</a> <span>‣</span> <b>Chapter 2</b></form>
|
||||
<form action="http://www.google.com/cse" id="search"><div><input type="hidden" name="cx" value="014021643941856155761:l5eihuescdw"><input type="hidden" name="ie" value="UTF-8"> <input name="q" size="31"> <input type="submit" name="sa" value="Search"></div><p>You are here: <a href="index.html">Dive Into Python 3</a> <span>‣</span> <b>1. Your first Python program</b></p></form>
|
||||
<h1>Your first Python program</h1>
|
||||
<blockquote class="q">
|
||||
<p><span>❝</span> Don’t bury your burden in saintly silence. You have a problem? Great. Rejoice, dive in, and investigate. <span>❞</span><br>— <cite>Ven. Henepola Gunararatana</cite>
|
||||
@@ -20,6 +21,19 @@ body{counter-reset:h1 1}
|
||||
<li><a href="#divingin">Diving in</a>
|
||||
<li><a href="#declaringfunctions">Declaring functions</a>
|
||||
<li><a href="#readability">Writing readable code</a>
|
||||
<ol>
|
||||
<li><a href="#whybother">Why bother?</a>
|
||||
<li><a href="#docstrings">Docstrings</a>
|
||||
<li><a href="#functionannotations">Function annotations</a>
|
||||
<li><a href="#styleconventions">Style conventions</a>
|
||||
</ol>
|
||||
<li><a href="#everythingisanobject">Everything is an object</a>
|
||||
<ol>
|
||||
<li><a href="#importsearchpath">The <code>import</code> search path</a>
|
||||
<li><a href="#whatsanobject">What's an object?</a>
|
||||
</ol>
|
||||
<li><a href="#indentingcode">Indenting code</a>
|
||||
<li><a href="#runningscripts">Running scripts</a>
|
||||
</ol>
|
||||
<h2 id="divingin">Diving in</h2>
|
||||
<p class="fancy">You know how other books go on and on about programming fundamentals and finally work up to building something useful? Let's skip all that. Here is a complete, working Python program. It probably makes absolutely no sense to you. Don't worry about that, because you're going to dissect it line by line. But read through it first and see what, if anything, you can make of it.
|
||||
@@ -67,8 +81,8 @@ if __name__ == "__main__":
|
||||
<blockquote class="note">
|
||||
<p><span>☞</span>In some languages, functions (that return a value) start with <code>function</code>, and subroutines (that do not return a value) start with <code>sub</code>. There are no subroutines in Python. Everything is a function, all functions return a value (even if it's <code>None</code>), and all functions start with <code>def</code>.
|
||||
</blockquote>
|
||||
<p>The <code>approximate_size</code> function takes the two arguments — <var>size</var> and <var>a_kilobyte_is_1024_bytes</var> — but neither argument specifies a datatype. (As you might guess from the <code>=True</code> syntax, the second argument is a boolean. You'll learn what that syntax does in [FIXME xref].) In Python, variables are never explicitly typed. Python figures out what type a variable is and keeps track of it internally.
|
||||
<blockquote class="note">
|
||||
<p>The <code>approximate_size</code> function takes the two arguments — <var>size</var> and <var>a_kilobyte_is_1024_bytes</var> — but neither argument specifies a datatype. (As you might guess from the <code>=True</code> syntax, the second argument is a boolean. You'll learn what that syntax does in [FIXME xref-was-#apihelper].) In Python, variables are never explicitly typed. Python figures out what type a variable is and keeps track of it internally.
|
||||
<blockquote class="note compare-java compare-cplusplus">
|
||||
<p><span>☞</span>In Java, <acronym>C++</acronym>, and other statically-typed languages, you must specify the datatype of the function return value and each function argument. In Python, you never explicitly specify the datatype of anything. Based on what value you assign, Python keeps track of the datatype internally.
|
||||
</blockquote>
|
||||
<h3>How Python's Datatypes Compare to Other Programming Languages</h3>
|
||||
@@ -95,10 +109,10 @@ if __name__ == "__main__":
|
||||
<tr><th>Strongly typed</th><td>Pascal, Java</td><td>Python, Ruby</td></tr>
|
||||
</table>
|
||||
<h2 id="readability">Writing readable code</h2>
|
||||
|
||||
FIXME
|
||||
|
||||
<p>You can document a Python function by giving it a <code>docstring</code>. In this program, the <code>approximate_size</code> function has a <code>docstring</code>:
|
||||
<h3 id="whybother">Why bother?</h3>
|
||||
<p>FIXME
|
||||
<h3 id="docstrings">Documentation strings</h3>
|
||||
<p>You can document a Python function by giving it a documentation string (<code>docstring</code> for short). In this program, the <code>approximate_size</code> function has a <code>docstring</code>:
|
||||
<pre><code>def approximate_size(size, a_kilobyte_is_1024_bytes=True):
|
||||
"""Convert a file size to human-readable form.
|
||||
|
||||
@@ -110,14 +124,18 @@ FIXME
|
||||
Returns: string
|
||||
|
||||
"""</code></pre>
|
||||
<p>Triple quotes signify a multi-line string. Everything between the start and end quotes is part of a single string, including carriage returns and other quote characters. You can use them anywhere, but you'll see them most often used when defining a <code>docstring</code>.
|
||||
<blockquote class="note">
|
||||
<p>Triple quotes signify a multi-line string. Everything between the start and end quotes is part of a single string, including carriage returns, leading white space, and other quote characters. You can use them anywhere, but you'll see them most often used when defining a <code>docstring</code>.
|
||||
<blockquote class="note compare-perl">
|
||||
<p><span>☞</span>Triple quotes are also an easy way to define a string with both single and double quotes, like <code>qq/.../</code> in Perl 5.
|
||||
</blockquote>
|
||||
<p>Everything between the triple quotes is the function's <code>docstring</code>, which documents what the function does. A <code>docstring</code>, if it exists, must be the first thing defined in a function (that is, on the next line after the function declaration). You don't technically need to give your function a <code>docstring</code>, but you always should. I know you've heard this in every programming class you've ever taken, but Python gives you an added incentive: the <code>docstring</code> is available at runtime as an attribute of the function.
|
||||
<blockquote class="note">
|
||||
<p><span>☞</span>Many Python <acronym>IDE</acronym>s use the <code>docstring</code> to provide context-sensitive documentation, so that when you type a function name, its <code>docstring</code> appears as a tooltip. This can be incredibly helpful, but it's only as good as the <code>docstring</code>s you write.
|
||||
</blockquote>
|
||||
<h3 id="functionannotations">Function annotations</h3>
|
||||
<p>FIXME
|
||||
<h3 id="styleconventions">Style conventions</h3>
|
||||
<p>FIXME
|
||||
<div class="fr">
|
||||
<h4>Further reading</h4>
|
||||
<ul>
|
||||
@@ -126,6 +144,106 @@ FIXME
|
||||
<li><a href="http://docs.python.org/3.0/tutorial/controlflow.html#documentation-strings">Python Tutorial: Documentation Strings</a>
|
||||
</ul>
|
||||
</div>
|
||||
<h2 id="everythingisanobject">Everything is an object</h2>
|
||||
<p>In case you missed it, I just said that Python functions have attributes, and that those attributes are available at runtime. A function, like everything else in Python, is an object.
|
||||
<p>Run the interactive Python shell and follow along:
|
||||
<pre class="screen">
|
||||
<a><samp class="prompt">>>> </samp><kbd>import humansize</kbd> <span>①</span></a>
|
||||
<a><samp class="prompt">>>> </samp><kbd>print(humansize.approximate_size(4096, True))</kbd> <span>②</span></a>
|
||||
<samp>4.0 KiB</samp>
|
||||
<a><samp class="prompt">>>> </samp><kbd>print(humansize.approximate_size.__doc__)</kbd> <span>③</span></a>
|
||||
<samp>Convert a file size to human-readable form.
|
||||
|
||||
Keyword arguments:
|
||||
size -- file size in bytes
|
||||
a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
|
||||
if False, use multiples of 1000
|
||||
|
||||
Returns: string
|
||||
|
||||
</samp></pre>
|
||||
<ol>
|
||||
<li>The first line imports the <code>humansize</code> program as a module -- a chunk of code that you can use interactively, or from a larger Python program. (You'll see examples of multi-module Python programs in [FIXME xref].) Once you import a module, you can reference any of its public functions, classes, or attributes. Modules can do this to access functionality in other modules, and you can do it in the Python interactive shell too. This is an important concept, and you'll see a lot more of it throughout this book.
|
||||
<li>When you want to use functions defined in imported modules, you need to include the module name. So you can't just say <code>approximate_size</code>; it must be <code>humansize.approximate_size</code>. If you've used classes in Java, this should feel vaguely familiar.
|
||||
<li>Instead of calling the function as you would expect to, you asked for one of the function's attributes, <code>__doc__</code>.
|
||||
</ol>
|
||||
<blockquote class="note compare-perl">
|
||||
<p><span>☞</span><code>import</code> in Python is like <code>require</code> in Perl. Once you <code>import</code> a Python module, you access its functions with <code><var>module</var>.<var>function</var></code>; once you <code>require</code> a Perl module, you access its functions with <code><var>module</var>::<var>function</var></code>.
|
||||
</blockquote>
|
||||
<h3 id="importsearchpath">The <code>import</code> search path</h3>
|
||||
<p>Before this goes any further, I want to briefly mention the library search path. Python looks in several places when you try to import a module. Specifically, it looks in all the directories defined in <code>sys.path</code>. This is just a list, and you can easily view it or modify it with standard list methods. (You'll learn more about lists later in this chapter.)
|
||||
<pre class="screen">
|
||||
<a><samp class="prompt">>>> </samp><kbd>import sys</kbd> <span>①</span></a>
|
||||
<a><samp class="prompt">>>> </samp><kbd>sys.path</kbd> <span>②</span></a>
|
||||
<samp>['', '/usr/lib/python30.zip', '/usr/lib/python3.0', '/usr/lib/python3.0/plat-linux2@EXTRAMACHDEPPATH@', '/usr/lib/python3.0/lib-dynload', '/usr/lib/python3.0/dist-packages', '/usr/local/lib/python3.0/dist-packages']</samp>
|
||||
<a><samp class="prompt">>>> </samp><kbd>sys</kbd> <span>③</span></a>
|
||||
<samp><module 'sys' (built-in)></samp>
|
||||
<a><samp class="prompt">>>> </samp><kbd>sys.path.append('/my/new/path')</kbd> <span>④</span></a></pre>
|
||||
<ol>
|
||||
<li>Importing the <code>sys</code> module makes all of its functions and attributes available.
|
||||
<li><code>sys.path</code> is a list of directory names that constitute the current search path. (Yours will look different, depending on your operating system, what version of Python you're running, and where it was originally installed.) Python will look through these directories (in this order) for a <code>.py</code> file whose name matches what you're trying to import.
|
||||
<li>Actually, I lied; the truth is more complicated than that, because not all modules are stored as <code>.py</code> files. Some, like the <code>sys</code> module, are "built-in modules"; they are actually baked right into Python itself. Built-in modules behave just like regular modules, but their Python source code is not available, because they are not written in Python! (The <code>sys</code> module is written in <acronym>C</acronym>.)
|
||||
<li>You can add a new directory to Python's search path at runtime by appending the directory name to <code>sys.path</code>, and then Python will look in that directory as well, whenever you try to import a module. The effect lasts as long as Python is running. (You'll learn more about <code>append()</code> and other list methods in [FIXME xref-was-#datatypes].)
|
||||
</ol>
|
||||
<h3 id="whatsanobject">What's an object?</h3>
|
||||
<p>Everything in Python is an object, and almost everything has attributes and methods. All functions have a built-in attribute <code>__doc__</code>, which returns the <var>docstring</var> defined in the function's source code. The <code>sys</code> module is an object which has (among other things) an attribute called <var>path</var>. And so forth.
|
||||
<p>Still, this doesn't answer the more fundamental question: what is an object? Different programming languages define “object” in different ways. In some, it means that <em>all</em> objects <em>must</em> have attributes and methods; in others, it means that all objects are subclassable. In Python, the definition is looser; some objects have neither attributes nor methods (more on this in [FIXME xref-was-#datatypes]), and not all objects are subclassable (more on this in [FIXME xref-was-#fileinfo]). But everything is an object in the sense that it can be assigned to a variable or passed as an argument to a function (more in this in [FIXME xref-was-#apihelp]).
|
||||
<p>This is so important that I'm going to repeat it in case you missed it the first few times: <em>everything in Python is an object</em>. Strings are objects. Lists are objects. Functions are objects. Even modules are objects.
|
||||
<div class="itemizedlist">
|
||||
<div class="fr">
|
||||
<h4>Further reading</h4>
|
||||
<ul>
|
||||
<li><a href="http://docs.python.org/3.0/reference/"><cite>Python Reference Manual</cite></a> explains exactly what it means to say that <a href="http://docs.python.org/3.0/reference/datamodel.html#objects-values-and-types">everything in Python is an object</a>, because some people are pedantic and like to discuss this sort of thing at great length.
|
||||
</ul>
|
||||
</div>
|
||||
<h2 id="indentingcode">Indenting code</h2>
|
||||
<p>Python functions have no explicit <code>begin</code> or <code>end</code>, and no curly braces to mark where the function code starts and stops. The only delimiter is a colon (<code>:</code>) and the indentation of the code itself.
|
||||
<pre><code>
|
||||
<a>def approximate_size(size, a_kilobyte_is_1024_bytes=True): <span>①</span></a>
|
||||
<a> if size < 0: <span>②</span></a>
|
||||
<a> raise ValueError('number must be non-negative') <span>③</span></a>
|
||||
<a> <span>④</span></a>
|
||||
multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
|
||||
<a> for suffix in SUFFIXES[multiple]: <span>⑤</span></a>
|
||||
size /= multiple
|
||||
if size < multiple:
|
||||
return "{0:.1f} {1}".format(size, suffix)
|
||||
|
||||
raise ValueError('number too large')</code></pre>
|
||||
<ol>
|
||||
<li>Code blocks are defined by their indentation. By "code block," I mean functions, <code>if</code> statements, <code>for</code> loops, <code>while</code> loops, and so forth. Indenting starts a block and unindenting ends it. There are no explicit braces, brackets, or keywords. This means that whitespace is significant, and must be consistent. In this example, the function code is indented four spaces. It doesn't need to be four spaces, it just needs to be consistent. The first line that is not indented marks the end of the function.
|
||||
<li>In Python, an <code>if</code> statement is followed by a code block. If the <code>if</code> expression evaluates to true, the indented block is executed, otherwise it falls to the <code>else</code> block (if any). (Note the lack of parentheses around the expression.)
|
||||
<li>This line is inside the <code>if</code> code block. This <code>raise</code> statement will raise an exception (of type <code>ValueError</code>), but only if <code>size < 0</code>.
|
||||
<li>This is <em>not</em> the end of the function. Completely blank lines don't count. The function continues on the next line.
|
||||
<li>The <code>for</code> loop also marks the start of a code block. Code blocks can contain multiple lines, as long as they are all indented the same amount. This <code>for</code> loop has three lines of code in it. There is no other special syntax for multi-line code blocks. Just indent and get on with your life.
|
||||
</ol>
|
||||
<p>After some initial protests and several snide analogies to Fortran, you will make peace with this and start seeing its benefits. One major benefit is that all Python programs look similar, since indentation is a language requirement and not a matter of style. This makes it easier to read and understand other people's Python code.
|
||||
<blockquote class="note compare-java">
|
||||
<p><span>☞</span>Python uses carriage returns to separate statements and a colon and indentation to separate code blocks. <acronym>C++</acronym> and Java use semicolons to separate statements and curly braces to separate code blocks.
|
||||
</blockquote>
|
||||
<div class="fr">
|
||||
<h4>Further reading</h4>
|
||||
<ul>
|
||||
<li><a href="http://www.python.org/dev/peps/pep-0008/">PEP 8: Style Guide for Python Code</a> discusses good indentation style.
|
||||
</ul>
|
||||
</div>
|
||||
<h2 id="runningscripts">Running scripts</h2>
|
||||
<p>Python modules are objects and have several useful attributes. You can use this to easily test your modules as you write them, by including a special block of code that executes when you run the Python file on the command line. Take the last few lines of <code>humansize.py</code>:
|
||||
<pre><code>
|
||||
if __name__ == "__main__":
|
||||
print(approximate_size(1000000000000, False))
|
||||
print(approximate_size(1000000000000))</code></pre>
|
||||
<blockquote class="note compare-c">
|
||||
<p><span>☞</span>Like <acronym>C</acronym>, Python uses <code>==</code> for comparison and <code>=</code> for assignment. Unlike <acronym>C</acronym>, Python does not support in-line assignment, so there's no chance of accidentally assigning the value you thought you were comparing.
|
||||
</blockquote>
|
||||
<p>So what makes this <code>if</code> statement special? Well, modules are objects, and all modules have a built-in attribute <code>__name__</code>. A module's <code>__name__</code> depends on how you're using the module. If you <code>import</code> the module, then <code>__name__</code> is the module's filename, without a directory path or file extension.
|
||||
<pre class="screen"><samp class="prompt">>>> </samp><kbd>import humansize</kbd>
|
||||
<samp class="prompt">>>> </samp><kbd>humansize.__name__</kbd>
|
||||
<samp>'humansize'</samp></pre>
|
||||
<p>But you can also run the module directly as a standalone program, in which case <code>__name__</code> will be a special default value, <code>__main__</code>. Python will evaluate this <code>if</code> statement, find a true expression, and execute the <code>if</code> code block. In this case, to print two values.
|
||||
<pre><samp class="prompt">c:\home\diveintopython3> </samp><kbd>c:\python30\python.exe humansize.py</kbd>
|
||||
<samp>1.0 TB
|
||||
931.3 GiB</samp></pre>
|
||||
<p class="c">© 2001-4, 2009 <span>ℳ</span>ark Pilgrim, <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">CC-BY-3.0</a>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user