mirror of
https://github.com/kennethreitz/dive-into-python3.git
synced 2026-06-05 15:00:18 +00:00
added section on exceptions to your-first-python-program
This commit is contained in:
@@ -385,15 +385,18 @@ if __name__ == "__main__":
|
||||
<td rowspan="2" align="center" valign="top" width="1%"><img src="images/note.png" alt="Note" title="" width="24" height="24"><td colspan="2" align="left" valign="top" width="99%">When a command is split among several lines with the line-continuation marker (“<code>\</code>”), the continued lines can be indented in any manner; Python's normally stringent indentation rules do not apply. If your Python <abbr>IDE</abbr> auto-indents the continued line, you should probably accept its default unless you have a burning reason not to.
|
||||
<p><a name="tip.implicitmultiline"></a>Strictly speaking, expressions in parentheses, straight brackets, or curly braces (like <a href="#myparamsdef" title="Example 3.17. Defining the myParams Variable">defining a dictionary</a>) can be split into multiple lines with or without the line continuation character (“<code>\</code>”). I like to include the backslash even when it's not required because I think it makes the code easier to read, but that's
|
||||
a matter of style.
|
||||
<p>Third, you never declared the variable <var>myParams</var>, you just assigned a value to it. This is like VBScript without the <code>option explicit</code> option. Luckily, unlike VBScript, Python will not allow you to reference a variable that has never been assigned a value; trying to do so will raise an exception.
|
||||
<h3>3.4.1. Referencing Variables</h3>
|
||||
<div class=example><h3 id="odbchelper.unboundvariable">Example 3.18. Referencing an Unbound Variable</h3><pre class=screen><samp class=p>>>> </samp><kbd>x</kbd>
|
||||
<samp class=traceback>Traceback (innermost last):
|
||||
File "<interactive input>", line 1, in ?
|
||||
NameError: There is no variable named 'x'</samp>
|
||||
<samp class=p>>>> </samp><kbd>x = 1</kbd>
|
||||
<samp class=p>>>> </samp><kbd>x</kbd>
|
||||
1</pre><p>You will thank Python for this one day.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[unbound variable exception example was here]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 id="odbchelper.multiassign">3.4.2. Assigning Multiple Values at Once</h3>
|
||||
<p>One of the cooler programming shortcuts in Python is using sequences to assign multiple values at once.
|
||||
<div class=example><h3>Example 3.19. Assigning multiple values at once</h3><pre class=screen><samp class=p>>>> </samp><kbd>v = ('a', 'b', 'e')</kbd>
|
||||
@@ -1604,104 +1607,12 @@ AttributeError: 'MP3FileInfo' instance has no attribute '__parse'</span></pre>
|
||||
<li>Defining <a href="#fileinfo.private" title="5.9. Private Functions">private attributes and methods</a>
|
||||
</ul>
|
||||
<div class=chapter>
|
||||
<h2 id="filehandling">Chapter 6. Exceptions and File Handling</h2>
|
||||
<p>In this chapter, you will dive into exceptions, file objects, <code>for</code> loops, and the <code>os</code> and <code>sys</code> modules. If you've used exceptions in another programming language, you can skim the first section to get a sense of Python's syntax. Be sure to tune in again for file handling.
|
||||
<h2 id="fileinfo.exception">6.1. Handling Exceptions</h2>
|
||||
<p>Like many other programming languages, Python has exception handling via <code>try...except</code> blocks.
|
||||
<table id="compare.exceptions.java" class=note border="0" summary="">
|
||||
|
||||
<td rowspan="2" align="center" valign="top" width="1%"><img src="images/note.png" alt="Note" title="" width="24" height="24"><td colspan="2" align="left" valign="top" width="99%">Python uses <code>try...except</code> to handle exceptions and <code>raise</code> to generate them. Java and <abbr>C++</abbr> use <code>try...catch</code> to handle exceptions, and <code>throw</code> to generate them.
|
||||
<p>Exceptions are everywhere in Python. Virtually every module in the standard Python library uses them, and Python itself will raise them in a lot of different circumstances. You've already seen them repeatedly throughout this book.
|
||||
<div class=itemizedlist>
|
||||
<ul>
|
||||
<li><a href="#odbchelper.dict.define" title="Example 3.1. Defining a Dictionary">Accessing a non-existent dictionary key</a> will raise a <code>KeyError</code> exception.
|
||||
|
||||
<li><a href="#odbchelper.list.search" title="Example 3.12. Searching a List">Searching a list for a non-existent value</a> will raise a <code>ValueError</code> exception.
|
||||
|
||||
<li><a href="#odbchelper.tuplemethods" title="Example 3.16. Tuples Have No Methods">Calling a non-existent method</a> will raise an <code>AttributeError</code> exception.
|
||||
|
||||
<li><a href="#odbchelper.unboundvariable" title="Example 3.18. Referencing an Unbound Variable">Referencing a non-existent variable</a> will raise a <code>NameError</code> exception.
|
||||
|
||||
<li><a href="#odbchelper.stringformatting.coerce" title="Example 3.22. String Formatting vs. Concatenating">Mixing datatypes without coercion</a> will raise a <code>TypeError</code> exception.
|
||||
|
||||
</ul>
|
||||
<p>In each of these cases, you were simply playing around in the Python <abbr>IDE</abbr>: an error occurred, the exception was printed (depending on your <abbr>IDE</abbr>, perhaps in an intentionally jarring shade of red), and that was that. This is called an <em>unhandled</em> exception. When the exception was raised, there was no code to explicitly notice it and deal with it, so it bubbled its
|
||||
way back to the default behavior built in to Python, which is to spit out some debugging information and give up. In the <abbr>IDE</abbr>, that's no big deal, but if that happened while your actual Python program was running, the entire program would come to a screeching halt.
|
||||
<p>An exception doesn't need result in a complete program crash, though. Exceptions, when raised, can be <em>handled</em>. Sometimes an exception is really because you have a bug in your code (like accessing a variable that doesn't exist), but
|
||||
many times, an exception is something you can anticipate. If you're opening a file, it might not exist. If you're connecting
|
||||
to a database, it might be unavailable, or you might not have the correct security credentials to access it. If you know
|
||||
a line of code may raise an exception, you should handle the exception using a <code>try...except</code> block.
|
||||
<div class=example><h3>Example 6.1. Opening a Non-Existent File</h3><pre class=screen><samp class=p>>>> </samp><kbd>fsock = open("/notthere", "r")</kbd> <span>①</span>
|
||||
<samp class=traceback>Traceback (innermost last):
|
||||
File "<interactive input>", line 1, in ?
|
||||
IOError: [Errno 2] No such file or directory: '/notthere'</samp>
|
||||
<samp class=p>>>> </samp><kbd>try:</kbd>
|
||||
<samp class=p>... </samp>fsock = open("/notthere") <span>②</span>
|
||||
<samp class=p>... </samp>except IOError: <span>③</span>
|
||||
<samp class=p>... </samp>print "The file does not exist, exiting gracefully"
|
||||
<samp class=p>... </samp>print "This line will always print" <span>④</span>
|
||||
<samp>The file does not exist, exiting gracefully
|
||||
This line will always print</span></pre>
|
||||
<ol>
|
||||
<li>Using the built-in <code>open</code> function, you can try to open a file for reading (more on <code>open</code> in the next section). But the file doesn't exist, so this raises the <code>IOError</code> exception. Since you haven't provided any explicit check for an <code>IOError</code> exception, Python just prints out some debugging information about what happened and then gives up.
|
||||
<li>You're trying to open the same non-existent file, but this time you're doing it within a <code>try...except</code> block.
|
||||
<li>When the <code>open</code> method raises an <code>IOError</code> exception, you're ready for it. The <code>except IOError:</code> line catches the exception and executes your own block of code, which in this case just prints a more pleasant error message.
|
||||
<li>Once an exception has been handled, processing continues normally on the first line after the <code>try...except</code> block. Note that this line will always print, whether or not an exception occurs. If you really did have a file called
|
||||
<code>notthere</code> in your root directory, the call to <code>open</code> would succeed, the <code>except</code> clause would be ignored, and this line would still be executed.
|
||||
<p>Exceptions may seem unfriendly (after all, if you don't catch the exception, your entire program will crash), but consider
|
||||
the alternative. Would you rather get back an unusable file object to a non-existent file? You'd need to check its validity
|
||||
somehow anyway, and if you forgot, somewhere down the line, your program would give you strange errors somewhere down the
|
||||
line that you would need to trace back to the source. I'm sure you've experienced this, and you know it's not fun. With
|
||||
exceptions, errors occur immediately, and you can handle them in a standard way at the source of the problem.
|
||||
<h3>6.1.1. Using Exceptions For Other Purposes</h3>
|
||||
<p>There are a lot of other uses for exceptions besides handling actual error conditions. A common use in the standard Python library is to try to import a module, and then check whether it worked. Importing a module that does not exist will raise
|
||||
an <code>ImportError</code> exception. You can use this to define multiple levels of functionality based on which modules are available at run-time,
|
||||
or to support multiple platforms (where platform-specific code is separated into different modules).
|
||||
<p>You can also define your own exceptions by creating a class that inherits from the built-in <code>Exception</code> class, and then raise your exceptions with the <code>raise</code> command. See the further reading section if you're interested in doing this.
|
||||
<p>The next example demonstrates how to use an exception to support platform-specific functionality. This code comes from the
|
||||
<code>getpass</code> module, a wrapper module for getting a password from the user. Getting a password is accomplished differently on <abbr>UNIX</abbr>, Windows, and Mac OS platforms, but this code encapsulates all of those differences.
|
||||
<div class=example><h3 id="crossplatform.example">Example 6.2. Supporting Platform-Specific Functionality</h3><pre><code>
|
||||
# Bind the name getpass to the appropriate function
|
||||
try:
|
||||
import termios, TERMIOS <span>①</span>
|
||||
except ImportError:
|
||||
try:
|
||||
import msvcrt <span>②</span>
|
||||
except ImportError:
|
||||
try:
|
||||
from EasyDialogs import AskPassword <span>③</span>
|
||||
except ImportError:
|
||||
getpass = default_getpass <span>④</span>
|
||||
else: <span>⑤</span>
|
||||
getpass = AskPassword
|
||||
else:
|
||||
getpass = win_getpass
|
||||
else:
|
||||
getpass = unix_getpass</pre>
|
||||
<ol>
|
||||
<li><code>termios</code> is a <abbr>UNIX</abbr>-specific module that provides low-level control over the input terminal. If this module is not available (because it's not
|
||||
on your system, or your system doesn't support it), the import fails and Python raises an <code>ImportError</code>, which you catch.
|
||||
<li>OK, you didn't have <code>termios</code>, so let's try <code>msvcrt</code>, which is a Windows-specific module that provides an <abbr>API</abbr> to many useful functions in the Microsoft Visual C++ runtime services. If this import fails, Python will raise an <code>ImportError</code>, which you catch.
|
||||
<li>If the first two didn't work, you try to import a function from <code>EasyDialogs</code>, which is a Mac OS-specific module that provides functions to pop up dialog boxes of various types. Once again, if this import fails, Python will raise an <code>ImportError</code>, which you catch.
|
||||
<li>None of these platform-specific modules is available (which is possible, since Python has been ported to a lot of different platforms), so you need to fall back on a default password input function (which is
|
||||
defined elsewhere in the <code>getpass</code> module). Notice what you're doing here: assigning the function <code>default_getpass</code> to the variable <var>getpass</var>. If you read the official <code>getpass</code> documentation, it tells you that the <code>getpass</code> module defines a <code>getpass</code> function. It does this by binding <var>getpass</var> to the correct function for your platform. Then when you call the <code>getpass</code> function, you're really calling a platform-specific function that this code has set up for you. You don't need to know or
|
||||
care which platform your code is running on -- just call <code>getpass</code>, and it will always do the right thing.
|
||||
<li>A <code>try...except</code> block can have an <code>else</code> clause, like an <code>if</code> statement. If no exception is raised during the <code>try</code> block, the <code>else</code> clause is executed afterwards. In this case, that means that the <code>from EasyDialogs import AskPassword</code> import worked, so you should bind <var>getpass</var> to the <code>AskPassword</code> function. Each of the other <code>try...except</code> blocks has similar <code>else</code> clauses to bind <var>getpass</var> to the appropriate function when you find an <code>import</code> that works.
|
||||
<div class=itemizedlist>
|
||||
<h3>Further Reading on Exception Handling</h3>
|
||||
<ul>
|
||||
<li><a href="http://www.python.org/doc/current/tut/tut.html"><i class=citetitle>Python Tutorial</i></a> discusses <a href="http://www.python.org/doc/current/tut/node10.html#SECTION0010400000000000000000">defining and raising your own exceptions, and handling multiple exceptions at once</a>.
|
||||
|
||||
<li><a href="http://www.python.org/doc/current/lib/"><i class=citetitle>Python Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/module-exceptions.html">all the built-in exceptions</a>.
|
||||
|
||||
<li><a href="http://www.python.org/doc/current/lib/"><i class=citetitle>Python Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-getpass.html">getpass</a> module.
|
||||
|
||||
<li><a href="http://www.python.org/doc/current/lib/"><i class=citetitle>Python Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-traceback.html"><code>traceback</code> module</a>, which provides low-level access to exception attributes after an exception is raised.
|
||||
|
||||
<li><a href="http://www.python.org/doc/current/ref/"><i class=citetitle>Python Reference Manual</i></a> discusses the inner workings of the <a href="http://www.python.org/doc/current/ref/try.html"><code>try...except</code> block</a>.
|
||||
|
||||
</ul>
|
||||
|
||||
[exception stuff was here]
|
||||
|
||||
|
||||
|
||||
|
||||
Regular → Executable
Regular → Executable
+80
-9
@@ -9,6 +9,7 @@ body{counter-reset:h1 1}
|
||||
table{border:1px solid #bbb;border-collapse:collapse;margin:auto}
|
||||
td,th{border:1px solid #bbb;padding:0 1.75em}
|
||||
th{text-align:left}
|
||||
mark{display:inline}
|
||||
</style>
|
||||
<link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
|
||||
<link rel=stylesheet media=print href=print.css>
|
||||
@@ -54,12 +55,12 @@ if __name__ == '__main__':
|
||||
print(approximate_size(1000000000000, False))
|
||||
print(approximate_size(1000000000000))</code></pre>
|
||||
<p>Now let’s run this program on the command line. On Windows, it will look something like this:
|
||||
<pre class=screen>
|
||||
<pre class='nd screen'>
|
||||
<samp class=p>c:\home\diveintopython3> </samp><kbd>c:\python30\python.exe humansize.py</kbd>
|
||||
<samp>1.0 TB
|
||||
931.3 GiB</samp></pre>
|
||||
<p>On Mac OS X or Linux, it would look something like this:
|
||||
<pre class=screen>
|
||||
<pre class='nd screen'>
|
||||
<samp class=p>you@localhost:~$ </samp><kbd>python3 humansize.py</kbd>
|
||||
<samp>1.0 TB
|
||||
931.3 GiB</samp></pre>
|
||||
@@ -74,7 +75,7 @@ if __name__ == '__main__':
|
||||
|
||||
<h2 id=declaringfunctions>Declaring Functions</h2>
|
||||
<p>Python has functions like most other languages, but it does not have separate header files like <abbr>C++</abbr> or <code>interface</code>/<code>implementation</code> sections like Pascal. When you need a function, just declare it, like this:
|
||||
<pre><code class=pp>def approximate_size(size, a_kilobyte_is_1024_bytes=True):</code></pre>
|
||||
<pre class=nd><code class=pp>def approximate_size(size, a_kilobyte_is_1024_bytes=True):</code></pre>
|
||||
<aside>When you need a function, just declare it.</aside>
|
||||
<p>The keyword <code>def</code> starts the function declaration, followed by the function name, followed by the arguments in parentheses. Multiple arguments are separated with commas.
|
||||
<p>Also note that the function doesn’t define a return datatype. Python functions do not specify the datatype of their return value; they don’t even specify whether or not they return a value. (In fact, every Python function returns a value; if the function ever executes a <code>return</code> statement, it will return that value, otherwise it will return <code>None</code>, the Python null value.)
|
||||
@@ -92,7 +93,7 @@ if __name__ == '__main__':
|
||||
|
||||
<p>Let’s take another look at that <code>approximate_size()</code> function declaration:
|
||||
|
||||
<pre><code class=pp>def approximate_size(size, a_kilobyte_is_1024_bytes=True):</code></pre>
|
||||
<pre class=nd><code class=pp>def approximate_size(size, a_kilobyte_is_1024_bytes=True):</code></pre>
|
||||
|
||||
<p>The second argument, <var>a_kilobyte_is_1024_bytes</var>, specifies a default value of <code>True</code>. This means the argument is <i>optional</i>; you can call the function without it, and Python will act as if you had called it with <code>True</code> as a second parameter.
|
||||
|
||||
@@ -177,7 +178,7 @@ SyntaxError: non-keyword arg after keyword arg</samp></pre>
|
||||
|
||||
</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>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>
|
||||
@@ -237,7 +238,7 @@ SyntaxError: non-keyword arg after keyword arg</samp></pre>
|
||||
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>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. They can make the code more readable, but they don’t count as code block delimiters. 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.
|
||||
@@ -248,10 +249,80 @@ SyntaxError: non-keyword arg after keyword arg</samp></pre>
|
||||
</blockquote>
|
||||
<p class=a>⁂
|
||||
|
||||
<h2 id=exceptions>Exceptions</h2>
|
||||
|
||||
<p>Exceptions are everywhere in Python. Virtually every module in the standard Python library uses them, and Python itself will raise them in a lot of different circumstances. You’ll see them repeatedly throughout this book.
|
||||
|
||||
<p>What is an exception? It’s an error, an indication that something went wrong. Some programming languages encourage the use of error return codes, which you need to check. Python encourages the use of exceptions, which you need to handle.
|
||||
|
||||
<p>When an error occurs in the Python Shell, it prints out some details about the exception and how it happened, and that’s that. This is called an <em>unhandled</em> exception. When the exception was raised, there was no code to explicitly notice it and deal with it, so it bubbled its way back up to the top level of the Python Shell, which spits out some debugging information and calls it a day. In the shell, that's no big deal, but if that happened while your actual Python program was running, the entire program would come to a screeching halt.
|
||||
|
||||
<blockquote class='note compare java'>
|
||||
<p><span class=u>☞</span>Unlike Java, Python functions don’t declare which exceptions they might raise. It’s up to you to determine what possible exceptions you need to catch.
|
||||
</blockquote>
|
||||
|
||||
<p>An exception doesn’t need result in a complete program crash, though. Exceptions can be <em>handled</em>. Sometimes an exception is really because you have a bug in your code (like accessing a variable that doesn’t exist), but sometimes an exception is something you can anticipate. If you’re opening a file, it might not exist. If you’re importing a module, it might not be installed. If you’re connecting to a database, it might be unavailable, or you might not have the correct security credentials to access it. If you know a line of code may raise an exception, you should handle the exception using a <code>try...except</code> block.
|
||||
|
||||
<blockquote class='note compare java'>
|
||||
<p><span class=u>☞</span>Python uses <code>try...except</code> blocks to handle exceptions, and the <code>raise</code> statement to generate them. Java and <abbr>C++</abbr> use <code>try...catch</code> blocks to handle exceptions, and the <code>throw</code> statement to generate them.
|
||||
</blockquote>
|
||||
|
||||
<p>The <code>approximate_size()</code> function raises exceptions in two different cases: if the given <var>size</var> is larger than the function is designed to handle, or if it’s less than zero.
|
||||
|
||||
<pre class=nd><code class=pp>if size < 0:
|
||||
raise ValueError('number must be non-negative')</code></pre>
|
||||
|
||||
<p>The syntax for raising an exception is simple enough. Use the <code>raise</code> statement, followed by the exception name, and an optional human-readable string for debugging purposes. The syntax is reminiscent of calling a function. (In reality, exceptions are implemented as classes, and this <code>raise</code> statement is actually creating an instance of the <code>ValueError</code> class and passing the string <code>'number must be non-negative'</code> to its initialization method. But <a href=iterators.html#defining-classes>we’re getting ahead of ourselves</a><span class=u> </span><em>!</em><span class=u> </span>)
|
||||
|
||||
<h3 id=importerror>Catching Import Errors</h3>
|
||||
|
||||
<p>One of Python’s built-in exceptions is <code>ImportError</code>, which is raised when you try to import a module and fail. This can happen for a variety of reasons, but the simplest case is when the module doesn’t exist in your <a href=#importsearchpath>import search path</a>. You can use this to include optional features in your program. For example, <a href=case-study-porting-chardet-to-python-3.html>the <code>chardet</code> library</a> provides character encoding auto-detection. Perhaps your program wants to use this library <em>if it exists</em>, but continue gracefully if the user hasn’t installed it. You can do this with a <code>try..except</code> block.
|
||||
|
||||
<pre class=nd><code class=pp><mark>try</mark>:
|
||||
import chardet
|
||||
<mark>except</mark> ImportError:
|
||||
chardet = None</code></pre>
|
||||
|
||||
<p>Later, you can check for the presence of the <code>chardet</code> module with a simple <code>if</code> statement:
|
||||
|
||||
<pre class=nd><code class=pp>if chardet:
|
||||
# do something
|
||||
else:
|
||||
# continue anyway</code></pre>
|
||||
|
||||
<p>Another common use of the <code>ImportError</code> exception is when two modules implement a common <abbr>API</abbr>, but one is more desirable than the other. (Maybe it’s faster, or it uses less memory.) You can try to import one module but fall back to a different module if the first import fails. For example, <a href=xml.html>the XML chapter</a> talks about two modules that implement a common <abbr>API</abbr>, called the <code>ElementTree</code> <abbr>API</abbr>. The first, <code>lxml</code>, is a third-party module that you need to download and install yourself. The second, <code>xml.etree.ElementTree</code>, is slower but is part of the Python 3 standard library.
|
||||
|
||||
<pre class=nd><code class=pp>try:
|
||||
from lxml import etree
|
||||
except ImportError:
|
||||
import xml.etree.ElementTree as etree</code></pre>
|
||||
|
||||
<p>By the end of this <code>try..except</code> block, you have imported <em>some</em> module and named it <var>etree</var>. Since both modules implement a common <abbr>API</abbr>, the rest of your code doesn’t need to keep checking which module got imported. And since the module that <em>did</em> get imported is always called <var>etree</var>, the rest of your code doesn’t need to be littered with <code>if</code> statements to call differently-named modules.
|
||||
|
||||
<h3 id=nameerror>Unbound Variables</h3>
|
||||
|
||||
<p>Take another look at this line of code from the <code>approximate_size()</code> function:
|
||||
|
||||
<pre class=nd><code class=pp>multiple = 1024 if a_kilobyte_is_1024_bytes else 1000</code></pre>
|
||||
|
||||
<p>You never declare the variable <var>multiple</var>, you just assign a value to it. That’s OK, because Python lets you do that. What Python will <em>not</em> let you do is reference a variable that has never been assigned a value. Trying to do so will raise a <code>NameError</code> exception.
|
||||
<pre class='nd screen'>
|
||||
<samp class=p>>>> </samp><kbd class=pp>x</kbd>
|
||||
<samp class=traceback>Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
NameError: name 'x' is not defined</samp>
|
||||
<samp class=p>>>> </samp><kbd class=pp>x = 1</kbd>
|
||||
<samp class=p>>>> </samp><kbd class=pp>x</kbd>
|
||||
<samp class=pp>1</samp></pre>
|
||||
|
||||
<p>You will thank Python for this one day.
|
||||
|
||||
<p class=a>⁂
|
||||
|
||||
<h2 id=runningscripts>Running Scripts</h2>
|
||||
<aside>Everything in Python is an object.</aside>
|
||||
<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 class=pp>
|
||||
<pre class=nd><code class=pp>
|
||||
if __name__ == '__main__':
|
||||
print(approximate_size(1000000000000, False))
|
||||
print(approximate_size(1000000000000))</code></pre>
|
||||
@@ -259,12 +330,12 @@ if __name__ == '__main__':
|
||||
<p><span class=u>☞</span>Like <abbr>C</abbr>, Python uses <code>==</code> for comparison and <code>=</code> for assignment. Unlike <abbr>C</abbr>, 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>
|
||||
<pre class='nd screen'>
|
||||
<samp class=p>>>> </samp><kbd class=pp>import humansize</kbd>
|
||||
<samp class=p>>>> </samp><kbd class=pp>humansize.__name__</kbd>
|
||||
<samp class=pp>'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 class=screen>
|
||||
<pre class='nd screen'>
|
||||
<samp class=p>c:\home\diveintopython3> </samp><kbd>c:\python30\python.exe humansize.py</kbd>
|
||||
<samp>1.0 TB
|
||||
931.3 GiB</samp></pre>
|
||||
|
||||
Reference in New Issue
Block a user