Changeset 267

Show
Ignore:
Timestamp:
Sun Dec 18 11:21:48 2005
Author:
osmond
Message:

初步整理了 Chapter 6. 异常和文件处理

Files:

Legend:

Unmodified
Added
Removed
Modified
  • zh-translations/branches/diveintopython-zh-5.4/zh-cn/xml/fileinfo.xml

    r259 r267  
    811 811 </section>  
    812 812 </chapter>  
      813 <!-- =================================================================================================== -->  
    813 814 <chapter id="filehandling">  
    814 815 <?dbhtml filename="file_handling/index.html"?>  
    815   <title>Exceptions and File Handling</title>  
      816 <title>异常和文件处理</title>  
    815 816 <titleabbrev id="filehandling.numberonly">Chapter 6</titleabbrev>  
    816 817 <abstract>  
    817 818 <title/>  
    818   <para>In this chapter, you will dive into exceptions, file objects, &for; loops, and the &os; and &sys; 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.</para>  
      819 <para>在本章中, 将研究异常, 文件对象, &for; 循环, &os; 和 &sys; 模块等内容。 如果你已经在其它编程语言中使用过异常, 你可以简单看看第一部分来了解 &python; 的语法。  Be sure to tune in again for file handling.</para>  
    818 819 </abstract>  
    819 820 <section id="fileinfo.exception">  
    820 821 <?dbhtml filename="file_handling/handling_exceptions.html"?>  
    821   <title>Handling Exceptions</title>  
      822 <title>异常处理</title>  
    821 822 <abstract>  
    822 823 <title/>  
    823   <para>Like many other programming languages, &python; has exception handling via &tryexcept; blocks.</para>  
      824 <para>与许多面向对象语言一样,&python; 具有异常处理,通过使用 &tryexcept;  块来实现。</para>  
    823 824 </abstract>  
    824 825 <note id="compare.exceptions.java" role="compare" vendor="java">  
    825   <title>&python; &vs; &java; exception handling</title>  
    826   <para>&python; uses &tryexcept; to handle exceptions and <literal>raise</literal> to generate them.  &java; and &cpp; use <literal>try...catch</literal> to handle exceptions, and <literal>throw</literal> to generate them.</para>  
      826 <title>&python; &vs; &java; 的异常处理</title>  
      827 <para>&python; 使用 &tryexcept; 来处理异常,使用 <literal>raise</literal> 来引发异常。  &java; 和 &cpp; 使用 <literal>try...catch</literal> 来处理异常,使用 <literal>throw</literal> 来引发异常。</para>  
    827 828 </note>  
    828   <para>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.</para>  
      829 <para>异常在 &python; 中无处不在;实际上在标准 &python; 库中的每个模块都使用了它们,并且 &python; 自已会在许多不同的情况下引发它们。在整本书中你已经再三看到它们了。</para>  
    828 829 <itemizedlist>  
    829   <listitem><para><link linkend="odbchelper.dict.define">Accessing a non-existent dictionary key</link> will raise a <errorcode>KeyError</errorcode> exception.</para></listitem>  
    830   <listitem><para><link linkend="odbchelper.list.search">Searching a list for a non-existent value</link> will raise a <errorcode>ValueError</errorcode> exception.</para></listitem>  
    831   <listitem><para><link linkend="odbchelper.tuplemethods">Calling a non-existent method</link> will raise an <errorcode>AttributeError</errorcode> exception.</para></listitem>  
    832   <listitem><para><link linkend="odbchelper.unboundvariable">Referencing a non-existent variable</link> will raise a <errorcode>NameError</errorcode> exception.</para></listitem>  
    833   <listitem><para><link linkend="odbchelper.stringformatting.coerce">Mixing datatypes without coercion</link> will raise a <errorcode>TypeError</errorcode> exception.</para></listitem>  
      830 <listitem><para><link linkend="odbchelper.dict.define">使用不存在的字典关键字</link>  将引发 <errorcode>KeyError</errorcode> 异常。</para></listitem>  
      831 <listitem><para><link linkend="odbchelper.list.search">搜索列表中不存在的值</link> 将引发 <errorcode>ValueError</errorcode> 异常。</para></listitem>  
      832 <listitem><para><link linkend="odbchelper.tuplemethods">调用不存在的方法</link> 将引发 <errorcode>AttributeError</errorcode> 异常。</para></listitem>  
      833 <listitem><para><link linkend="odbchelper.unboundvariable">引用不存在的变量</link> 将引发 <errorcode>NameError</errorcode> 异常。</para></listitem>  
      834 <listitem><para><link linkend="odbchelper.stringformatting.coerce">未强制转换就混和数据类型</link> 将引发 <errorcode>TypeError</errorcode> 异常。</para></listitem>  
    834 835 </itemizedlist>  
    835   <para>In each of these cases, you were simply playing around in the &python; &ide;: an error occurred, the exception was printed (depending on your &ide;, perhaps in an intentionally jarring shade of red), and that was that.  This is called an <emphasis>unhandled</emphasis> 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 &ide;, 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.</para>  
    836   <para>An exception doesn't need result in a complete program crash, though.  Exceptions, when raised, can be <emphasis>handled</emphasis>.  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 &tryexcept; block.</para>  
      836 <para>在这些情况下,我们都在简单使用 &python; &ide;:一个错误发生了,异常被打印出来 (根据你的 &ide;,有意地以一种刺眼的红色形式表示),并且就这些。这叫做 <emphasis>未处理</emphasis> 异常;当异常被引发时,没有代码来显式地关注它和处理它,所以异常被传给置在 &python; 中的缺省的处理,它会输出一些调试信息并且终止运行。在 &ide; 中,这不是什么大事,但是如果发生在你真正的 &python; 程序运行的时候,整个程序将会终止。</para>  
      837 <para>然而,一个异常不一定会引起程序的完全崩溃。当异常引发时,可以被  <emphasis>处理</emphasis> 掉。有时候一个异常实际是因为代码中的 bug (比如使用一个不存在的变量),但是许多时候,一个异常是可以预计的。如果你打开一个文件,它可能不存在。如果你连接一个数据库,它可能不可连接或没有访问所需的正确的安全证书。如果知道一行代码可能会引发异常,你应该使用一个 &tryexcept; 块来处理异常。</para>  
    837 838 <example>  
    838   <title>Opening a Non-Existent File</title>  
      839 <title>打开一个不存在的文件</title>  
    838 839 <screen>&prompt;<userinput>fsock = open("/notthere", "r")</userinput>      <co id="fileinfo.exceptions.1.1"/>  
    839 840 <computeroutput role='traceback'>&traceback;  
     
    854 855 <calloutlist>  
    855 856 <callout arearefs="fileinfo.exceptions.1.1">  
    856   <para>Using the built-in &open; function, you can try to open a file for reading (more on &open; in the next section).  But the file doesn't exist, so this raises the &ioerror; exception.  Since you haven't provided any explicit check for an &ioerror; exception, &python; just prints out some debugging information about what happened and then gives up.</para>  
      857 <para>使用内置 &open; 函数,我们可以试着打开一个文件来读取(在下一节有关于 &open; 的更多内容)。但是那个文件不存在,所以这样就引发 &ioerror; 异常。因为我们没有提供任何显式的对 &ioerror; 异常的检查,&python; 仅仅打印出某个关于发生了什么的调试信息,然后终止。</para>  
    856 857 </callout>  
    857 858 <callout arearefs="fileinfo.exceptions.1.2">  
    858   <para>You're trying to open the same non-existent file, but this time you're doing it within a &tryexcept; block.</para>  
      859 <para>我们试图打开同样不存在的文件,但是这次我们在一个 &tryexcept; 内来执行它。</para>  
    858 859 </callout>  
    859 860 <callout arearefs="fileinfo.exceptions.1.3">  
    860   <para>When the &open; method raises an &ioerror; exception, you're ready for it.  The <literal>except IOError:</literal> line catches the exception and executes your own block of code, which in this case just prints a more pleasant error message.</para>  
      861 <para>当 &open; 方法引发 &ioerror; 异常时,我们已经准备好处理它了。 <literal>except IOError:</literal>  行捕捉异常接着执行我们自已的代码块,这个代码块在本例中只是打印出更令人愉快的错误信息。</para>  
    860 861 </callout>  
    861 862 <callout arearefs="fileinfo.exceptions.1.4">  
    862   <para>Once an exception has been handled, processing continues normally on the first line after the &tryexcept; block.  Note that this line will always print, whether or not an exception occurs.  If you really did have a file called <filename>notthere</filename> in your root directory, the call to &open; would succeed, the <literal>except</literal> clause would be ignored, and this line would still be executed.</para>  
      863 <para>一旦异常被处理了,处理通常在 &tryexcept;  块之后的第一行继续进行。注意这一行将总是打印出来,无论异常是否发生。如果在你的根目录下确实有一个叫 <filename>notthere</filename> 的文件,对 &open; 的调用将成功,<literal>except</literal> 子句将忽略,并且最后一行仍将执行。</para>  
    862 863 </callout>  
    863 864 </calloutlist>  
    864 865 </example>  
    865   <para>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.</para>  
      866 <para>异常可能看上去不友好(毕竟,如果你不捕捉异常,整个程序将崩溃),但是考虑一下别的方法。你宁愿找回对于不存在文件的不可用的文件对象吗?不管怎么样你都得检查它的有效性,而且如果你忘记了,你的程序将会在下面某个地方给出奇怪的错误,这样你将不得不追溯到源程序。我确信你做过这种事;这可并不有趣。使用异常,一发生错误,你就可以在问题的源头通过标准的方法来处理它们。</para>  
    865 866 <section>  
    866   <title>Using Exceptions For Other Purposes</title>  
    867   <para>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 &importerror; 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).</para>  
    868   <para>You can also define your own exceptions by creating a class that inherits from the built-in <classname>Exception</classname> class, and then raise your exceptions with the <function>raise</function> command.  See the further reading section if you're interested in doing this.</para>  
      867 <title>为其他用途使用异常</title>  
      868 <para>除了处理实际的错误条件之外,对于异常还有许多其它的用处。在标准 &python; 库中一个普通的用法就是试着导入一个模块,然后检查是否它能使用。导入一个并不存在的模块将引发一个 &importerror;  异常。你可以使用这种方法来定义多级别的功能,依靠在运行时哪个模块是有效的,或支持多种平台(即平台特定代码被分离到不同的模块中)。</para>  
      869 <para>你也能通过创建一个从内置的  <classname>Exception</classname> 类继承的类定义你自己的异常, 然后使用 <function>raise</function> 命令引发你的异常。如果你对此感兴趣,请看进一步阅读的部分。</para>  
    869 870  
    870   <para>The next example demonstrates how to use an exception to support platform-specific functionality.  This code comes from the <filename class="headerfile">getpass</filename> module, a wrapper module for getting a password from the user.  Getting a password is accomplished differently on &unix;, &windows;, and &macos; platforms, but this code encapsulates all of those differences.</para>  
      871 <para>下面的例子演示了如何使用异常支持特定平台功能。  代码来自 <filename class="headerfile">getpass</filename> 模块, 一个从用户获得口令的封装模块。获得口令在 &unix;, &windows; 和 &macos; 平台上的实现是不同的,但是这个代码封装了所有的不同之处。</para>  
    870 871  
    871 872 <example id="crossplatform.example">  
    872   <title>Supporting Platform-Specific Functionality</title>  
      873 <title>支持特定平台功能</title>  
    872 873 <programlisting>  
    873 874   # Bind the name getpass to the appropriate function  
     
    897 898 <calloutlist>  
    898 899 <callout arearefs="fileinfo.exceptions.2.1">  
    899   <para>&termios; is a &unix;-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 &importerror;, which you catch.</para>  
      900 <para>&termios; 是一个 &unix; 特定模块,它提供了对于输入终端的底层控制。如果这个模块无效 (因为它不在你的系统上,或你的系统不支持它),则导入失败,&python; 引发我们捕捉的 &importerror; 异常。</para>  
    899 900 </callout>  
    900 901 <callout arearefs="fileinfo.exceptions.2.2">  
    901   <para>OK, you didn't have &termios;, so let's try &msvcrt;, which is a &windows;-specific module that provides an &api; to many useful functions in the Microsoft <application>Visual C++</application> runtime services.  If this import fails, &python; will raise an &importerror;, which you catch.</para>  
      902 <para>OK, 我们没有 &termios;,所以让我们试试  &msvcrt;,它是一个 &windows; 特定模块,可以提供在 Microsoft <application>Visual C++</application> 运行服务中的许多有用的函数的一个&api;。如果导入失败,&python; 会引发我们捕捉的 &importerror; 异常。</para>  
    901 902 </callout>  
    902 903 <callout arearefs="fileinfo.exceptions.2.3">  
    903   <para>If the first two didn't work, you try to import a function from &easydialogs;, which is a &macos;-specific module that provides functions to pop up dialog boxes of various types.  Once again, if this import fails, &python; will raise an &importerror;, which you catch.</para>  
      904 <para>如果前两个不能工作,我们试着从 &easydialogs; 导入一个函数,它是一个 &macos; 特定模块,提供了各种各样类型的弹出对话框。再一次,如果导入失败,&python; 会引发一个我们捕捉的 &importerror; 异常。</para>  
    903 904 </callout>  
    904 905 <callout arearefs="fileinfo.exceptions.2.4">  
    905   <para>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 &getpass; module).  Notice what you're doing here: assigning the function <function>default_getpass</function> to the variable <varname>getpass</varname>.  If you read the official &getpass; documentation, it tells you that the &getpass; module defines a <function>getpass</function> function.  It does this by binding <varname>getpass</varname> to the correct function for your platform.  Then when you call the <function>getpass</function> 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 <function>getpass</function>, and it will always do the right thing.</para>  
      906 <para>这些平台特定的模块没有一个有效(有可能,因为 &python; 已经移植到了许多不同的平台上了),所以我们需要回头使用一个缺省口令输入函数(这个函数定义在 &getpass; 模块中的别的地方)。注意,我们在这里做的:我们将函数 <function>default_getpass</function> 赋给变量 <varname>getpass</varname>。如果你读了官方 &getpass; 文档,它会告诉你 &getpass; 模块定义了一个 <function>getpass</function> 函数。它是这样做的:通过绑定 <varname>getpass</varname> 到正确的函数来适应你的平台。然后当你调用 <function>getpass</function> 函数时,你实际上调用了平台特定的函数,是这段代码已经为你设置好的。你不需要知道或关心你的代码正运行在何种平台上;只要调用 <function>getpass</function>,则它总能正确处理。</para>  
    905 906 </callout>  
    906 907 <callout arearefs="fileinfo.exceptions.2.5">  
    907   <para>A &tryexcept; block can have an &else; clause, like an &if; statement.  If no exception is raised during the <literal>try</literal> block, the &else; clause is executed afterwards.  In this case, that means that the <literal>from EasyDialogs import AskPassword</literal> import worked, so you should bind <varname>getpass</varname> to the <function>AskPassword</function> function.  Each of the other &tryexcept; blocks has similar &else; clauses to bind <varname>getpass</varname> to the appropriate function when you find an &import; that works.</para>  
      908 <para>一个 &tryexcept; 块可以有一条 &else; 子句,就象 &if; 语句。如果在 <literal>try</literal> 块中没有异常引发,然后 else 子句被执行。在本例中,那就意味着如果 <literal>from EasyDialogs import AskPassword</literal> 导入可工作,所以我们应该绑定 <varname>getpass</varname> 到 <function>AskPassword</function> 函数。其它每个 &tryexcept; 块有着相似的 &else; 子句,当我们找到一个 &import; 可用时,来绑定  <varname>getpass</varname> 到适合的函数。</para>  
    907 908 </callout>  
    908 909 </calloutlist>  
    909 910 </example>  
    910 911 <itemizedlist role="furtherreading">  
    911   <title>Further Reading on Exception Handling</title>  
    912   <listitem><para>&pythontutorial; discusses <ulink url="&url_pythontutorial;node10.html#SECTION0010400000000000000000">defining and raising your own exceptions, and handling multiple exceptions at once</ulink>.</para></listitem>  
    913   <listitem><para>&pythonlibraryreference; summarizes <ulink url="&url_pythonlibraryreference;module-exceptions.html">all the built-in exceptions</ulink>.</para></listitem>  
    914   <listitem><para>&pythonlibraryreference; documents the <ulink url="&url_pythonlibs;module-getpass.html">getpass</ulink> module.</para></listitem>  
    915   <listitem><para>&pythonlibraryreference; documents the <ulink url="&url_pythonlibraryreference;module-traceback.html"><filename class="headerfile">traceback</filename> module</ulink>, which provides low-level access to exception attributes after an exception is raised.</para></listitem>  
    916   <listitem><para>&pythonlanguagereference; discusses the inner workings of the <ulink url="&url_pythonlanguagereference;try.html">&tryexcept; block</ulink>.</para></listitem>  
      912 <title>进一步阅读</title>  
      913 <listitem><para>&pythontutorial; 讨论了异常,包括 <ulink url="&url_pythontutorial;node10.html#SECTION0010400000000000000000">定义和引发你自已的异常, 以及一次处理多个异常</ulink>。</para></listitem>  
      914 <listitem><para>&pythonlibraryreference; 总结了 <ulink url="&url_pythonlibraryreference;module-exceptions.html">所有内置异常</ulink>。</para></listitem>  
      915 <listitem><para>&pythonlibraryreference; 提供了 <ulink url="&url_pythonlibs;module-getpass.html">getpass</ulink> 模块的文档。</para></listitem>  
      916 <listitem><para>&pythonlibraryreference; 提供了 <ulink url="&url_pythonlibraryreference;module-traceback.html"><filename class="headerfile">traceback</filename> 模块</ulink>的文档, 这个模块在异常引发之后,提供了底层的对异常属性的处理。</para></listitem>  
      917 <listitem><para>&pythonlanguagereference; 讨论了 <ulink url="&url_pythonlanguagereference;try.html">&tryexcept; 块</ulink>的内部工作方式。</para></listitem>  
    917 918 </itemizedlist>  
    918 919 </section>  
     
    925 926 <section id="fileinfo.files">  
    926 927 <?dbhtml filename="file_handling/file_objects.html"?>  
    927   <title>Working with File Objects</title>  
      928 <title>与 文件对象 共事</title>  
    927 928 <abstract>  
    928 929 <title/>  
    929   <para>&python; has a built-in function, &open;, for opening a file on disk.  &open; returns a file object, which has methods and attributes for getting information about and manipulating the opened file.</para>  
      930 <para>&python; 有一个内置函数,&open;,用来打开在磁盘上的文件。&open; 返回一个文件对象,它拥有一些方法和属性,可以得到打开文件的信息,和对打开文件进行操作。</para>  
    929 930 </abstract>  
    930 931 <example>  
    931   <title>Opening a File</title>  
      932 <title>打开文件</title>  
    931 932 <screen>&prompt;<userinput>f = open("/music/_singles/kairo.mp3", "rb")</userinput> <co id="fileinfo.files.1.1"/>  
    932 933 &prompt;<userinput>f</userinput>                                           <co id="fileinfo.files.1.2"/>  
     
    941 942 <calloutlist>  
    942 943 <callout arearefs="fileinfo.files.1.1">  
    943   <para>The &open; method can take up to three parameters: a filename, a mode, and a buffering parameter.  Only the first one, the filename, is required; the other two are <link linkend="apihelper.optional">optional</link>.  If not specified, the file is opened for reading in text mode.  Here you are opening the file for reading in binary mode.  (<literal>print open.__doc__</literal> displays a great explanation of all the possible modes.)</para>  
      944 <para>&open; 方法可以接收三个参数:文件名,模式,和缓冲区参数。只有第一个参数,文件名,是必须的;其它两个是 <link linkend="apihelper.optional">可选的</link>。如果没有指定,文件以文本方式打开。这里我们以二进制方式打开文件进行读取。(<literal>print open.__doc__</literal> 会给出所有可能模式的很好的解释。)</para>  
    943 944 </callout>  
    944 945 <callout arearefs="fileinfo.files.1.2">  
    945   <para>The &open; function returns an object (by now, <link linkend="odbchelper.objects">this should not surprise you</link>).  A file object has several useful attributes.</para>  
      946 <para>&open;  函数返回一个对象(到现在为止,<link linkend="odbchelper.objects">这一点应该不会使你感到吃惊</link>)。一个文件对象有几个有用的属性。</para>  
    945 946 </callout>  
    946 947 <callout arearefs="fileinfo.files.1.3">  
    947   <para>The <varname>mode</varname> attribute of a file object tells you in which mode the file was opened.</para>  
      948 <para>文件对象的 <varname>mode</varname> 属性告诉你文件以何种模式被打开。</para>  
    947 948 </callout>  
    948 949 <callout arearefs="fileinfo.files.1.4">  
    949   <para>The <varname>name</varname> attribute of a file object tells you the name of the file that the file object has open.</para>  
      950 <para>文件对象的 <varname>name</varname> 属性告诉你文件对象所打开的文件名。</para>  
    949 950 </callout>  
    950 951 </calloutlist>  
    951 952 </example>  
    952 953 <section>  
    953   <title>Reading Files</title>  
    954   <para>After you open a file, the first thing you'll want to do is read from it, as shown in the next example.</para>  
      954 <title>读取文件</title>  
      955 <para>你打开文件之后, 你要做的第一件事是从中读取, 正如下一个例子所显示的。</para>  
    955 956 <example>  
    956   <title>Reading a File</title>  
      957 <title>读取文件</title>  
    956 957 <screen>  
    957 958 &prompt;<userinput>f</userinput>  
     
    975 976 <calloutlist>  
    976 977 <callout arearefs="fileinfo.files.2.1">  
    977   <para>A file object maintains state about the file it has open.  The &tell; method of a file object tells you your current position in the open file.  Since you haven't done anything with this file yet, the current position is &zero;, which is the beginning of the file.</para>  
      978 <para>一个文件对象维护它所打开文件的状态。文件对象的 &tell; 方法告诉你在打开文件中的当前位置。因为我们还没有对这个文件做任何事,当前位置为 &zero;,它是文件的开始处。</para>  
    977 978 </callout>  
    978 979 <callout arearefs="fileinfo.files.2.2">  
    979   <para>The &seek; method of a file object moves to another position in the open file.  The second parameter specifies what the first one means; &zero; means move to an absolute position (counting from the start of the file), &one; means move to a relative position (counting from the current position), and <literal>2</literal> means move to a position relative to the end of the file.  Since the &mp3; tags you're looking for are stored at the end of the file, you use <literal>2</literal> and tell the file object to move to a position <literal>128</literal> bytes from the end of the file.</para>  
      980 <para>文件对象的 &seek; 方法在打开文件中移动到另一个位置。第二个参数指出第一个参数是什么意思:&zero; 表示移动到一个绝对位置(从文件开始算起),&one; 表示移到一个相对位置(从当前位置算起),还有 <literal>2</literal>  表示对于文件尾的一个相对位置。因为我们搜索的 &mp3; 标记保存在文件的末尾,我们使用 <literal>2</literal>  并且告诉文件对象从文件尾移动到 <literal>128</literal> 字节的位置。</para>  
    979 980 </callout>  
    980 981 <callout arearefs="fileinfo.files.2.3">  
    981   <para>The &tell; method confirms that the current file position has moved.</para>  
      982 <para>&tell;方法确认了已经移到当前文件位置。</para>  
    981 982 </callout>  
    982 983 <callout arearefs="fileinfo.files.2.4">  
    983   <para>The &read; method reads a specified number of bytes from the open file and returns a string with the data that was read.  The optional parameter specifies the maximum number of bytes to read.  If no parameter is specified, &read; will read until the end of the file.  (You could have simply said <literal>read()</literal> here, since you know exactly where you are in the file and you are, in fact, reading the last 128 bytes.)  The read data is assigned to the <varname>tagData</varname> variable, and the current position is updated based on how many bytes were read.</para>  
      984 <para> &read;  方法从打开文件中读取指定个数的字节,并且返回含有读取数据的字符串。可选参数指定了读取的最大字节数。如果没有指定参数,&read; 将读到文件末尾。(我们本可以在这里简单地说一下  <literal>read()</literal> ,因为我们确切地知道在文件的何处,事实上,我们读的是最后128个字节。)读出的数据赋给变量 <varname>tagData</varname>,并且当前的位置根据所读的字节数作了修改。</para>  
    983 984 </callout>  
    984 985 <callout arearefs="fileinfo.files.2.5">  
    985   <para>The &tell; method confirms that the current position has moved.  If you do the math, you'll see that after reading 128 bytes, the position has been incremented by 128.</para>  
      986 <para>&tell; 方法确认了当前位置已经移动了。如果做一下算术,你会看到在读了128个字节之后,位置数已经增加了128。</para>  
    985 986 </callout>  
    986 987 </calloutlist>  
     
    993 994 </section>  
    994 995 <section>  
    995   <title>Closing Files</title>  
    996   <para>Open files consume system resources, and depending on the file mode, other programs may not be able to access them.  It's important to close files as soon as you're finished with them.</para>  
      996 <title>关闭文件</title>  
      997 <para>打开文件消耗系统资源, 并且依赖于文件模式, 其它程序或许不能访问它们。这就是一旦操作完毕就该关闭文件的重要所在。</para>  
    997 998 <example>  
    998   <title>Closing a File</title>  
      999 <title>关闭文件</title>  
    998 999 <screen>  
    999 1000 &prompt;<userinput>f</userinput>  
     
    1019 1020 <calloutlist>  
    1020 1021 <callout arearefs="fileinfo.files.3.1">  
    1021   <para>The <varname>closed</varname> attribute of a file object indicates whether the object has a file open or not.  In this case, the file is still open (<varname>closed</varname> is &false;).</para>  
      1022 <para>文件对象的 <varname>closed</varname> 属性表示对象是否打开或关闭了文件。在本例中,文件仍然打开着(<varname>closed</varname> 是 &false;)。打开文件要消耗系统资源,并且根据文件模式,其它程序可能不能使用它们。一旦你处理完它们,把文件关闭这一点很重要。</para>  
    1021 1022 </callout>  
    1022 1023 <callout arearefs="fileinfo.files.3.2">  
    1023   <para>To close a file, call the &close; method of the file object.  This frees the lock (if any) that you were holding on the file, flushes buffered writes (if any) that the system hadn't gotten around to actually writing yet, and releases the system resources.</para>  
      1024 <para>为了关闭文件,调用文件对象的 &close; 方法。这样就释放掉你加在文件上的锁(如果有的话),刷新被缓冲的系统确实还未写入的输出(如果有的话),并且释放系统资源。</para>  
    1023 1024 </callout>  
    1024 1025 <callout arearefs="fileinfo.files.3.3">  
    1025   <para>The <varname>closed</varname> attribute confirms that the file is closed.</para>  
      1026 <para><varname>closed</varname> 属性证实了文件被关闭了。</para>  
    1025 1026 </callout>  
    1026 1027 <callout arearefs="fileinfo.files.3.4">  
    1027   <para>Just because a file is closed doesn't mean that the file object ceases to exist.  The variable <varname>f</varname> will continue to exist until it <link linkend="fileinfo.scope">goes out of scope</link> or gets manually deleted.  However, none of the methods that manipulate an open file will work once the file has been closed; they all raise an exception.</para>  
      1028 <para>只是因为文件被关闭,并不意味着文件对象停止存在。变量 <varname>f</varname> 将继续存在,直到它 <link linkend="fileinfo.scope">超出作用域</link> 或被手工删除。然而,一旦文件被关闭,可操作打开文件的方法没有一个能使用;它们都会引发异常。</para>  
    1027 1028 </callout>  
    1028 1029 <callout arearefs="fileinfo.files.3.5">  
    1029   <para>Calling &close; on a file object whose file is already closed does <emphasis>not</emphasis> raise an exception; it fails silently.</para>  
      1030 <para>对一个文件已经关闭的文件对象调用 &close; <emphasis>不会</emphasis> 引发异常,它静静地失败。</para>  
    1029 1030 </callout>  
    1030 1031 </calloutlist>  
     
    1037 1038 </section>  
    1038 1039 <section>  
    1039   <title>Handling <acronym>I/O</acronym> Errors</title>  
    1040   <para>Now you've seen enough to understand the file handling code in the &fileinfo_filename; sample code from teh previous chapter.  This example shows how to safely open and read from a file and gracefully handle errors.</para>  
      1040 <title>处理 <acronym>I/O</acronym> 错误</title>  
      1041 <para>现在你已经足能理解前一章的例子程序 &fileinfo_filename; 的文件处理代码了。 下面这个例子展示了如何安全的打开文件和读取文件以及优美地处理错误。</para>  
    1041 1042 <example id="fileinfo.files.incode">  
    1042   <title>File Objects in &mp3fileinfo_classname;</title>  
      1043 <title>&mp3fileinfo_classname; 中的文件对象</title>  
    1042 1043 <programlisting>  
    1043 1044 &fileinfo_mp3parsetryexcepttry; <co id="fileinfo.files.4.1"/>  
     
    1056 1057 <calloutlist>  
    1057 1058 <callout arearefs="fileinfo.files.4.1">  
    1058   <para>Because opening and reading files is risky and may raise an exception, all of this code is wrapped in a &tryexcept; block.  (Hey, isn't <link linkend="odbchelper.indenting">standardized indentation</link> great?  This is where you start to appreciate it.)</para>  
      1059 <para>因为打开和读取文件有风险,并且可能引发异常,所有这些代码都用一个 &tryexcept; 块封装。(嘿,<link linkend="odbchelper.indenting">标准化的缩近</link> 不好吗?这就是你开始欣赏它的地方。)</para>  
    1058 1059 </callout>  
    1059 1060 <callout arearefs="fileinfo.files.4.2">  
    1060   <para>The &open; function may raise an &ioerror;.  (Maybe the file doesn't exist.)</para>  
      1061 <para>&open; 函数可能引发 &ioerror; 异常。(可能是文件不存在。)</para>  
    1060 1061 </callout>  
    1061 1062 <callout arearefs="fileinfo.files.4.3">  
    1062   <para>The &seek; method may raise an &ioerror;.  (Maybe the file is smaller than 128 bytes.)</para>  
      1063 <para>&seek; 方法可能引发 &ioerror; 异常。(可能是文件长度小于128字节。)</para>  
    1062 1063 </callout>  
    1063 1064 <callout arearefs="fileinfo.files.4.4">  
    1064   <para>The &read; method may raise an &ioerror;.  (Maybe the disk has a bad sector, or it's on a network drive and the network just went down.)</para>  
      1065 <para>&read; 方法可能引发 &ioerror; 异常。(可能磁盘有坏扇区,或它在一个网络驱劝器上,而网络刚好断了。)</para>  
    1064 1065 </callout>  
    1065 1066 <callout arearefs="fileinfo.files.4.5">  
    1066   <para>This is new: a &tryfinally; block.  Once the file has been opened successfully by the &open; function, you want to make absolutely sure that you close it, even if an exception is raised by the &seek; or &read; methods.  That's what a &tryfinally; block is for: code in the <literal>finally</literal> block will <emphasis>always</emphasis> be executed, even if something in the <literal>try</literal> block raises an exception.  Think of it as code that gets executed on the way out, regardless of what happened before.</para>  
      1067 <para>这是新的:一个 &tryfinally; 块。一旦文件通过 &open; 函数被成功地打开,我们应该绝对保证把它关闭,甚至由于 &seek; 或 &read; 方法引发了一个异常。&tryfinally; 块可以用来:在 <literal>finally</literal> 块中的代码将 <emphasis>总是</emphasis> 被执行,甚至某些东西在 <literal>try</literal> 块中引发一个异常也会执行。可以这样考虑,不管在路上发生什么,代码都会被 “即将灭亡” 地执行。</para>  
    1066 1067 </callout>  
    1067 1068 <callout arearefs="fileinfo.files.4.6">  
    1068   <para>At last, you handle your &ioerror; exception.  This could be the &ioerror; exception raised by the call to &open;, &seek;, or &read;.  Here, you really don't care, because all you're going to do is ignore it silently and continue.  (Remember, &pass; is a &python; statement that <link linkend="fileinfo.class.simplest">does nothing</link>.)  That's perfectly legal; <quote>handling</quote> an exception can mean explicitly doing nothing.  It still counts as handled, and processing will continue normally on the next line of code after the &tryexcept; block.</para>  
      1069 <para>最后,处理我们的 &ioerror; 异常。它可能是由调用 &open;, &seek;,或 &read; 引发的 &ioerror; 异常。这里,我们其实不用关心,因为将要做的事就是静静地忽略它然后继续。(记住,&pass; 是一条不做任何事的 &python; 语句。) 这样完全合法,<quote>处理</quote> 一个异常可以明确表示不做任何事。它仍然被认为处理过了,并且处理将正常继续,从 &tryexcept; 块的下一行代码。</para>  
    1068 1069 </callout>  
    1069 1070 </calloutlist>  
     
    1077 1078 </section>  
    1078 1079 <section>  
    1079   <title>Writing to Files</title>  
    1080   <para>As you would expect, you can also write to files in much the same way that you read from them.  There are two basic file modes:</para>  
      1080 <title>写文件</title>  
      1081 <para>正如你所期待的, 你也能用与读取文件同样的方式写文件。  有两种基本的文件模式:</para>  
    1081 1082 <itemizedlist>  
    1082   <listitem><para>"Append" mode will add data to the end of the file.</para></listitem>  
    1083   <listitem><para>"write" mode will overwrite the file.</para></listitem>  
      1083 <listitem><para>"Append" 模式将数据追加到文件尾。</para></listitem>  
      1084 <listitem><para>"write" 模式将覆盖文件的原有内容。</para></listitem>  
    1084 1085 </itemizedlist>  
    1085   <para>Either mode will create the file automatically if it doesn't already exist, so there's never a need for any sort of fiddly "if the log file doesn't exist yet, create a new empty file just so you can open it for the first time" logic.  Just open it and start writing.</para>  
      1086 <para>如果文件还不存在任意一种模式都将自动创建文件, 因此从来不需要任何复杂的 "if the log file doesn't exist yet, create a new empty file just so you can open it for the first time" 逻辑。 打开文件并开始写就可以了。</para>  
    1085 1086 <example id="fileinfo.files.writeandappend">  
    1086   <title>Writing to Files</title>  
      1087 <title>写文件</title>  
    1086 1087 <screen>  
    1087 1088 &prompt;<userinput>logfile = open('test.log', 'w')</userinput> <co id="fileinfo.files.5.1"/>  
     
    1100 1101 <calloutlist>  
    1101 1102 <callout arearefs="fileinfo.files.5.1">  
    1102   <para>You start boldly by creating either the new file <filename>test.log</filename> or overwrites the existing file, and opening the file for writing.  (The second parameter <literal>"w"</literal> means open the file for writing.)  Yes, that's all as dangerous as it sounds.  I hope you didn't care about the previous contents of that file, because it's gone now.</para>  
      1103 <para>[todo]You start boldly by creating either the new file <filename>test.log</filename> or overwrites the existing file, and opening the file for writing.  (The second parameter <literal>"w"</literal> means open the file for writing.)  Yes, that's all as dangerous as it sounds.  I hope you didn't care about the previous contents of that file, because it's gone now.</para>  
    1102 1103 </callout>  
    1103 1104 <callout arearefs="fileinfo.files.5.2">  
     
    1117 1118 </example>  
    1118 1119 <itemizedlist role="furtherreading">  
    1119   <title>Further Reading on File Handling</title>  
    1120   <listitem><para>&pythontutorial; discusses reading and writing files, including how to <ulink url="&url_pythontutorial;node9.html#SECTION009210000000000000000">read a file one line at a time into a list</ulink>.</para></listitem>  
    1121   <listitem><para>&effbot; discusses efficiency and performance of <ulink url="&url_effbot;readline-performance.htm">various ways of reading a file</ulink>.</para></listitem>  
    1122   <listitem><para>&pythonknowledgebase; answers <ulink url="&url_pythonknowledgebase;index.phtml/fid/552">common questions about files</ulink>.</para></listitem>  
    1123   <listitem><para>&pythonlibraryreference; summarizes <ulink url="&url_pythonlibraryreference;bltin-file-objects.html">all the file object methods</ulink>.</para></listitem>  
      1120 <title>进一步阅读</title>  
      1121 <listitem><para>&pythontutorial; 讨论了文件的读取和写入,包括如何 <ulink url="&url_pythontutorial;node9.html#SECTION009210000000000000000">将一个文件一次一行地读到 list 中</ulink>。</para></listitem>  
      1122 <listitem><para>&effbot; 讨论了 efficiency and performance of <ulink url="&url_effbot;readline-performance.htm">各种各样读取文件方法</ulink>的效率和性能。</para></listitem>  
      1123 <listitem><para>&pythonknowledgebase; 回答了 <ulink url="&url_pythonknowledgebase;index.phtml/fid/552">关于文件的常见问题</ulink>。</para></listitem>  
      1124 <listitem><para>&pythonlibraryreference; 总结了 <ulink url="&url_pythonlibraryreference;bltin-file-objects.html">所有文件对象模块</ulink>。</para></listitem>  
    1124 1125 </itemizedlist>  
    1125 1126 </section>  
     
    1127 1128 <section id="fileinfo.for">  
    1128 1129 <?dbhtml filename="file_handling/for_loops.html"?>  
    1129   <title>Iterating with &for; Loops</title>  
      1130 <title>&for; 循环</title>  
    1129 1130 <abstract>  
    1130 1131 <title/>  
    1131   <para>Like most other languages, &python; has &for; loops.  The only reason you haven't seen them until now is that &python; is good at so many other things that you don't need them as often.</para>  
      1132 <para>与其它大多数语言一样,&python; 也拥有 &for; 循环。你到现在还未曾看到它们的唯一的原因就是,&python; 在其它太多的方面表现出色,通常你不需要它们。</para>  
    1131 1132 </abstract>  
    1132   <para>Most other languages don't have a powerful list datatype like &python;, so you end up doing a lot of manual work, specifying a start, end, and step to define a range of integers or characters or other iteratable entities.  But in &python;, a &for; loop simply iterates over a list, the same way <link linkend="odbchelper.map">list comprehensions</link> work.</para>  
      1133 <para>其它大多数语言没有象 &python; 一样的强大的 list 数据类型,所以你需要亲自做很多事情,指定开始,结束和步长,来定义一定范围的整数或字符或其它可重复的实体。但是在 &python; 中,&for;  循环简单地在一个列表上循环,与  <link linkend="odbchelper.map">list 理解</link> 的工作方式相同。</para>  
    1132 1133 <example>  
    1133   <title>Introducing the &for; Loop</title>  
      1134 <title>&for; 循环介绍</title>  
    1133 1134 <screen>&prompt;<userinput>li = ['a', 'b', 'e']</userinput>  
    1134 1135 &prompt;<userinput>for s in li:</userinput>         <co id="fileinfo.for.1.1"/>  
     
    1147 1148 <calloutlist>  
    1148 1149 <callout arearefs="fileinfo.for.1.1">  
    1149   <para>The syntax for a &for; loop is similar to <link linkend="odbchelper.map">list comprehensions</link>.  <varname>li</varname> is a list, and <varname>s</varname> will take the value of each element in turn, starting from the first element.</para>  
      1150 <para>&for; 循环的语法同 <link linkend="odbchelper.map">list 理解</link> 相似。<varname>li</varname> 是一个 list,而 <varname>s</varname> 将从第一个元素开始依次接收每个元素的值。</para>  
    1149 1150 </callout>  
    1150 1151 <callout arearefs="fileinfo.for.1.2">  
    1151   <para>Like an &if; statement or any other <link linkend="odbchelper.indenting">indented block</link>, a &for; loop can have any number of lines of code in it.</para>  
      1152 <para>象 &if; 语句或其它任意 <link linkend="odbchelper.indenting">缩进块</link>,&for; 循环可以在它里面有任意条数的代码行。</para>  
    1151 1152 </callout>  
    1152 1153 <callout arearefs="fileinfo.for.1.3">  
    1153   <para>This is the reason you haven't seen the &for; loop yet: you haven't needed it yet.  It's amazing how often you use &for; loops in other languages when all you really want is a &join; or a list comprehension.</para>  
      1154 <para>这就是为什么你以前没看到过 &for; 循环的原因:至今我们都不需要它。太令人吃惊了,当你想要的只是一个 &join; 或是 list 理解时,而用其它语言常常需要使用 &for; 循环。</para>  
    1153 1154 </callout>  
    1154 1155 </calloutlist>  
    1155 1156 </example>  
    1156   <para>Doing a <quote>normal</quote> (by &vb; standards) counter &for; loop is also simple.</para>  
      1157 <para>要做一个 <quote>通常的</quote> (&vb; 标准的) 计数 &for; 循环也非常简单。</para>  
    1156 1157 <example id="fileinfo.for.counter">  
    1157   <title>Simple Counters</title>  
      1158 <title>简单计数</title>  
    1157 1158 <screen>  
    1158 1159 &prompt;<userinput>for i in range(5):</userinput>             <co id="fileinfo.for.3.1"/>  
     
    1179 1180 <calloutlist>  
    1180 1181 <callout arearefs="fileinfo.for.3.1">  
    1181   <para>As you saw in <xref linkend="odbchelper.multiassign.range"/>, &range; produces a list of integers, which you then loop through.  I know it looks a bit odd, but it is occasionally (and I stress <emphasis>occasionally</emphasis>) useful to have a counter loop.</para>  
      1182 <para>正如你在 <xref linkend="odbchelper.multiassign.range"/> 所看到的, &range; 生成一个整数的 list, [todo]which you then loop through.  我知道它看上去有些奇怪, 但是它对计数循环偶尔 (我只是说 <emphasis>偶尔</emphasis>) 会有用 。</para>  
    1181 1182 </callout>  
    1182 1183 <callout arearefs="fileinfo.for.3.2">  
    1183   <para>Don't ever do this.  This is &vb;-style thinking.  Break out of it.  Just iterate through the list, as shown in the previous example.</para>  
      1184 <para>我们从来没这么用过。 这是 &vb;-式的想法。摆脱它吧。 正确遍历 list 的方法是上一个例子所展示的。</para>  
    1183 1184 </callout>  
    1184 1185 </calloutlist>  
    1185 1186 </example>  
    1186   <para>&for; loops are not just for simple counters.  They can iterate through all kinds of things.  Here is an example of using a &for; loop to iterate through a dictionary.</para>  
      1187 <para>&for; 循环不仅仅用于简单计数。  它们可以遍历任何类型的东西。 下面的例子是一个用  &for; 循环遍历 dictionary 的例子。</para>  
    1186 1187 <example id="dictionaryiter.example">  
    1187   <title>Iterating Through a Dictionary</title>  
      1188 <title>遍历 dictionary</title>  
    1187 1188 <screen>  
    1188 1189 &prompt;<userinput>import os</userinput>  
     
    1198 1199 USERNAME=mpilgrim  
    1199 1200  
    1200   [...snip...]</computeroutput>  
      1201 [......]</computeroutput>  
    1200 1201 &prompt;<userinput>print "\n".join(["%s=%s" % (k, v)</userinput>  
    1201 1202 &continuationprompt;<userinput>for k, v in os.environ.items()])</userinput> <co id="fileinfo.for.2.3"/>  
     
    1206 1207 USERNAME=mpilgrim  
    1207 1208  
    1208   [...snip...]</computeroutput></screen>  
      1209 [......]</computeroutput></screen>  
    1208 1209 <calloutlist>  
    1209 1210 <callout arearefs="fileinfo.for.2.1">  
    1210   <para><varname>os.environ</varname> is a dictionary of the environment variables defined on your system.  In &windows;, these are your user and system variables accessible from &dos;.  In &unix;, they are the variables exported in your shell's startup scripts.  In &macos;, there is no concept of environment variables, so this dictionary is empty.</para>  
      1211 <para><varname>os.environ</varname>  是在你的系统上所定义的环境变量的 dictionary。在 &windows; 下,这些变量是可以从 &dos; 访问的用户和系统变量。在 &unix; 下,它们是在你的 shell 启动脚本中所 export(输出)的变量。在 &macos; 中,没有环境变量的概念,所以这个 dictionary 为空。</para>  
    1210 1211 </callout>  
    1211 1212 <callout arearefs="fileinfo.for.2.2">  
    1212   <para><literal>os.environ.items()</literal> returns a list of tuples: <literal>[(<replaceable>key1</replaceable>, <replaceable>value1</replaceable>), (<replaceable>key2</replaceable>, <replaceable>value2</replaceable>), ...]</literal>.  The &for; loop iterates through this list.  The first round, it assigns <literal><replaceable>key1</replaceable></literal> to <varname>k</varname> and <literal><replaceable>value1</replaceable></literal> to <varname>v</varname>, so <varname>k</varname> = <literal>USERPROFILE</literal> and <varname>v</varname> = <literal>C:\Documents and Settings\mpilgrim</literal>.  In the second round, <varname>k</varname> gets the second key, <literal>OS</literal>, and <varname>v</varname> gets the corresponding value, <literal>Windows_NT</literal>.</para>  
      1213 <para><literal>os.environ.items()</literal> 返回一个 tuple 的 list:<literal>[(<replaceable>key1</replaceable>, <replaceable>value1</replaceable>), (<replaceable>key2</replaceable>, <replaceable>value2</replaceable>), ...]</literal>。 &for; 循环对这个 list 进行遍历。第一轮,它将 <literal><replaceable>key1</replaceable></literal> 赋给 <varname>k</varname> ,<literal><replaceable>value1</replaceable></literal> 赋给 <varname>v</varname>,所以  <varname>k</varname> = <literal>USERPROFILE</literal>,<varname>v</varname> = <literal>C:\Documents and Settings\mpilgrim</literal>。第二轮,<varname>k</varname> 得到第二个键字,<literal>OS</literal>,<varname>v</varname> 得到相应的值,<literal>Windows_NT</literal>。</para>  
    1212 1213 </callout>  
    1213 1214 <callout arearefs="fileinfo.for.2.3">  
    1214   <para>With <link linkend="odbchelper.multiassign">multi-variable assignment</link> and <link linkend="odbchelper.map">list comprehensions</link>, you can replace the entire &for; loop with a single statement.  Whether you actually do this in real code is a matter of personal coding style.  I like it because it makes it clear that what I'm doing is mapping a dictionary into a list, then joining the list into a single string.  Other programmers prefer to write this out as a &for; loop.  The output is the same in either case, although this version is slightly faster, because there is only one &print; statement instead of many.</para>  
      1215 <para>使用 <link linkend="odbchelper.multiassign">多变量赋值</link> 和 <link linkend="odbchelper.map">list 理解</link>,你可以使用单行语句来替换整个 &for; 循环。在实际的编码中是否这样做只是个人风格问题;我喜欢它是因为,可以使得将一个 dictionary 映射到一个 list,然后将 list 合并成一个字符串这一过程变得清晰。其它的程序员宁愿将其写成一个 &for; 循环。请注意在两种情况下输出是一样的,然而这一版本稍微快一些,因为它只有一条 &print; 语句而不是许多。</para>  
    1214 1215 </callout>  
    1215 1216 </calloutlist>  
    1216 1217 </example>  
    1217   <para>Now we can look at the &for; loop in <classname>MP3FileInfo</classname>, from the sample &fileinfo_filename; program introduced in <xref linkend="fileinfo" endterm="fileinfo.numberonly"/>.</para>  
      1218 <para>现在我们来看看在 <xref linkend="fileinfo" endterm="fileinfo.numberonly"/>介绍的样例程序 &fileinfo_filename; <classname>MP3FileInfo</classname> 中的 &for; 循环 。 </para>  
    1217 1218 <example id="fileinfo.multiassign.for.example">  
    1218   <title>&for; Loop in &mp3fileinfo_classname;</title>  
      1219 <title>&mp3fileinfo_classname; 中的 &for; 循环</title>  
    1218 1219 <programlisting>  
    1219 1220 &fileinfo_mp3classvar;                               <co id="fileinfo.multiassign.5.1"/>  
     
    1232 1233 <calloutlist>  
    1233 1234 <callout arearefs="fileinfo.multiassign.5.1">  
    1234   <para>&tagdatamap; is a <link linkend="fileinfo.classattributes">class attribute</link> that defines the tags you're looking for in an &mp3; file.  Tags are stored in fixed-length fields.  Once you read the last 128 bytes of the file, bytes 3 through 32 of those are always the song title, 33 through 62 are always the artist name, 63 through 92 are the album name, and so forth.  Note that &tagdatamap; is a dictionary of tuples, and each tuple contains two integers and a function reference.</para>  
      1235 <para>&tagdatamap;  是一个 <link linkend="fileinfo.classattributes">类属性</link> ,它定义了我们正在一个 &mp3; 文件中搜索的标记。标记存储为定长字段,一旦我们读出文件最后 128 个字节,第 3 到 32 字节总是歌曲的名字,33-62 总是歌手的名字,63-92 为专辑的名字,等等。请注意 &tagdatamap; 是一个 tuple 的 dictionary,每个 tuple 包含两个整数和一个函数引用。</para>  
    1234 1235 </callout>  
    1235 1236 <callout arearefs="fileinfo.multiassign.5.2">  
    1236   <para>This looks complicated, but it's not.  The structure of the &for; variables matches the structure of the elements of the list returned by &items;.  Remember that &items; returns a list of tuples of the form <literal>(<replaceable>key</replaceable>, <replaceable>value</replaceable>)</literal>.  The first element of that list is <literal>("title", (3, 33, &lt;function stripnulls>))</literal>, so the first time around the loop, <varname>tag</varname> gets <literal>"title"</literal>, <varname>start</varname> gets <literal>3</literal>, <varname>end</varname> gets <literal>33</literal>, and <varname>parseFunc</varname> gets the function <function>stripnulls</function>.</para>  
      1237 <para>这个看上去复杂一些,但其实并非如此。这个 &for; 变量结构与 &items; 所返回的 list 的元素的结构相匹配。记住,&items; 返回一个形如 <literal>(<replaceable>key</replaceable>, <replaceable>value</replaceable>)</literal> 的 tuple 的 list。list 第一个元素是 <literal>("title", (3, 33, &lt;function stripnulls>))</literal>,所以循环的第一轮,<varname>tag</varname> 为 <literal>"title"</literal>,<varname>start</varname> 为 <literal>3</literal>,<varname>end</varname> 为 <literal>33</literal>,<varname>parseFunc</varname> 为函数 <function>stripnulls</function>。</para>  
    1236 1237 </callout>  
    1237 1238 <callout arearefs="fileinfo.multiassign.5.3">  
    1238   <para>Now that you've extracted all the parameters for a single &mp3; tag, saving the tag data is easy.  You <link linkend="odbchelper.list.slice">slice</link> <varname>tagdata</varname> from <varname>start</varname> to <varname>end</varname> to get the actual data for this tag, call <varname>parseFunc</varname> to post-process the data, and assign this as the value for the key <varname>tag</varname> in the pseudo-dictionary <varname>self</varname>.  After iterating through all the elements in &tagdatamap;, <varname>self</varname> has the values for all the tags, and <link linkend="fileinfo.specialmethods.setname">you know what that looks like</link>.</para>  
      1239 <para>现在我们已经从一个单个的 &mp3; 标记中提取出了所有的参数,将标记数据保存起来挺容易。我们从 <varname>start</varname> 到 <varname>end</varname> 对 <varname>tagdata</varname> 进行 <link linkend="odbchelper.list.slice">分片</link>,从而得到这个标记的实际数据,调用 <varname>parseFunc</varname> 对数据进行后续的处理,接着将 <varname>parseFunc</varname> 作为值赋值给伪字典 <varname>self</varname> 中的键字 <varname>tag</varname>。在遍历完 &tagdatamap; 中所有元素之后, <varname>self</varname> 拥有了所有标记的值, <link linkend="fileinfo.specialmethods.setname">你知道看上去是什么样</link>。</para>  
    1238 1239 </callout>  
    1239 1240 </calloutlist>  
     
    1245 1246 <section id="fileinfo.modules">  
    1246 1247 <?dbhtml filename="file_handling/more_on_modules.html"?>  
    1247   <title>Using &sysmodules;</title>  
      1248 <title>使用 &sysmodules;</title>  
    1247 1248 <abstract>  
    1248 1249 <title/>  
    1249   <para>Modules, like everything else in &python;, are objects.  Once imported, you can always get a reference to a module through the global dictionary &sysmodules;.</para>  
      1250 <para>与其它任何 &python; 的东西一样, 模块也是对象。 一旦导入,总是可以全局 dictionary &sysmodules; 来得到一个模块的引用。</para>  
    1249 1250 </abstract>  
    1250 1251 <example>  
    1251   <title>Introducing &sysmodules;</title>  
      1252 <title>&sysmodules; 介绍</title>  
    1251 1252 <screen>&prompt;<userinput>import sys</userinput>                          <co id="fileinfo.modules.1.1"/>  
    1252 1253 &prompt;<userinput>print '\n'.join(sys.modules.keys())</userinput> <co id="fileinfo.modules.1.2"/>  
     
    1269 1270 <calloutlist>  
    1270 1271 <callout arearefs="fileinfo.modules.1.1">  
    1271   <para>The &sys; module contains system-level information, such as the version of &python; you're running (<literal>&sys;.version</literal> or <literal>&sys;.version_info</literal>), and system-level options such as the maximum allowed recursion depth (<literal>&sys;.getrecursionlimit()</literal> and <literal>&sys;.setrecursionlimit()</literal>).</para>  
      1272 <para>这个 &sys; 模块包含了系统级的信息,象正在运行的 &python; 的版本 (<literal>&sys;.version</literal> 或 <literal>&sys;.version_info</literal>),和系统级选项,象最大允许递归的深度 (<literal>&sys;.getrecursionlimit()</literal> 和 <literal>&sys;.setrecursionlimit()</literal>)。</para>  
    1271 1272 </callout>  
    1272 1273 <callout arearefs="fileinfo.modules.1.2">  
    1273   <para>&sysmodules; is a dictionary containing all the modules that have ever been imported since &python; was started; the key is the module name, the value is the module object.  Note that this is more than just the modules <emphasis>your</emphasis> program has imported.  &python; preloads some modules on startup, and if you're using a &python; &ide;, &sysmodules; contains all the modules imported by all the programs you've run within the &ide;.</para>  
      1274 <para>&sysmodules; 是一个字典,它包含了从 &python; 开始运行起被导入的所有模块。键字就是模块名,键值就是模块对象。请注意除了你的程序导入的模块外还有其它模块。&python; 在启动时预先装入了一些模块,如果你在一个 &python; &ide; 环境下,&sysmodules; 包含了你在 &ide; 中运行的所有程序所导入的所有的模块。</para>  
    1273 1274 </callout>  
    1274 1275 </calloutlist>  
    1275 1276 </example>  
    1276   <para>This example demonstrates how to use &sysmodules;.</para>  
      1277 <para>这个例子展示了如何使用 &sysmodules;。</para>  
    1276 1277 <example>  
    1277   <title>Using &sysmodules;</title>  
      1278 <title>使用 &sysmodules;</title>  
    1277 1278 <screen>&prompt;<userinput>import fileinfo</userinput>         <co id="fileinfo.modules.1.3"/>  
    1278 1279 &prompt;<userinput>print '\n'.join(sys.modules.keys())</userinput>  
     
    1301 1302 <calloutlist>  
    1302 1303 <callout arearefs="fileinfo.modules.1.3">  
    1303   <para>As new modules are imported, they are added to &sysmodules;.  This explains why importing the same module twice is very fast: &python; has already loaded and cached the module in &sysmodules;, so importing the second time is simply a dictionary lookup.</para>  
      1304 <para>当导入新的模块,它们加入到 &sysmodules; 中。这就解释了为什么第二次导入相同的模块是非常的快:&python; 已经在 &sysmodules; 中装入和缓冲了,所以第二次导入仅仅对 dictionary 做了一个查询。</para>  
    1303 1304 </callout>  
    1304 1305 <callout arearefs="fileinfo.modules.1.4">  
    1305   <para>Given the name (as a string) of any previously-imported module, you can get a reference to the module itself through the &sysmodules; dictionary.</para>  
      1306 <para>一旦给出任何以前导入过的模块名(以字符串方式),通过 &sysmodules; dictionary,你可以得到对模块本身的一个引用。</para>  
    1305 1306 </callout>  
    1306 1307 </calloutlist>  
    1307 1308 </example>  
    1308   <para>The next example shows how to use the <literal>__module__</literal> class attribute with the &sysmodules; dictionary to get a reference to the module in which a class is defined.</para>  
      1309 <para>下面的例子展示了如何使用 <literal>__module__</literal> 类属性[todo] with the &sysmodules; dictionary to get a reference to the module in which a class is defined.</para>  
    1308 1309 <example>  
    1309   <title>The &moduleattr; Class Attribute</title>  
      1310 <title>&moduleattr; 类属性</title>  
    1309 1310 <screen>&prompt;<userinput>from fileinfo import MP3FileInfo</userinput>  
    1310 1311 &prompt;<userinput>MP3FileInfo.__module__</userinput>              <co id="fileinfo.modules.2.1"/>  
     
    1318 1319 <calloutlist>  
    1319 1320 <callout arearefs="fileinfo.modules.2.1">  
    1320   <para>Every &python; class has a built-in <link linkend="fileinfo.classattributes">class attribute</link> &moduleattr;, which is the name of the module in which the class is defined.</para>  
      1321 <para>每个 &python; 类拥有一个内置的 <link linkend="fileinfo.classattributes">类属性</link>  &moduleattr;,它是定义了这个类的模块的名字。</para>  
    1320 1321 </callout>  
    1321 1322 <callout arearefs="fileinfo.modules.2.2">  
    1322   <para>Combining this with the &sysmodules; dictionary, you can get a reference to the module in which a class is defined.</para>  
      1323 <para>将它与 &sysmodules; dictionary 复合使用,你可以得到定义了某个类的模块的引用。</para>  
    1322 1323 </callout>  
    1323 1324 </calloutlist>  
    1324 1325 </example>  
    1325   <para>Now you're ready to see how &sysmodules; is used in &fileinfo_filename;, the sample program introduced in <xref linkend="fileinfo" endterm="fileinfo.numberonly"/>.  This example shows that portion of the code.</para>  
      1326 <para>现在准备好了, 看看 &sysmodules; 在样例程序 <xref linkend="fileinfo" endterm="fileinfo.numberonly"/> 介绍的 &fileinfo_filename; 中是如何使用的。  这个例子显示它的一部分代码。</para>  
    1325 1326 <example>  
    1326   <title>&sysmodules; in &fileinfo_filename;</title>  
      1327 <title>&fileinfo_filename; 中的 &sysmodules;</title>  
    1326 1327 <programlisting>  
    1327 1328 &fileinfo_getdef; <co id="fileinfo.modules.3.1"/>  
     
    1335 1336 <calloutlist>  
    1336 1337 <callout arearefs="fileinfo.modules.3.1">  
    1337   <para>This is a function with two arguments; <varname>filename</varname> is required, but <varname>module</varname> is <link linkend="apihelper.optional">optional</link> and defaults to the module that contains the <classname>FileInfo</classname> class.  This looks inefficient, because you might expect &python; to evaluate the &sysmodules; expression every time the function is called.  In fact, &python; evaluates default expressions only once, the first time the module is imported.  As you'll see later, you never call this function with a <varname>module</varname> argument, so <varname>module</varname> serves as a function-level constant.</para>  
      1338 <para>这是一个有两个参数的函数;<varname>filename</varname> 是必须的,但 <varname>module</varname> 是 <link linkend="apihelper.optional">可选的</link> 并且 module 的缺省值包含了 <classname>FileInfo</classname> 类。这样看上去效率低,因为你可能认为 &python; 会在每次函数调用时计算这个 &sysmodules; 表达式。实际上,&python; 仅会对缺省表达式计算一次,是在模块导入的第一次。正如后面我们会看到,我们永远不会用一个 <varname>module</varname> 参数来调用这个函数,所以 <varname>module</varname> 的功能是作为一个函数级别的常量。</para>  
    1337 1338 </callout>  
    1338 1339 <callout arearefs="fileinfo.modules.3.2">  
    1339   <para>You'll plow through this line later, after you dive into the &os; module.  For now, take it on faith that <varname>subclass</varname> ends up as the name of a class, like <classname>MP3FileInfo</classname>.</para>  
      1340 <para>我们会在后面再仔细研究这一行,在我们了解了 &os; 模块之后。那么现在,只要想信 <varname>subclass</varname> 最终为一个类的名字就行了,象 <classname>MP3FileInfo</classname>。</para>  
    1339 1340 </callout>  
    1340 1341 <callout arearefs="fileinfo.modules.3.3">  
    1341   <para>You already know about <link linkend="apihelper.getattr">&getattr;</link>, which gets a reference to an object by name.  &hasattr; is a complementary function that checks whether an object has a particular attribute; in this case, whether a module has a particular class (although it works for any object and any attribute, just like &getattr;).  In English, this line of code says, <quote>If this module has the class named by <varname>subclass</varname> then return it, otherwise return the base class <classname>FileInfo</classname>.</quote></para>  
      1342 <para>你已经了解了 <link linkend="apihelper.getattr">&getattr;</link>,它可以通过名字得到一个对象的引用。&hasattr; 是一个补充性的函数,用来检查是否一个对象具有一个特别的属性;在本例中,用来检查一个模块是否有一个特别的类(然而它可以用于任何类和任何属性,就象 &getattr;)。用英语来说,这行代码是说, <quote>If this module has the class named by <varname>subclass</varname> then return it, otherwise return the base class <classname>FileInfo</classname>(如果这个模块有一个名为 <varname>subclass</varname> 的类,那么返回它,否则返回基类 <classname>FileInfo</classname>)</quote>。</para>  
    1341 1342 </callout>  
    1342 1343 </calloutlist>  
    1343 1344 </example>  
    1344 1345 <itemizedlist role="furtherreading">  
    1345   <title>Further Reading on Modules</title>  
    1346   <listitem><para>&pythontutorial; discusses exactly <ulink url="&url_pythontutorial;node6.html#SECTION006710000000000000000">when and how default arguments are evaluated</ulink>.</para></listitem>  
    1347   <listitem><para>&pythonlibraryreference; documents the <ulink url="&url_pythonlibraryreference;module-sys.html">&sys;</ulink> module.</para></listitem>  
      1346 <title>进一步阅读</title>  
      1347 <listitem><para>&pythontutorial; 讨论了 <ulink url="&url_pythontutorial;node6.html#SECTION006710000000000000000">缺省参数到底在什么时候和是如何计算的</ulink>。</para></listitem>  
      1348 <listitem><para>&pythonlibraryreference; 提供了 <ulink url="&url_pythonlibraryreference;module-sys.html">&sys;</ulink> 模块的文档。</para></listitem>  
    1348 1349 </itemizedlist>  
    1349 1350 </section>  
    1350 1351 <section id="fileinfo.os">  
    1351 1352 <?dbhtml filename="file_handling/os_module.html"?>  
    1352   <title>Working with Directories</title>  
      1353 <title>与 Directory 共事</title>  
    1352 1353 <abstract>  
    1353 1354 <title/>  
    1354   <para>The &ospath; module has several functions for manipulating files and directories.  Here, we're looking at handling pathnames and listing the contents of a directory.</para>  
      1355 <para>&ospath; 模块有几个操作文件和目录的函数。 这里, 我们看看如何 操作路径名和列出一个目录的内容。</para>  
    1354 1355 </abstract>  
    1355 1356 <example id="fileinfo.os.path.join.example">  
    1356   <title>Constructing Pathnames</title>  
      1357 <title>构造路径名</title>  
    1356 1357 <screen>  
    1357 1358 &prompt;<userinput>import os</userinput>  
     
    1372 1373 <calloutlist>  
    1373 1374 <callout arearefs="fileinfo.os.1.1">  
    1374   <para>&ospath; is a reference to a module -- which module depends on your platform.  Just as <link linkend="crossplatform.example">&getpass;</link> encapsulates differences between platforms by setting <varname>getpass</varname> to a platform-specific function, &os; encapsulates differences between platforms by setting <varname>path</varname> to a platform-specific module.</para>  
      1375 <para>&ospath; 是一个模块的引用;使用哪一个模块要看你正运行在哪种平台上。就象 <link linkend="crossplatform.example">&getpass;</link> 通过将 <varname>getpass</varname> 设置为一个与平台相关的函数从而封装了平台之间的不同。&os; 通过设置 <varname>path</varname> 封装不同的相关平台模块。</para>  
    1374 1375 </callout>  
    1375 1376 <callout arearefs="fileinfo.os.1.2">  
    1376   <para>The &join; function of &ospath; constructs a pathname out of one or more partial pathnames.  In this case, it simply concatenates strings.  (Note that dealing with pathnames on &windows; is annoying because the backslash character must be escaped.)</para>  
      1377 <para>&ospath; 的 &join; 函数用一个或多个部分路径名构造成一个路径名。在这个简单的例子中,它只是将字符串进行连接。(请注意在 &windows; 下处理路径名是一个麻烦的事,因为反斜线字符必须被转义。)</para>  
    1376 1377 </callout>  
    1377 1378 <callout arearefs="fileinfo.os.1.3">  
    1378   <para>In this slightly less trivial case, &join; will add an extra backslash to the pathname before joining it to the filename.  I was overjoyed when I discovered this, since <function>addSlashIfNecessary</function> is one of the stupid little functions I always need to write when building up my toolbox in a new language.  <emphasis>Do not</emphasis> write this stupid little function in &python;; smart people have already taken care of it for you.</para>  
      1379 <para>在这个几乎没有价值的例子中,在将路径名加到文件名上之前,&join; 将在路径名后添加额外的反斜线。当我发现这一点时我高兴极了,因为当用一种新的语言创建我自已的工具包时,<function>addSlashIfNecessary</function> 总是我必须要写的那些愚蠢的小函数之一。在 &python; 中  <emphasis>不要</emphasis> 写这样的愚蠢的小函数,聪明的人已经为你考虑到了。</para>  
    1378 1379 </callout>  
    1379 1380 <callout arearefs="fileinfo.os.1.4">  
    1380   <para><function>expanduser</function> will expand a pathname that uses <literal>~</literal> to represent the current user's home directory.  This works on any platform where users have a home directory, like &windows;, &unix;, and &macosx;; it has no effect on &macos;.</para>  
      1381 <para><function>expanduser</function>  将对使用 <literal>~</literal> 来表示当前用户根目录的路径名进行扩展。在任何平台上,只要用户拥有一个根目录,它就会有效,象&windows;, &unix;,和 &macosx;; 在 &macos; 上无效。</para>  
    1380 1381 </callout>  
    1381 1382 <callout arearefs="fileinfo.os.1.5">  
    1382   <para>Combining these techniques, you can easily construct pathnames for directories and files under the user's home directory.</para>  
      1383 <para>将这些技术合在一起,你可以容易地对在用户根目录下为目录和文件构造出路径名。</para>  
    1382 1383 </callout>  
    1383 1384 </calloutlist>  
    1384 1385 </example>  
    1385 1386 <example id="splittingpathnames.example">  
    1386   <title>Splitting Pathnames</title>  
      1387 <title>分割路径名</title>  
    1386 1387 <screen>&prompt;<userinput>os.path.split("c:\\music\\ap\\mahadeva.mp3")</userinput>                        <co id="fileinfo.os.2.1"/>  
    1387 1388 <computeroutput>('c:\\music\\ap', 'mahadeva.mp3')</computeroutput>  
     
    1404 1405 <calloutlist>  
    1405 1406 <callout arearefs="fileinfo.os.2.1">  
    1406   <para>The &split; function splits a full pathname and returns a tuple containing the path and filename.  Remember when I said you could use <link linkend="odbchelper.multiassign">multi-variable assignment</link> to return multiple values from a function?  Well, &split; is such a function.</para>  
      1407 <para>&split;  函数对一个全路径名进行分割,返回一个包含路径和文件名的元组。还记得我说过你可以使用 <link linkend="odbchelper.multiassign">多变量赋值</link> 从一个函数返回多个值吗?对,&split; 就是这样一个函数。</para>  
    1406 1407 </callout>  
    1407 1408 <callout arearefs="fileinfo.os.2.2">  
    1408   <para>You assign the return value of the &split; function into a tuple of two variables.  Each variable receives the value of the corresponding element of the returned tuple.</para>  
      1409 <para>我们将 &split; 函数的返回值赋值给一个两个变量的 tuple。每个变量接收到返回的 tuple 相对应的元素值。</para>  
    1408 1409 </callout>  
    1409 1410 <callout arearefs="fileinfo.os.2.3">  
    1410   <para>The first variable, <varname>filepath</varname>, receives the value of the first element of the tuple returned from &split;, the file path.</para>  
      1411 <para>第一个变量,<varname>filepath</varname>,接收到从 &split; 返回的元组的第一个元素的值,文件路径。</para>  
    1410 1411 </callout>  
    1411 1412 <callout arearefs="fileinfo.os.2.4">  
    1412   <para>The second variable, <varname>filename</varname>, receives the value of the second element of the tuple returned from &split;, the filename.</para>  
      1413 <para>第二个变量,<varname>filename</varname>,接收到从 &split; 返回的元组的第二个元素的值,文件名。</para>  
    1412 1413 </callout>  
    1413 1414 <callout arearefs="fileinfo.os.2.5">  
    1414   <para>&ospath; also contains a function &splitext;, which splits a filename and returns a tuple containing the filename and the file extension.   You use the same technique to assign each of them to separate variables.</para>  
      1415 <para>&ospath; 也包含了一个 &splitext; 函数,可以用来对文件名进行分割,并且回一个包含了文件名和文件扩展名的元组。我们使用相同的技术来将它们赋值给独立的变量。</para>  
    1414 1415 </callout>  
    1415 1416 </calloutlist>  
    1416 1417 </example>  
    1417 1418 <example id="fileinfo.listdir.example">  
    1418   <title>Listing Directories</title>  
      1419 <title>列出目录</title>  
    1418 1419 <screen>&prompt;<userinput>os.listdir("c:\\music\\_singles\\")</userinput>              <co id="fileinfo.os.3.1"/>  
    1419 1420 <computeroutput>['a_time_long_forgotten_con.mp3', 'hellraiser.mp3',  
     
    1444 1445 <calloutlist>  
    1445 1446 <callout arearefs="fileinfo.os.3.1">  
    1446   <para>The &listdir; function takes a pathname and returns a list of the contents of the directory.</para>  
      1447 <para>&listdir; 函数接收一个路径名,它返回那个目录的内容的一个列表。</para>  
    1446 1447 </callout>  
    1447 1448 <callout arearefs="fileinfo.os.3.2">  
    1448   <para>&listdir; returns both files and folders, with no indication of which is which.</para>  
      1449 <para>&listdir; 同时返回文件和文件夹,并不指出哪个是文件,哪个是文件夹。</para>  
    1448 1449 </callout>  
    1449 1450 <callout arearefs="fileinfo.os.3.3">  
    1450   <para>You can use <link linkend="apihelper.filter">list filtering</link> and the <function>isfile</function> function of the &ospath; module to separate the files from the folders.  &isfile; takes a pathname and returns 1 if the path represents a file, and 0 otherwise.  Here you're using <literal>&ospath;.&join;</literal> to ensure a full pathname, but &isfile; also works with a partial path, relative to the current working directory.  You can use <literal>os.getcwd()</literal> to get the current working directory.</para>  
      1451 <para>你可以使用 <link linkend="apihelper.filter">list 过滤</link> 和 &ospath; 模块的 <function>isfile</function> 函数,从文件夹中将文件分离出来。&isfile;  接收一个路径名,如果路径表示一个文件,则返回 1,否则为 0。在这里,我们使用 <literal>&ospath;.&join;</literal> 来确保一个全路径名,但 &isfile;  对一个相对于当前工作目录的部分路径也是有效的。你可以使用 <literal>os.getcwd()</literal>  来得到当前的工作目录。</para>  
    1450 1451 </callout>  
    1451 1452 <callout arearefs="fileinfo.os.3.4">  
    1452   <para>&ospath; also has a <function>isdir</function> function which returns 1 if the path represents a directory, and 0 otherwise.  You can use this to get a list of the subdirectories within a directory.</para>  
      1453 <para>&ospath; 还有一个 <function>isdir</function> 函数,当路径表示一个目录,则返回 1,否则为 0。你可以使用它来得到一个目录下的子目录列表。</para>  
    1452 1453 </callout>  
    1453 1454 </calloutlist>  
    1454 1455 </example>  
    1455 1456 <example>  
    1456   <title>Listing Directories in &fileinfo_filename;</title>  
      1457 <title>在 &fileinfo_filename; 中列出目录</title>  
    1456 1457 <programlisting>  
    1457 1458 &fileinfo_listdef;  
     
    1466 1467 <calloutlist>  
    1467 1468 <callout arearefs="fileinfo.os.3a.1">  
    1468   <para><literal>os.listdir(directory)</literal> returns a list of all the files and folders in <varname>directory</varname>.</para>  
      1469 <para><literal>os.listdir(directory)</literal> 返回在 <varname>directory</varname> 中所有文件和文件夹的一个 list。</para>  
    1468 1469 </callout>  
    1469 1470 <callout arearefs="fileinfo.os.3a.2">  
    1470   <para>Iterating through the list with <varname>f</varname>, you use <literal>os.path.normcase(f)</literal> to normalize the case according to operating system defaults.  <function>normcase</function> is a useful little function that compensates for case-insensitive operating systems that think that <filename>mahadeva.mp3</filename> and <filename>mahadeva.MP3</filename> are the same file.  For instance, on &windows; and &macos;, <function>normcase</function> will convert the entire filename to lowercase; on &unix;-compatible systems, it will return the filename unchanged.</para>  
      1471 <para>使用 <varname>f</varname> 对 list 进行遍历,我们使用 <literal>os.path.normcase(f)</literal>  根据操作系统的缺省值对大小写进行标准化处理。 <function>normcase</function>  是一个有用的函数,用于对大小写不敏感操作系统的一个补充。这种操作系统认为 <filename>mahadeva.mp3</filename>  和 <filename>mahadeva.MP3</filename> 是同一个文件名。例如,在 &windows; 和 &macos; 下,<function>normcase</function>  将把整个文件名转换为小写字母;而在 &unix; 兼容的系统下,它将返回未作修改的文件名。</para>  
    1470 1471 </callout>  
    1471 1472 <callout arearefs="fileinfo.os.3a.3">  
    1472   <para>Iterating through the normalized list with <varname>f</varname> again, you use <literal>os.path.splitext(f)</literal> to split each filename into name and extension.</para>  
      1473 <para>再次用 <varname>f</varname> 对标准化后的 list 进行遍历,我们使用 <literal>os.path.splitext(f)</literal> 将每个文件名分割为名字和扩展名。 </para>  
    1472 1473 </callout>  
    1473 1474 <callout arearefs="fileinfo.os.3a.4">  
    1474   <para>For each file, you see if the extension is in the list of file extensions you care about (<varname>fileExtList</varname>, which was passed to the <function>listDirectory</function> function).</para>  
      1475 <para>对每个文件,我们查看是否扩展名在我们关心的文件扩展名 list 中 (<varname>fileExtList</varname>,被传递给 <function>listDirectory</function> 函数)。</para>  
    1474 1475 </callout>  
    1475 1476 <callout arearefs="fileinfo.os.3a.5">  
    1476   <para>For each file you care about, you use <literal>os.path.join(directory, f)</literal> to construct the full pathname of the file, and return a list of the full pathnames.</para>  
      1477 <para>对每个我们所关心的文件,我们使用 <literal>os.path.join(directory, f)</literal> 来构造这个文件的全路径名,接着返回这个全路径名的 list。</para>  
    1476 1477 </callout>  
    1477 1478 </calloutlist>  
     
    1485 1486 <!--<title>When To Use the &os; Module</title>-->  
    1486 1487 <title/>  
    1487   <para>Whenever possible, you should use the functions in &os; and &ospath; for file, directory, and path manipulations.  These modules are wrappers for platform-specific modules, so functions like <function>os.path.split</function> work on &unix;, &windows;, &macos;, and any other platform supported by &python;.</para>  
      1488 <para>只要有可能,你应该使用在 &os; 和 &ospath; 中的函数进行文件,目录,和路径的操作。这些模块是对平台相关模块的封装模块,所以象 <function>os.path.split</function> 这样的函数可以工作在&unix;, &windows;,&macos; 和 &python; 所支持的任一种平台上。</para>  
    1487 1488 </note>  
    1488   <para>There is one other way to get the contents of a directory.  It's very powerful, and it uses the sort of wildcards that you may already be familiar with from working on the command line.</para>  
      1489 <para>[todo]There is one other way to get the contents of a directory.  It's very powerful, and it uses the sort of wildcards that you may already be familiar with from working on the command line.</para>  
    1488 1489 <example id="fileinfo.os.glob.example">  
    1489 1490 <title>Listing Directories with &glob;</title>  
     
    1524 1525 </example>  
    1525 1526 <itemizedlist role="furtherreading">  
    1526   <title>Further Reading on the &os; Module</title>  
    1527   <listitem><para>&pythonknowledgebase; answers <ulink url="&url_pythonknowledgebase;index.phtml/fid/240">questions about the &os; module</ulink>.</para></listitem>  
    1528   <listitem><para>&pythonlibraryreference; documents the <ulink url="&url_pythonlibraryreference;module-os.html">&os;</ulink> module and the <ulink url="&url_pythonlibraryreference;module-os.path.html">&ospath;</ulink> module.</para></listitem>  
      1527 <title>进一步阅读</title>  
      1528 <listitem><para>&pythonknowledgebase; 回答了 <ulink url="&url_pythonknowledgebase;index.phtml/fid/240">关于 &os; 模块的问题</ulink>。</para></listitem>  
      1529 <listitem><para>&pythonlibraryreference; 提供了 <ulink url="&url_pythonlibraryreference;module-os.html">&os;</ulink> 模块和 <ulink url="&url_pythonlibraryreference;module-os.path.html">&ospath;</ulink> 模块的文档。 </para></listitem>  
    1529 1530 </itemizedlist>  
    1530 1531 </section>  
    1531 1532 <section id="fileinfo.alltogether">  
    1532 1533 <?dbhtml filename="file_handling/all_together.html"?>  
    1533   <title>Putting It All Together</title>  
      1534 <title>全部放在一起</title>  
    1533 1534 <abstract>  
    1534 1535 <title/>  
    1535   <para>Once again, all the dominoes are in place.  You've seen how each line of code works.  Now let's step back and see how it all fits together.</para>  
      1536 <para>再一次,所有的多米诺骨牌都放好了。我们已经看过每行代码是如何工作的了。现在往回走一步,看一下放在一起是怎么样的。</para>  
    1535 1536 </abstract>  
    1536 1537 <example id="fileinfo.nested">  
     
    1550 1551 <calloutlist>  
    1551 1552 <callout arearefs="fileinfo.alltogether.1.1">  
    1552   <para>&listdirectory; is the main attraction of this entire module.  It takes a directory (like <filename class="directory">c:\music\_singles\</filename> in my case) and a list of interesting file extensions (like <literal>['.mp3']</literal>), and it returns a list of class instances that act like dictionaries that contain metadata about each interesting file in that directory.  And it does it in just a few straightforward lines of code.</para>  
      1553 <para>&listdirectory; 是整个模块主要的引吸之处。它接收一个字典 (在我的例子中如 <filename class="directory">c:\music\_singles\</filename>) 和一个感兴趣的文件扩展名列表 (如 <literal>['.mp3']</literal>),接着它返回一个类实例的 list ,这些类实例的行为象字典,包含了在目录中每个感兴趣文件的元数据。并且实现起来只用了几行直观的代码。</para>  
    1552 1553 </callout>  
    1553 1554 <callout arearefs="fileinfo.alltogether.1.2">  
    1554   <para>As you saw in the <link linkend="fileinfo.os">previous section</link>, this line of code gets a list of the full pathnames of all the files in <varname>directory</varname> that have an interesting file extension (as specified by <varname>fileExtList</varname>).</para>  
      1555 <para>正如在 <link linkend="fileinfo.os">前一节</link> 我们所看到的,这行代码得到一个全路径名的列表,它们是在 <varname>directory</varname> 中有着我们感兴趣的文件后缀 (由 <varname>fileExtList</varname> 所指定的) 的所有文件的路径名。</para>  
    1554 1555 </callout>  
    1555 1556 <callout arearefs="fileinfo.alltogether.1.3">  
    1556   <para>Old-school &pascal; programmers may be familiar with them, but most people give me a blank stare when I tell them that &python; supports <emphasis>nested functions</emphasis> -- literally, a function within a function.  The nested function <function>getFileInfoClass</function> can be called only from the function in which it is defined, &listdirectory;.  As with any other function, you don't need an interface declaration or anything fancy; just define the function and code it.</para>  
      1557 <para>老学校出身的 &pascal; 程序员可能对嵌套函数感到熟悉,但大部分人,当我告诉他们  &python;  支持嵌套函数时,都茫然地看着我。<emphasis>嵌套函数</emphasis>,从字面理解,是定义在函数内的函数。嵌套函数 <function>getFileInfoClass</function>  只能在定义它的函数 &listdirectory; 内进行调用。正如任何其它的函数一样,不需要一个接口声明或奇怪的什么东西,只要定义函数,开始编码就行了。</para>  
    1556 1557 </callout>  
    1557 1558 <callout arearefs="fileinfo.alltogether.1.4">  
    1558   <para>Now that you've seen the <link linkend="fileinfo.os">&os;</link> module, this line should make more sense.  It gets the extension of the file (<literal>os.path.splitext(filename)[1]</literal>), forces it to uppercase (<literal>.upper()</literal>), slices off the dot (<literal>[1:]</literal>), and constructs a class name out of it with string formatting.  So <filename>c:\music\ap\mahadeva.mp3</filename> becomes <literal>.mp3</literal> becomes <literal>.MP3</literal> becomes <literal>MP3</literal> becomes <literal>MP3FileInfo</literal>.</para>  
      1559 <para>既然你已经看过 <link linkend="fileinfo.os">&os;</link> 模块了,这一行应该能理解了。它得到文件的扩展名 (<literal>os.path.splitext(filename)[1]</literal>),将其转换为大写字母 (<literal>.upper()</literal>),从圆点处进行分片 (<literal>[1:]</literal>),使用字符串格式化从其中生成一个类名。所以 <filename>c:\music\ap\mahadeva.mp3</filename> 变成 <literal>.mp3</literal> 再变成 <literal>MP3</literal> 再变成 <literal>MP3FileInfo</literal>。</para>  
    1558 1559 </callout>  
    1559 1560 <callout arearefs="fileinfo.alltogether.1.5">  
    1560   <para>Having constructed the name of the handler class that would handle this file, you check to see if that handler class actually exists in this module.  If it does, you return the class, otherwise you return the base class &fileinfo_classname;.  This is a very important point: <emphasis>this function returns a class</emphasis>.  Not an instance of a class, but the class itself.</para>  
      1561 <para>在生成完处理这个文件的处理类的名字之后,我们查阅在这个模块中是否存在这个处理类。如果存在,我们返回这个类,否则我们返回基类 &fileinfo_classname;。这一点很重要: <emphasis>这个函数返回一个类</emphasis>。不是类的实例,而是类本身。</para>  
    1560 1561 </callout>  
    1561 1562 <callout arearefs="fileinfo.alltogether.1.6">  
    1562   <para>For each file in the <quote>interesting files</quote> list (<varname>fileList</varname>), you call <function>getFileInfoClass</function> with the filename (<varname>f</varname>).  Calling <literal>getFileInfoClass(f)</literal> returns a class; you don't know exactly which class, but you don't care.  You then create an instance of this class (whatever it is) and pass the filename (<varname>f</varname> again), to the &init; method.  As you saw <link linkend="fileinfo.specialmethods.setname">earlier in this chapter</link>, the &init; method of &fileinfo_classname; sets <literal>self["name"]</literal>, which triggers &setitem;, which is overridden in the descendant (&mp3fileinfo_classname;) to parse the file appropriately to pull out the file's metadata.  You do all that for each interesting file and return a list of the resulting instances.</para>  
      1563 <para>对每个属于我们 <quote>感兴趣文件</quote> list (<varname>fileList</varname>)中的文件,我们用文件名 (<varname>f</varname>) 来调用 <function>getFileInfoClass</function>。调用 <literal>getFileInfoClass(f)</literal> 返回一个类;我们并不知道确切是哪一个类,但是我们并不关心。接着我们创建这个类(不管它是什么)的一个实例,传入文件名(又是<varname>f</varname> 给 &init; 方法。正如我们在 <link linkend="fileinfo.specialmethods.setname">本章的前面</link> 所看到的,&fileinfo_classname; 的 &init; 方法设置了 <literal>self["name"]</literal>,它将引发 &setitem; 的调用,&setitem; 在子类 (&mp3fileinfo_classname;) 中被覆盖掉了,用来适当地对文件进行分析,取出文件的元数据。我们对所有感兴趣的文件进行处理,返回结果实例的一个 list。</para>  
    1562 1563 </callout>  
    1563 1564 </calloutlist>  
    1564 1565 </example>  
    1565   <para>Note that &listdirectory; is completely generic.  It doesn't know ahead of time which types of files it will be getting, or which classes are defined that could potentially handle those files.  It inspects the directory for the files to process, and then introspects its own module to see what special handler classes (like &mp3fileinfo_classname;) are defined.  You can extend this program to handle other types of files simply by defining an appropriately-named class: <classname>HTMLFileInfo</classname> for <acronym>HTML</acronym> files, <classname>DOCFileInfo</classname> for <application>Word</application> <literal>.doc</literal> files, and so forth.  &listdirectory; will handle them all, without modification, by handing off the real work to the appropriate classes and collating the results.</para>  
      1566 <para>请注意 &listdirectory; 完全是通用的。它事先不知道将得到文件哪种类型,或者哪些定义好的类能够处理这些文件。它检查目录中要进行处理的文件,然后反观本身模块,了解定义了什么特别的处理类 (象 &mp3fileinfo_classname;)。你可以对这个程序进行扩充,对其它类型的文件进行处理,只要用适合的名字定义类:<classname>HTMLFileInfo</classname> 用于 <acronym>HTML</acronym> 文件,<classname>DOCFileInfo</classname> 用于 <application>Word</application> <literal>.doc</literal> 文件,等等。&listdirectory; 将会对它们都进行处理,不作改变,将工作交给适当的类,接着收集结果。</para>  
    1565 1566 </section>  
    1566 1567 <section id="fileinfo.summary2">  
    1567 1568 <?dbhtml filename="file_handling/summary.html"?>  
    1568   <title>Summary</title>  
      1569 <title>小结</title>  
    1568 1569 <abstract>  
    1569 1570 <title/>  
    1570   <para>The &fileinfo_filename; program introduced in <xref linkend="fileinfo" endterm="fileinfo.numberonly"/> should now make perfect sense.</para>  
      1571 <para>在 <xref linkend="fileinfo" endterm="fileinfo.numberonly"/> 介绍的 &fileinfo_filename; 程序现在应该完全理解了。</para>  
    1570 1571 </abstract>  
    1571 1572 <informalexample>  
    1635 1636 </informalexample>  
    1636 1637 <highlights>  
    1637   <para>Before diving into the next chapter, make sure you're comfortable doing the following things:</para>  
      1638 <para>在研究下一章之前,确保你可以无困难地完成下面的事情:</para>  
    1637 1638 <itemizedlist>  
    1638   <listitem><para>Catching exceptions with <link linkend="fileinfo.exception">&tryexcept;</link></para></listitem>  
    1639   <listitem><para>Protecting external resources with <link linkend="fileinfo.files.incode">&tryfinally;</link></para></listitem>  
    1640   <listitem><para>Reading from <link linkend="fileinfo.files">files</link></para></listitem>  
    1641   <listitem><para>Assigning multiple values at once in a <link linkend="fileinfo.multiassign.for.example">&for; loop</link></para></listitem>  
    1642   <listitem><para>Using the <link linkend="fileinfo.os">&os;</link> module for all your cross-platform file manipulation needs</para></listitem>  
    1643   <listitem><para>Dynamically <link linkend="fileinfo.alltogether">instantiating classes of unknown type</link> by treating classes as objects and passing them around</para></listitem>  
      1639 <listitem><para>使用 <link linkend="fileinfo.exception">&tryexcept;</link> 来捕捉异常</para></listitem>  
      1640 <listitem><para>使用 <link linkend="fileinfo.files.incode">&tryfinally;</link>来保护额外的资源</para></listitem>  
      1641 <listitem><para>读取 <link linkend="fileinfo.files">文件</link></para></listitem>  
      1642 <listitem><para>在一个 <link linkend="fileinfo.multiassign.for.example">&for; 循环</link> 中一次赋多个值</para></listitem>  
      1643 <listitem><para>使用 <link linkend="fileinfo.os">&os;</link> 模块来满足你的跨平台文件操作的需要</para></listitem>  
      1644 <listitem><para>动态地 <link linkend="fileinfo.alltogether">实例化未知类型的类</link> 通过将类看成对象并传入参数</para></listitem>  
    1644 1645 </itemizedlist>  
    1645 1646 </highlights>