Changeset 269

Show
Ignore:
Timestamp:
Mon Dec 19 12:12:32 2005
Author:
osmond
Message:

Chapter 6. 异常和文件处理 完毕 待审

Files:

Legend:

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

    r267 r269  
    818 818 <abstract>  
    819 819 <title/>  
    820   <para>在本章中, 将研究异常, 文件对象, &for; 循环, &os; 和 &sys; 模块等内容。 如果你已经在其它编程语言中使用过异常, 你可以简单看看第一部分来了解 &python; 的语法。  Be sure to tune in again for file handling.</para>  
      820 <para>在本章中, 将研究异常, 文件对象, &for; 循环, &os; 和 &sys; 模块等内容。 如果你已经在其它编程语言中使用过异常, 你可以简单看看第一部分来了解 &python; 的语法。  但是本章其它的内容仍需仔细研读。</para>  
    820 820 </abstract>  
    821 821 <section id="fileinfo.exception">  
     
    855 855 <calloutlist>  
    856 856 <callout arearefs="fileinfo.exceptions.1.1">  
    857   <para>使用内置 &open; 函数,我们可以试着打开一个文件来读取(在下一节有关于 &open; 的更多内容)。但是那个文件不存在,所以这样就引发 &ioerror; 异常。因为我们没有提供任何显式的对 &ioerror; 异常的检查,&python; 仅仅打印出某个关于发生了什么的调试信息,然后终止。</para>  
      857 <para>使用内置 &open; 函数,我们可以试着打开一个文件来读取 (在下一节有关于 &open; 的更多内容)。但是那个文件不存在,所以这样就引发 &ioerror; 异常。因为我们没有提供任何显式的对 &ioerror; 异常的检查,&python; 仅仅打印出某个关于发生了什么的调试信息,然后终止。</para>  
    857 857 </callout>  
    858 858 <callout arearefs="fileinfo.exceptions.1.2">  
     
    868 868 </calloutlist>  
    869 869 </example>  
    870   <para>异常可能看上去不友好(毕竟,如果你不捕捉异常,整个程序将崩溃),但是考虑一下别的方法。你宁愿找回对于不存在文件的不可用的文件对象吗?不管怎么样你都得检查它的有效性,而且如果你忘记了,你的程序将会在下面某个地方给出奇怪的错误,这样你将不得不追溯到源程序。我确信你做过这种事;这可并不有趣。使用异常,一发生错误,你就可以在问题的源头通过标准的方法来处理它们。</para>  
      870 <para>异常可能看上去不友好 (毕竟,如果你不捕捉异常,整个程序将崩溃),但是考虑一下别的方法。你宁愿找回对于不存在文件的不可用的文件对象吗?不管怎么样你都得检查它的有效性,而且如果你忘记了,你的程序将会在下面某个地方给出奇怪的错误,这样你将不得不追溯到源程序。我确信你做过这种事;这可并不有趣。使用异常,一发生错误,你就可以在问题的源头通过标准的方法来处理它们。</para>  
    870 870 <section>  
    871 871 <title>为其他用途使用异常</title>  
    872   <para>除了处理实际的错误条件之外,对于异常还有许多其它的用处。在标准 &python; 库中一个普通的用法就是试着导入一个模块,然后检查是否它能使用。导入一个并不存在的模块将引发一个 &importerror;  异常。你可以使用这种方法来定义多级别的功能,依靠在运行时哪个模块是有效的,或支持多种平台(即平台特定代码被分离到不同的模块中)。</para>  
      872 <para>除了处理实际的错误条件之外,对于异常还有许多其它的用处。在标准 &python; 库中一个普通的用法就是试着导入一个模块,然后检查是否它能使用。导入一个并不存在的模块将引发一个 &importerror;  异常。你可以使用这种方法来定义多级别的功能,依靠在运行时哪个模块是有效的,或支持多种平台 (即平台特定代码被分离到不同的模块中)。</para>  
    872 872 <para>你也能通过创建一个从内置的  <classname>Exception</classname> 类继承的类定义你自己的异常, 然后使用 <function>raise</function> 命令引发你的异常。如果你对此感兴趣,请看进一步阅读的部分。</para>  
    873 873  
     
    907 907 </callout>  
    908 908 <callout arearefs="fileinfo.exceptions.2.4">  
    909   <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>  
      909 <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>  
    909 909 </callout>  
    910 910 <callout arearefs="fileinfo.exceptions.2.5">  
     
    919 919 <listitem><para>&pythonlibraryreference; 总结了 <ulink url="&url_pythonlibraryreference;module-exceptions.html">所有内置异常</ulink>。</para></listitem>  
    920 920 <listitem><para>&pythonlibraryreference; 提供了 <ulink url="&url_pythonlibs;module-getpass.html">getpass</ulink> 模块的文档。</para></listitem>  
    921   <listitem><para>&pythonlibraryreference; 提供了 <ulink url="&url_pythonlibraryreference;module-traceback.html"><filename class="headerfile">traceback</filename> 模块</ulink>的文档, 这个模块在异常引发之后,提供了底层的对异常属性的处理。</para></listitem>  
    922   <listitem><para>&pythonlanguagereference; 讨论了 <ulink url="&url_pythonlanguagereference;try.html">&tryexcept; 块</ulink>的内部工作方式。</para></listitem>  
      921 <listitem><para>&pythonlibraryreference; 提供了 <ulink url="&url_pythonlibraryreference;module-traceback.html"><filename class="headerfile">traceback</filename> 模块</ulink> 的文档, 这个模块在异常引发之后,提供了底层的对异常属性的处理。</para></listitem>  
      922 <listitem><para>&pythonlanguagereference; 讨论了 <ulink url="&url_pythonlanguagereference;try.html">&tryexcept; 块</ulink> 的内部工作方式。</para></listitem>  
    923 923 </itemizedlist>  
    924 924 </section>  
     
    926 926 <section id="fileinfo.files">  
    927 927 <?dbhtml filename="file_handling/file_objects.html"?>  
    928   <title>与 文件对象 共事</title>  
      928 <title>与文件对象共事</title>  
    928 928 <abstract>  
    929 929 <title/>  
     
    945 945 </callout>  
    946 946 <callout arearefs="fileinfo.files.1.2">  
    947   <para>&open;  函数返回一个对象(到现在为止,<link linkend="odbchelper.objects">这一点应该不会使你感到吃惊</link>)。一个文件对象有几个有用的属性。</para>  
      947 <para>&open;  函数返回一个对象 (到现在为止,<link linkend="odbchelper.objects">这一点应该不会使你感到吃惊</link>)。一个文件对象有几个有用的属性。</para>  
    947 947 </callout>  
    948 948 <callout arearefs="fileinfo.files.1.3">  
     
    979 979 </callout>  
    980 980 <callout arearefs="fileinfo.files.2.2">  
    981   <para>文件对象的 &seek; 方法在打开文件中移动到另一个位置。第二个参数指出第一个参数是什么意思:&zero; 表示移动到一个绝对位置(从文件开始算起),&one; 表示移到一个相对位置(从当前位置算起),还有 <literal>2</literal>  表示对于文件尾的一个相对位置。因为我们搜索的 &mp3; 标记保存在文件的末尾,我们使用 <literal>2</literal>  并且告诉文件对象从文件尾移动到 <literal>128</literal> 字节的位置。</para>  
      981 <para>文件对象的 &seek; 方法在打开文件中移动到另一个位置。第二个参数指出第一个参数是什么意思:&zero; 表示移动到一个绝对位置 (从文件开始算起),&one; 表示移到一个相对位置 (从当前位置算起),还有 <literal>2</literal>  表示对于文件尾的一个相对位置。因为我们搜索的 &mp3; 标记保存在文件的末尾,我们使用 <literal>2</literal>  并且告诉文件对象从文件尾移动到 <literal>128</literal> 字节的位置。</para>  
    981 981 </callout>  
    982 982 <callout arearefs="fileinfo.files.2.3">  
    983   <para>&tell;方法确认了已经移到当前文件位置。</para>  
      983 <para>&tell; 方法确认了已经移到当前文件位置。</para>  
    983 983 </callout>  
    984 984 <callout arearefs="fileinfo.files.2.4">  
    985   <para> &read;  方法从打开文件中读取指定个数的字节,并且返回含有读取数据的字符串。可选参数指定了读取的最大字节数。如果没有指定参数,&read; 将读到文件末尾。(我们本可以在这里简单地说一下  <literal>read()</literal> ,因为我们确切地知道在文件的何处,事实上,我们读的是最后128个字节。)读出的数据赋给变量 <varname>tagData</varname>,并且当前的位置根据所读的字节数作了修改。</para>  
      985 <para> &read;  方法从打开文件中读取指定个数的字节,并且返回含有读取数据的字符串。可选参数指定了读取的最大字节数。如果没有指定参数,&read; 将读到文件末尾。(我们本可以在这里简单地说一下  <literal>read()</literal> ,因为我们确切地知道在文件的何处,事实上,我们读的是最后 128 个字节。) 读出的数据赋给变量 <varname>tagData</varname>,并且当前的位置根据所读的字节数作了修改。</para>  
    985 985 </callout>  
    986 986 <callout arearefs="fileinfo.files.2.5">  
    987   <para>&tell; 方法确认了当前位置已经移动了。如果做一下算术,你会看到在读了128个字节之后,位置数已经增加了128。</para>  
      987 <para>&tell; 方法确认了当前位置已经移动了。如果做一下算术,你会看到在读了 128 个字节之后,位置数已经增加了 128。</para>  
    987 987 </callout>  
    988 988 </calloutlist>  
     
    1020 1020 <calloutlist>  
    1021 1021 <callout arearefs="fileinfo.files.3.1">  
    1022   <para>文件对象的 <varname>closed</varname> 属性表示对象是否打开或关闭了文件。在本例中,文件仍然打开着(<varname>closed</varname> 是 &false;)。打开文件要消耗系统资源,并且根据文件模式,其它程序可能不能使用它们。一旦你处理完它们,把文件关闭这一点很重要。</para>  
      1022 <para>文件对象的 <varname>closed</varname> 属性表示对象是否打开或关闭了文件。在本例中,文件仍然打开着 (<varname>closed</varname> 是 &false;)。打开文件要消耗系统资源,并且根据文件模式,其它程序可能不能使用它们。一旦你处理完它们,把文件关闭这一点很重要。</para>  
    1022 1022 </callout>  
    1023 1023 <callout arearefs="fileinfo.files.3.2">  
    1024   <para>为了关闭文件,调用文件对象的 &close; 方法。这样就释放掉你加在文件上的锁(如果有的话),刷新被缓冲的系统确实还未写入的输出(如果有的话),并且释放系统资源。</para>  
      1024 <para>为了关闭文件,调用文件对象的 &close; 方法。这样就释放掉你加在文件上的锁 (如果有的话),刷新被缓冲的系统确实还未写入的输出 (如果有的话),并且释放系统资源。</para>  
    1024 1024 </callout>  
    1025 1025 <callout arearefs="fileinfo.files.3.3">  
     
    1063 1063 </callout>  
    1064 1064 <callout arearefs="fileinfo.files.4.3">  
    1065   <para>&seek; 方法可能引发 &ioerror; 异常。(可能是文件长度小于128字节。)</para>  
      1065 <para>&seek; 方法可能引发 &ioerror; 异常。(可能是文件长度小于 128 字节。)</para>  
    1065 1065 </callout>  
    1066 1066 <callout arearefs="fileinfo.files.4.4">  
     
    1072 1072 </callout>  
    1073 1073 <callout arearefs="fileinfo.files.4.6">  
    1074   <para>最后,处理我们的 &ioerror; 异常。它可能是由调用 &open;, &seek;或 &read; 引发的 &ioerror; 异常。这里,我们其实不用关心,因为将要做的事就是静静地忽略它然后继续。(记住,&pass; 是一条不做任何事的 &python; 语句。) 这样完全合法,<quote>处理</quote> 一个异常可以明确表示不做任何事。它仍然被认为处理过了,并且处理将正常继续,从 &tryexcept; 块的下一行代码。</para>  
      1074 <para>最后,处理我们的 &ioerror; 异常。它可能是由调用 &open;, &seek; 或 &read; 引发的 &ioerror; 异常。这里,我们其实不用关心,因为将要做的事就是静静地忽略它然后继续。(记住,&pass; 是一条不做任何事的 &python; 语句。) 这样完全合法,<quote>处理</quote> 一个异常可以明确表示不做任何事。它仍然被认为处理过了,并且处理将正常继续,从 &tryexcept; 块的下一行代码。</para>  
    1074 1074 </callout>  
    1075 1075 </calloutlist>  
     
    1078 1078 </section>  
    1079 1079 <section>  
    1080   <title>写文件</title>  
    1081   <para>正如你所期待的, 你也能用与读取文件同样的方式写文件。  有两种基本的文件模式:</para>  
      1080 <title>写入文件</title>  
      1081 <para>正如你所期待的, 你也能用与读取文件同样的方式写入文件。  有两种基本的文件模式:</para>  
    1082 1082 <itemizedlist>  
    1083 1083 <listitem><para>"Append" 模式将数据追加到文件尾。</para></listitem>  
    1084 1084 <listitem><para>"write" 模式将覆盖文件的原有内容。</para></listitem>  
    1085 1085 </itemizedlist>  
    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>  
      1086 <para>如果文件还不存在, 任意一种模式都将自动创建文件, 因此从来不需要任何复杂的逻辑 "如果 log 文件还不存在, 将创建一个新的空文件,正因为如此,你可以第一次就打开它" 。 打开文件并开始写就可以了。</para>  
    1086 1086 <example id="fileinfo.files.writeandappend">  
    1087   <title>写文件</title>  
      1087 <title>写文件</title>  
    1087 1087 <screen>  
    1088 1088 &prompt;<userinput>logfile = open('test.log', 'w')</userinput> <co id="fileinfo.files.5.1"/>  
     
    1101 1101 <calloutlist>  
    1102 1102 <callout arearefs="fileinfo.files.5.1">  
    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>  
      1103 <para>你可以大胆地开始创建任何的新文件 <filename>test.log</filename> 或覆盖现有文件, 为写入目的而打开它。  (第二个参数 <literal>"w"</literal> 的意思是为文件写入而打开。)  是的,它和想象中的一样危险。 我希望你不必关心文件以前的内容, 因为它现在已经不存在了。</para>  
    1103 1103 </callout>  
    1104 1104 <callout arearefs="fileinfo.files.5.2">  
    1105   <para>You can add data to the newly opened file with the &write; method of the file object returned by &open;.</para>  
      1105 <para>你可以使用 &open; 返回的文件对象的 &write; 方法向一个新打开的文件添加数据。</para>  
    1105 1105 </callout>  
    1106 1106 <callout arearefs="fileinfo.files.5.3">  
    1107   <para>&file; is a synonym for &open;.  This one-liner opens the file, reads its contents, and prints them.</para>  
      1107 <para>&file; 是 &open; 的同义语。 它用一行打开文件, 读取内容, 并打印它们。</para>  
    1107 1107 </callout>  
    1108 1108 <callout arearefs="fileinfo.files.5.4">  
    1109   <para>You happen to know that <filename>test.log</filename> exists (since you just finished writing to it), so you can open it and append to it.  (The <literal>"a"</literal> parameter means open the file for appending.)  Actually you could do this even if the file didn't exist, because opening the file for appending will create the file if necessary.  But appending will <emphasis>never</emphasis> harm the existing contents of the file.</para>  
      1109 <para>碰巧你知道 <filename>test.log</filename> 存在 (因为你刚向它写完了数据), 所以你可以打开它并向其追加数据。  (<literal>"a"</literal> 参数的意思是为追加目的打开文件。)  实际上即使文件不存在你也可以这样做, 因为以追加方式打开一文件时, 如果需要的话会创建文件。  但是追加操作 <emphasis>从不</emphasis> 损坏文件的现有内容。</para>  
    1109 1109 </callout>  
    1110 1110 <callout arearefs="fileinfo.files.5.5">  
    1111   <para>As you can see, both the original line you wrote and the second line you appended are now in <filename>test.log</filename>.  Also note that carriage returns are not included.  Since you didn't write them explicitly to the file either time, the file doesn't include them.  You can write a carriage return with the <literal>"\n"</literal> character.  Since you didn't do this, everything you wrote to the file ended up smooshed together on the same line.</para>  
      1111 <para>正如你所看到的, 原来的行和你以追加方式写入的第二行现在都在 <filename>test.log</filename>中了。  同时注意回车符并没包含进来。 因为两次写入文件时都没有明确地写入回车符, 所以文件中没有包含回车符。  你可以用 <literal>"\n"</literal> 写入回车符。  因为你没做这项工作, 所以你写到文件的所有内容都将显示在同一行上。</para>  
    1111 1111 </callout>  
    1112 1112 </calloutlist>  
     
    1120 1120 <title>进一步阅读</title>  
    1121 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>  
      1122 <listitem><para>&effbot; 讨论了 <ulink url="&url_effbot;readline-performance.htm">各种各样读取文件方法</ulink> 的效率和性能。</para></listitem>  
    1122 1122 <listitem><para>&pythonknowledgebase; 回答了 <ulink url="&url_pythonknowledgebase;index.phtml/fid/552">关于文件的常见问题</ulink>。</para></listitem>  
    1123 1123 <listitem><para>&pythonlibraryreference; 总结了 <ulink url="&url_pythonlibraryreference;bltin-file-objects.html">所有文件对象模块</ulink>。</para></listitem>  
     
    1131 1131 <abstract>  
    1132 1132 <title/>  
    1133   <para>与其它大多数语言一样,&python; 也拥有 &for; 循环。你到现在还未曾看到它们的唯一原因就是,&python; 在其它太多的方面表现出色,通常你不需要它们。</para>  
      1133 <para>与其它大多数语言一样,&python; 也拥有 &for; 循环。你到现在还未曾看到它们的唯一原因就是,&python; 在其它太多的方面表现出色,通常你不需要它们。</para>  
    1133 1133 </abstract>  
    1134 1134 <para>其它大多数语言没有象 &python; 一样的强大的 list 数据类型,所以你需要亲自做很多事情,指定开始,结束和步长,来定义一定范围的整数或字符或其它可重复的实体。但是在 &python; 中,&for;  循环简单地在一个列表上循环,与  <link linkend="odbchelper.map">list 理解</link> 的工作方式相同。</para>  
     
    1180 1180 <calloutlist>  
    1181 1181 <callout arearefs="fileinfo.for.3.1">  
    1182   <para>正如你在 <xref linkend="odbchelper.multiassign.range"/> 所看到的, &range; 生成一个整数的 list, [todo]which you then loop through.  我知道它看上去有些奇怪, 但是它对计数循环偶尔 (我只是说 <emphasis>偶尔</emphasis>) 会有用 。</para>  
      1182 <para>正如你在 <xref linkend="odbchelper.multiassign.range"/> 所看到的, &range; 生成一个整数的 list, 通过它来控制循环。  我知道它看上去有些奇怪, 但是它对计数循环偶尔 (我只是说 <emphasis>偶尔</emphasis>) 会有用 。</para>  
    1182 1182 </callout>  
    1183 1183 <callout arearefs="fileinfo.for.3.2">  
    1184   <para>我们从来没这么用过。 这是 &vb;-式的想法。摆脱它吧。 正确遍历 list 的方法是上一个例子所展示的。</para>  
      1184 <para>我们从来没这么用过。 这是 &vb; 的思维风格。摆脱它吧。 正确遍历 list 的方法是上一个例子所展示的。</para>  
    1184 1184 </callout>  
    1185 1185 </calloutlist>  
     
    1216 1216 </callout>  
    1217 1217 <callout arearefs="fileinfo.for.2.3">  
    1218   <para>使用 <link linkend="odbchelper.multiassign">多变量赋值</link> 和 <link linkend="odbchelper.map">list 理解</link>,你可以使用单行语句来替换整个 &for; 循环。在实际的编码中是否这样做只是个人风格问题;我喜欢它是因为,可以使得将一个 dictionary 映射到一个 list,然后将 list 合并成一个字符串这一过程变得清晰。其它的程序员宁愿将其写成一个 &for; 循环。请注意在两种情况下输出是一样的,然而这一版本稍微快一些,因为它只有一条 &print; 语句而不是许多。</para>  
      1218 <para>使用 <link linkend="odbchelper.multiassign">多变量赋值</link> 和 <link linkend="odbchelper.map">list 理解</link>,你可以使用单行语句来替换整个 &for; 循环。在实际的编码中是否这样做只是个人风格问题;我喜欢它是因为,可以使得将一个 dictionary 映射到一个 list,然后将 list 合并成一个字符串,这一过程显得很清晰。其它的程序员宁愿将其写成一个 &for; 循环。请注意在两种情况下输出是一样的,然而这一版本稍微快一些,因为它只有一条 &print; 语句而不是许多。</para>  
    1218 1218 </callout>  
    1219 1219 </calloutlist>  
    1220 1220 </example>  
    1221   <para>现在我们来看看在 <xref linkend="fileinfo" endterm="fileinfo.numberonly"/>介绍的样例程序 &fileinfo_filename; <classname>MP3FileInfo</classname> 中的 &for; 循环 。 </para>  
      1221 <para>现在我们来看看在 <xref linkend="fileinfo" endterm="fileinfo.numberonly"/> 介绍的样例程序 &fileinfo_filename; 中 <classname>MP3FileInfo</classname> 的 &for; 循环 。 </para>  
    1221 1221 <example id="fileinfo.multiassign.for.example">  
    1222 1222 <title>&mp3fileinfo_classname; 中的 &for; 循环</title>  
     
    1273 1273 </callout>  
    1274 1274 <callout arearefs="fileinfo.modules.1.2">  
    1275   <para>&sysmodules; 是一个字典,它包含了从 &python; 开始运行起被导入的所有模块。键字就是模块名,键值就是模块对象。请注意除了你的程序导入的模块外还有其它模块。&python; 在启动时预先装入了一些模块,如果你在一个 &python; &ide; 环境下,&sysmodules; 包含了你在 &ide; 中运行的所有程序所导入的所有模块。</para>  
      1275 <para>&sysmodules; 是一个字典,它包含了从 &python; 开始运行起被导入的所有模块。键字就是模块名,键值就是模块对象。请注意除了你的程序导入的模块外还有其它模块。&python; 在启动时预先装入了一些模块,如果你在一个 &python; &ide; 环境下,&sysmodules; 包含了你在 &ide; 中运行的所有程序所导入的所有模块。</para>  
    1275 1275 </callout>  
    1276 1276 </calloutlist>  
     
    1302 1302 <calloutlist>  
    1303 1303 <callout arearefs="fileinfo.modules.1.3">  
    1304   <para>当导入新的模块,它们加入到 &sysmodules; 中。这就解释了为什么第二次导入相同的模块���非常的快:&python; 已经在 &sysmodules; 中装入和缓冲了,所以第二次导入仅仅对 dictionary 做了一个查询。</para>  
      1304 <para>当导入新的模块,它们加入到 &sysmodules; 中。这就解释了为什么第二次导入相同的模块���非常的快:&python; 已经在 &sysmodules; 中装入和缓冲了,所以第二次导入仅仅对字典做了一个查询。</para>  
    1304 1304 </callout>  
    1305 1305 <callout arearefs="fileinfo.modules.1.4">  
    1306   <para>一旦给出任何以前导入过的模块名(以字符串方式),通过 &sysmodules; dictionary,你可以得到对模块本身的一个引用。</para>  
      1306 <para>一旦给出任何以前导入过的模块名(以字符串方式),通过 &sysmodules; 字典,你可以得到对模块本身的一个引用。</para>  
    1306 1306 </callout>  
    1307 1307 </calloutlist>  
    1308 1308 </example>  
    1309   <para>下面的例子展示了如何使用 <literal>__module__</literal> 类属性[todo] with the &sysmodules; dictionary to get a reference to the module in which a class is defined.</para>  
      1309 <para>下面的例子介绍 &sysmodules;  dictionary 的 <literal>__module__</literal> 属性,可以作为理解已定义类中 <literal>__module__</literal> 属性的参考。</para>  
    1309 1309 <example>  
    1310 1310 <title>&moduleattr; 类属性</title>  
     
    1322 1322 </callout>  
    1323 1323 <callout arearefs="fileinfo.modules.2.2">  
    1324   <para>将它与 &sysmodules; dictionary 复合使用,你可以得到定义了某个类的模块的引用。</para>  
      1324 <para>将它与 &sysmodules; 字典复合使用,你可以得到定义了某个类的模块的引用。</para>  
    1324 1324 </callout>  
    1325 1325 </calloutlist>  
    1326 1326 </example>  
    1327   <para>现在准备好了, 看看 &sysmodules; 在样例程序 <xref linkend="fileinfo" endterm="fileinfo.numberonly"/> 介绍的 &fileinfo_filename; 中是如何使用的。  这个例子显示它的一部分代码。</para>  
      1327 <para>现在准备好了, 看看在样例程序 <xref linkend="fileinfo" endterm="fileinfo.numberonly"/>  &sysmodules; 介绍的 &fileinfo_filename; 中是如何使用的。  这个例子显示它的一部分代码。</para>  
    1327 1327 <example>  
    1328 1328 <title>&fileinfo_filename; 中的 &sysmodules;</title>  
     
    1336 1336 <calloutlist>  
    1337 1337 <callout arearefs="fileinfo.modules.3.1">  
    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>  
      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>  
    1338 1338 </callout>  
    1339 1339 <callout arearefs="fileinfo.modules.3.2">  
     
    1342 1342 </callout>  
    1343 1343 <callout arearefs="fileinfo.modules.3.3">  
    1344   <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>  
      1344 <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>  
    1344 1344 </callout>  
    1345 1345 </calloutlist>  
     
    1357 1357 <abstract>  
    1358 1358 <title/>  
    1359   <para>&ospath; 模块有几个操作文件和目录的函数。 这里, 我们看看如何 操作路径名和列出一个目录的内容。</para>  
      1359 <para>&ospath; 模块有几个操作文件和目录的函数。 这里, 我们看看如何操作路径名和列出一个目录的内容。</para>  
    1359 1359 </abstract>  
    1360 1360 <example id="fileinfo.os.path.join.example">  
     
    1376 1376 </callout>  
    1377 1377 <callout arearefs="fileinfo.os.1.2">  
    1378   <para>&ospath; 的 &join; 函数用一个或多个部分路径名构造成一个路径名。在这个简单的例子中,它只是将字符串进行连接。(请注意在 &windows; 下处理路径名是一个麻烦的事,因为反斜线字符必须被转义。)</para>  
      1378 <para>&ospath; 的 &join; 函数用一个或多个部分路径名构造成一个路径名。在这个简单的例子中,它只是将字符串进行连接。 (请注意在 &windows; 下处理路径名是一个麻烦的事,因为反斜线字符必须被转义。)</para>  
    1378 1378 </callout>  
    1379 1379 <callout arearefs="fileinfo.os.1.3">  
     
    1382 1382 </callout>  
    1383 1383 <callout arearefs="fileinfo.os.1.4">  
    1384   <para><function>expanduser</function>  将对使用 <literal>~</literal> 来表示当前用户根目录的路径名进行扩展。在任何平台上,只要用户拥有一个根目录,它就会有效,象&windows;, &unix;,和 &macosx;; 在 &macos; 上无效。</para>  
      1384 <para><function>expanduser</function>  将对使用 <literal>~</literal> 来表示当前用户根目录的路径名进行扩展。在任何平台上,只要用户拥有一个根目录,它就会有效,象&windows;, &unix; 和 &macosx;, 但在 &macos; 上无效。</para>  
    1384 1384 </callout>  
    1385 1385 <callout arearefs="fileinfo.os.1.5">  
     
    1405 1405 <calloutlist>  
    1406 1406 <callout arearefs="fileinfo.os.2.1">  
    1407   <para>&split;  函数对一个全路径名进行分割,返回一个包含路径和文件名的元组。还记得我说过你可以使用 <link linkend="odbchelper.multiassign">多变量赋值</link> 从一个函数返回多个值吗?对,&split; 就是这样一个函数。</para>  
      1407 <para>&split;  函数对一个全路径名进行分割,返回一个包含路径和文件名的 tuple。还记得我说过你可以使用 <link linkend="odbchelper.multiassign">多变量赋值</link> 从一个函数返回多个值吗?对,&split; 就是这样一个函数。</para>  
    1407 1407 </callout>  
    1408 1408 <callout arearefs="fileinfo.os.2.2">  
    1409   <para>我们将 &split; 函数的返回值赋值给一个两个变量的 tuple。每个变量接收到返回 tuple 相对应的元素值。</para>  
      1409 <para>我们将 &split; 函数的返回值赋值给一个两个变量的 tuple。每个变量接收到返回 tuple 相对应的元素值。</para>  
    1409 1409 </callout>  
    1410 1410 <callout arearefs="fileinfo.os.2.3">  
    1411   <para>第一个变量,<varname>filepath</varname>,接收到从 &split; 返回的元组的第一个元素的值,文件路径。</para>  
      1411 <para>第一个变量,<varname>filepath</varname>,接收到从 &split; 返回 tuple 的第一个元素的值,文件路径。</para>  
    1411 1411 </callout>  
    1412 1412 <callout arearefs="fileinfo.os.2.4">  
    1413   <para>第二个变量,<varname>filename</varname>,接收到从 &split; 返回的元组的第二个元素的值,文件名。</para>  
      1413 <para>第二个变量,<varname>filename</varname>,接收到从 &split; 返回 tuple 的第二个元素的值,文件名。</para>  
    1413 1413 </callout>  
    1414 1414 <callout arearefs="fileinfo.os.2.5">  
    1415   <para>&ospath; 也包含了一个 &splitext; 函数,可以用来对文件名进行分割,并且回一个包含了文件名和文件扩展名的元组。我们使用相同的技术来将它们赋值给独立的变量。</para>  
      1415 <para>&ospath; 也包含了一个 &splitext; 函数,可以用来对文件名进行分割,并且回一个包含了文件名和文件扩展名的 tuple。我们使用相同的技术来将它们赋值给独立的变量。</para>  
    1415 1415 </callout>  
    1416 1416 </calloutlist>  
     
    1445 1445 <calloutlist>  
    1446 1446 <callout arearefs="fileinfo.os.3.1">  
    1447   <para>&listdir; 函数接收一个路径名,它返回那个目录的内容的一个列表。</para>  
      1447 <para>&listdir; 函数接收一个路径名,它返回那个目录的内容的一个 list。</para>  
    1447 1447 </callout>  
    1448 1448 <callout arearefs="fileinfo.os.3.2">  
     
    1486 1486 <!--<title>When To Use the &os; Module</title>-->  
    1487 1487 <title/>  
    1488   <para>只要有可能,你应该使用在 &os; 和 &ospath; 中的函数进行文件,目录,和路径的操作。这些模块是对平台相关模块的封装模块,所以象 <function>os.path.split</function> 这样的函数可以工作在&unix;, &windows;,&macos; 和 &python; 所支持的任一种平台上。</para>  
      1488 <para>只要有可能,你应该使用在 &os; 和 &ospath; 中的函数进行文件,目录,和路径的操作。这些模块是对平台相关模块的封装模块,所以象 <function>os.path.split</function> 这样的函数可以工作在 &unix;, &windows;, &macos; 和 &python; 所支持的任一种平台上。</para>  
    1488 1488 </note>  
    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>  
      1489 <para>还有一种获得 directory 内容的方法。  它非常强大, 它使用了一些你在命令行上工作时可能已经熟悉的通配符。</para>  
    1489 1489 <example id="fileinfo.os.glob.example">  
    1490 1490 <title>Listing Directories with &glob;</title>  
     
    1511 1511 <calloutlist>  
    1512 1512 <callout arearefs="fileinfo.os.4.1">  
    1513   <para>As you saw earlier, <function>os.listdir</function> simply takes a directory path and lists all files and directories in that directory.</para>  
      1513 <para>正如你前面看到的, <function>os.listdir</function> 简单的取出一个目录路径, 目录中的所有文件和子目录。</para>  
    1513 1513 </callout>  
    1514 1514 <callout arearefs="fileinfo.os.4.2">  
    1515   <para>The &glob; module, on the other hand, takes a wildcard and returns the full path of all files and directories matching the wildcard.  Here the wildcard is a directory path plus "*.mp3", which will match all <filename>.mp3</filename> files.  Note that each element of the returned list already includes the full path of the file.</para>  
      1515 <para>&glob; 模块, 另一方面, 选取一个通配符并且返回文件的或目录的完整路径与之匹配。  这个通配符是一个目录路径加上 "*.mp3", 它将匹配所有的 <filename>.mp3</filename> 文件。  注意返回列表的每一个元素已经包含了文件的完整路径。</para>  
    1515 1515 </callout>  
    1516 1516 <callout arearefs="fileinfo.os.4.3">  
    1517   <para>If you want to find all the files in a specific directory that start with "s" and end with ".mp3", you can do that too.</para>  
      1517 <para>如果你要查找指定目录中所有以 "s" 开头并以 ".mp3" 结尾的文件, 也可以这么做。</para>  
    1517 1517 </callout>  
    1518 1518 <callout arearefs="fileinfo.os.4.4">  
    1519   <para>Now consider this scenario: you have a <filename>music</filename> directory, with several subdirectories within it, with <filename>.mp3</filename> files within each subdirectory.  You can get a list of all of those with a single call to &glob;, by using two wildcards at once.  One wildcard is the <literal>"*.mp3"</literal> (to match <filename>.mp3</filename> files), and one wildcard is <emphasis>within the directory path itself</emphasis>, to match any subdirectory within <filename>c:\music</filename>.  That's a crazy amount of power packed into one deceptively simple-looking function!</para>  
      1519 <para>现在考查这种情况: 你有一个 <filename>music</filename> 目录, 它包含几个子目录,  子目录中包含一些 <filename>.mp3</filename> 文件。 你可以用两个通配符仅仅调用 &glob; 一次立刻获得所有这些文件的一个 list。  一个通配符是 <literal>"*.mp3"</literal> (用于匹配 <filename>.mp3</filename> 文件), 另一个通配符是 <emphasis>子目录名本身</emphasis>, 用于匹配 <filename>c:\music</filename> 中的所有子目录。 这看上去很简单, 但他蕴含了强大的功能。</para>  
    1519 1519 </callout>  
    1520 1520 </calloutlist>  
     
    1551 1551 <calloutlist>  
    1552 1552 <callout arearefs="fileinfo.alltogether.1.1">  
    1553   <para>&listdirectory; 是整个模块主要的引吸之处。它接收一个字典 (在我的例子中如 <filename class="directory">c:\music\_singles\</filename>) 和一个感兴趣的文件扩展名列表 (如 <literal>['.mp3']</literal>),接着它返回一个类实例的 list ,这些类实例的行为象字典,包含了在目录中每个感兴趣文件的元数据。并且实现起来只用了几行直观的代码。</para>  
      1553 <para>&listdirectory; 是整个模块主要的引吸之处。它接收一个 dictionary (在我的例子中如 <filename class="directory">c:\music\_singles\</filename>) 和一个感兴趣的文件扩展名列表 (如 <literal>['.mp3']</literal>),接着它返回一个类实例的 list ,这些类实例的行为象 dictionary,包含了在目录中每个感兴趣文件的元数据。并且实现起来只用了几行直观的代码。</para>  
    1553 1553 </callout>  
    1554 1554 <callout arearefs="fileinfo.alltogether.1.2">  
     
    1566 1566 </callout>  
    1567 1567 <callout arearefs="fileinfo.alltogether.1.6">  
    1568   <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>  
      1568 <para>对每个属于我们 <quote>感兴趣文件</quote> 列表 (<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>  
    1568 1568 </callout>  
    1569 1569 </calloutlist>  
    1639 1639 <itemizedlist>  
    1640 1640 <listitem><para>使用 <link linkend="fileinfo.exception">&tryexcept;</link> 来捕捉异常</para></listitem>  
    1641   <listitem><para>使用 <link linkend="fileinfo.files.incode">&tryfinally;</link>来保护额外的资源</para></listitem>  
      1641 <listitem><para>使用 <link linkend="fileinfo.files.incode">&tryfinally;</link> 来保护额外的资源</para></listitem>  
    1641 1641 <listitem><para>读取 <link linkend="fileinfo.files">文件</link></para></listitem>  
    1642 1642 <listitem><para>在一个 <link linkend="fileinfo.multiassign.for.example">&for; 循环</link> 中一次赋多个值</para></listitem>