Changeset 798

Show
Ignore:
Timestamp:
Tue Feb 28 05:10:51 2006
Author:
osmond
Message:

初步整理了[对象和面向对象]一章

Files:

Legend:

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

    r269 r798  
    9 9 </abstract>  
    10 10 <section id="fileinfo.divein">  
    11   <title>���触</title>  
      11 <title>���览</title>  
    11 11 <abstract>  
    12 12 <title/>  
     
    262 262 </callout>  
    263 263 <callout arearefs="fileinfo.class.2.5">  
    264   <para>&init; methods can take any number of arguments, and just like functions, the arguments can be defined with default values, making them optional to the caller.  In this case, <varname>filename</varname> has a default value of &none;, which is the &python; null value.</para>  
      264 <para>&init; 方法可以接受任意个数的参数,就象函数一样,参数可以用缺省值定义,可以设置成对于调用者可选。在本例中, <varname>filename</varname> 有一个缺省值 &none;,即 &python; 的空值。</para>  
    264 264 </callout>  
    265 265 </calloutlist>  
     
    376 376 <section id="fileinfo.userdict">  
    377 377 <?dbhtml filename="object_oriented_framework/userdict.html"?>  
    378   <title>Exploring &userdict_classname;: A Wrapper Class</title>  
      378 <title>探索 &userdict_classname;: 一个封装类</title>  
    378 378 <abstract>  
    379 379 <title/>  
    380   <para>As you've seen, &fileinfo_classname; is a class that acts like a dictionary.  To explore this further, let's look at the &userdict_classname; class in the &userdict; module, which is the ancestor of the &fileinfo_classname; class.  This is nothing special; the class is written in &python; and stored in a <literal>.py</literal> file, just like any other &python; code.  In particular, it's stored in the <filename class="directory">lib</filename> directory in your &python; installation.</para>  
      380 <para>如你所见, &fileinfo_classname; 是一个象字典一样动作的类。为了进一步揭示这一点,让我们看一看在 &userdict; 模块中的 &userdict_classname; 类,它是我们的 &fileinfo_classname; 类的父类。没有什么特别的,类是用 &python; 写的,并且保存在一个 <literal>.py</literal> 文件里,就象我们的代码。特别的,它保存在你的 &python; 安装目录的  <filename class="directory">lib</filename>  目录下。</para>  
    380 380 </abstract>  
    381 381 <tip id="tip.locate">  
    382 382 <!--<title>Open Modules Quickly</title>-->  
    383 383 <title/>  
    384   <para>In the &activepython; &ide; on &windows;, you can quickly open any module in your library path by selecting  
      384 <para>在 &windows; 下的 &activepython; &ide; 中,你可以快速打开在你的库路径中的任何模块,使用  
    384 384 <menuchoice>  
    385 385 <shortcut>  
     
    394 394 <guimenu>File</guimenu>  
    395 395 <guimenuitem><accel>L</accel>ocate...</guimenuitem>  
    396   </menuchoice>.</para>  
      396 </menuchoice></para>  
    396 396 </tip>  
    397 397 <example id="fileinfo.userdict.init.example">  
    398   <title>Defining the &userdict_classname; Class</title>  
      398 <title>定义 &userdict_classname; 类</title>  
    398 398 <programlisting>  
    399 399 &userdict_class; <co id="fileinfo.userdict.1.1"/>  
     
    406 406 <calloutlist>  
    407 407 <callout arearefs="fileinfo.userdict.1.1">  
    408   <para>Note that &userdict_classname; is a base class, not inherited from any other class.</para>  
      408 <para>注意 &userdict_classname; 是一个基类,不是从任何其他类继承而来。</para>  
    408 408 </callout>  
    409 409 <callout arearefs="fileinfo.userdict.1.2">  
    410   <para>This is the &init; method that you <link linkend="fileinfo.class.example">overrode in the &fileinfo_classname; class</link>.  Note that the argument list in this ancestor class is different than the descendant.  That's okay; each subclass can have its own set of arguments, as long as it calls the ancestor with the correct arguments.  Here the ancestor class has a way to define initial values (by passing a dictionary in the <varname>dict</varname> argument) which the &fileinfo_classname; does not use.</para>  
      410 <para>这就是我们 <link linkend="fileinfo.class.example">在 &fileinfo_classname;  类中进行了覆盖</link> 的 &init;  方法。注意这个父类的参数列表与子类不同。很好,每个子类可以拥有自已的参数集,只要使用正确的参数调用父类就可以了。这里父类有一个定义初始值的方法(通过在 <varname>dict</varname> 参数中传入一个字典),这一方法我们的 &fileinfo_classname; 没有用上。</para>  
    410 410 </callout>  
    411 411 <callout arearefs="fileinfo.userdict.1.3">  
    412   <para>&python; supports data attributes (called <quote>instance variables</quote> in &java; and &powerbuilder;, and <quote>member variables</quote> in &cpp;).  Data attributes are pieces of data held by a specific instance of a class.  In this case, each instance of &userdict_classname; will have a data attribute <varname>data</varname>.  To reference this attribute from code outside the class, you qualify it with the instance name, <literal><replaceable>instance</replaceable>.data</literal>, in the same way that you qualify a function with its module name.  To reference a data attribute from within the class, you use &self; as the qualifier.  By convention, all data attributes are initialized to reasonable values in the &init; method.  However, this is not required, since data attributes, like local variables, <link linkend="odbchelper.vardef">spring into existence</link> when they are first assigned a value.</para>  
      412 <para>&python; 支持数据属性(在 &java; 和 &powerbuilder; 中叫做 <quote>实例变量</quote>,在 &cpp; 中叫 <quote>数据成员</quote>),它是由某个特定的类实例所拥有的数据。在本例中,每个 &userdict_classname; 实例将拥有一个 <varname>data</varname> 数据属性。要从类外的代码引用这个属性,需要用实例的名字限定它,<literal><replaceable>instance</replaceable>.data</literal>,限定的方法与你用模块的名字来限定函数一样。要在类的内部引用一个数据属性,我们使用 &self; 作为限定符。习惯上,所有的数据属性都在 &init;  方法中初始化为有意义的值。然而,这并不是必须的,因为数据属性,象局部变量一样,当你首次赋给它值的时候<link linkend="odbchelper.vardef">突然产生</link>。</para>  
    412 412 </callout>  
    413 413 <callout arearefs="fileinfo.userdict.1.4">  
    414   <para>The &update; method is a dictionary duplicator: it copies all the keys and values from one dictionary to another.  This does <emphasis>not</emphasis> clear the target dictionary first; if the target dictionary already has some keys, the ones from the source dictionary will be overwritten, but others will be left untouched.  Think of &update; as a merge function, not a copy function.</para>  
      414 <para>[todo]The &update; method is a dictionary duplicator: it copies all the keys and values from one dictionary to another.  This does <emphasis>not</emphasis> clear the target dictionary first; if the target dictionary already has some keys, the ones from the source dictionary will be overwritten, but others will be left untouched.  Think of &update; as a merge function, not a copy function.</para>  
    414 414 </callout>  
    415 415 <callout arearefs="fileinfo.userdict.1.5">  
    416   <para>This is a syntax you may not have seen before (I haven't used it in the examples in this book).  It's an &if; statement, but instead of having an indented block starting on the next line, there is just a single statement on the same line, after the colon.  This is perfectly legal syntax, which is just a shortcut you can use when you have only one statement in a block.  (It's like specifying a single statement without braces in &cpp;.)  You can use this syntax, or you can have indented code on subsequent lines, but you can't do both for the same block.</para>  
      416 <para>这个语法你可能以前没看过(我还没有在这本书中的例子中用过它)。这是一条 &if; 语句,但是没有在下一行有一个缩近块,而只是在冒号后面,在同一行上有单条语句。这完全是合法的,它只是当你在一个块中仅有一条语句时的一个简写。(它就象在 &cpp; 中没有用大括号包括的单行语句。) 你可以用这种语法,或者可以在后面的行拥有缩近代码,但是不能对同一个块同时用两种方式。</para>  
    416 416 </callout>  
    417 417 </calloutlist>  
     
    424 424 <note id="compare.overloading" role="compare" vendor="java">  
    425 425 <title>&python; &vs; &java;: Function Overloading</title>  
    426   <para>&java; and &powerbuilder; support function overloading by argument list, &ie; one class can have multiple methods with the same name but a different number of arguments, or arguments of different types.  Other languages (most notably &plsql;) even support function overloading by argument name; &ie; one class can have multiple methods with the same name and the same number of arguments of the same type but different argument names.  &python; supports neither of these; it has no form of function overloading whatsoever.  Methods are defined solely by their name, and there can be only one method per class with a given name.  So if a descendant class has an &init; method, it <emphasis>always</emphasis> overrides the ancestor &init; method, even if the descendant defines it with a different argument list.  And the same rule applies to any other method.</para>  
      426 <para>&java;  和 &powerbuilder; 支持通过参数列表的重载,&ie; 一个类可以有同名的多个方法,但这些方法或者是参数个数不同,或参数的类型不同。其它语言(最明显如 &plsql;)甚至支持通过参数名的重载,&ie; 一个类可以有同名的多个方法,这些方法有相同类型,相同个数的参数,但参数名不同。&python; 两种都不支持,总之是没有任何形式的函数重载。一个 &init; 方法就是一个 &init; 方法,不管它有什么样的参数。每个类只能有一个 &init; 方法,并且如果一个子类拥有一个 &init; 方法,它 <emphasis>总是</emphasis> 覆盖父类的 &init; 方法,甚至子类可以用不同的参数列表来定义它。</para>  
    426 426 </note>  
    427 427 <note id="fileinfo.derivedclasses">  
    428 428 <!--<title>Guido on Derived Classes</title>-->  
    429 429 <title/>  
    430   <para>Guido, the original author of &python;, explains method overriding this way: "Derived classes may override methods of their base classes. Because methods have no special privileges when calling other methods of the same object, a method of a base class that calls another method defined in the same base class, may in fact end up calling a method of a derived class that overrides it. (For &cpp; programmers: all methods in &python; are effectively virtual.)"  If that doesn't make sense to you (it confuses the hell out of me), feel free to ignore it.  I just thought I'd pass it along.</para>  
      430 <para>[todo]Guido, the original author of &python;, explains method overriding this way: "Derived classes may override methods of their base classes. Because methods have no special privileges when calling other methods of the same object, a method of a base class that calls another method defined in the same base class, may in fact end up calling a method of a derived class that overrides it. (For &cpp; programmers: all methods in &python; are effectively virtual.)"  If that doesn't make sense to you (it confuses the hell out of me), feel free to ignore it.  I just thought I'd pass it along.</para>  
    430 430 </note>  
    431 431 <caution id="note.dataattributes">  
    432 432 <!--<title>Always Initialize Data Attributes</title>-->  
    433 433 <title/>  
    434   <para>Always assign an initial value to all of an instance's data attributes in the &init; method.  It will save you hours of debugging later, tracking down <classname>AttributeError</classname> exceptions because you're referencing uninitialized (and therefore non-existent) attributes.</para>  
      434 <para>应该总是在 &init; 方法中给所有实例的数据属性赋予一个初始值。这样做将会节省你在后面调试的时间,  
      435 [todo]Always assign an initial value to all of an instance's data attributes in the &init; method.  It will save you hours of debugging later,  
      436 tracking down <classname>AttributeError</classname> exceptions because you're referencing uninitialized (and therefore non-existent) attributes.</para>  
    435 437 </caution>  
    436 438 <example id="fileinfo.userdict.normalmethods">  
    437   <title>&userdict_classname; Normal Methods</title>  
      439 <title>&userdict_classname; 常规方法</title>  
    437 439 <programlisting>  
    438 440 &userdict_clear; <co id="fileinfo.userdict.2.1"/>  
     
    451 453 <calloutlist>  
    452 454 <callout arearefs="fileinfo.userdict.2.1">  
    453   <para>&clear; is a normal class method; it is publicly available to be called by anyone at any time.  Notice that &clear;, like all class methods, has &self; as its first argument.  (Remember that you don't include &self; when you call the method; it's something that &python; adds for you.)  Also note the basic technique of this wrapper class: store a real dictionary (<varname>data</varname>) as a data attribute, define all the methods that a real dictionary has, and have each class method redirect to the corresponding method on the real dictionary.  (In case you'd forgotten, a dictionary's &clear; method <link linkend="odbchelper.dict.del">deletes all of its keys</link> and their associated values.)</para>  
      455 <para>&clear; 是一个普通的类方法,可以在任何时候被任何人公开调用。注意,&clear; 象所有的类方法一样(常规的或专用的),使用  &self;  作为它的第一个参数。(记住,当你调用方法时,不用包括 &self;;这件事是 &python; 替你做的。) 还应注意这个封装类的基本技术:将一个真正的字典 (<varname>data</varname>)  作为数据属性保存起来,定义所有真正字典有拥有的方法,并且将每个类方法重定向到真正字典上的相应方法。(一旦你已经忘记了,字典的 &clear; 方法 <link linkend="odbchelper.dict.del">删除它的所有关键字</link> 和关键字相应的值。)</para>  
    453 455 </callout>  
    454 456 <callout arearefs="fileinfo.userdict.2.2">  
    455   <para>The &copy; method of a real dictionary returns a new dictionary that is an exact duplicate of the original (all the same key-value pairs).  But &userdict_classname; can't simply redirect to <function>self.data.copy</function>, because that method returns a real dictionary, and what you want is to return a new instance that is the same class as &self;.</para>  
      457 <para>真正字典的 &copy;  方法会返回一个新的字典,它是原始字典的原样的复制(所有的键-值对都相同)。但是 &userdict_classname; 不能简单地重定向到 <function>self.data.copy</function>,因为那个方法返回一个真正的字典,而我们想要的是返回同一个类的一个新的实例,就象是 &self;。</para>  
    455 457 </callout>  
    456 458 <callout arearefs="fileinfo.userdict.2.3">  
    457   <para>You use the &classattr; attribute to see if &self; is a &userdict_classname;; if so, you're golden, because you know how to copy a &userdict_classname;: just create a new &userdict_classname; and give it the real dictionary that you've squirreled away in <varname>self.data</varname>.  Then you immediately return the new &userdict_classname; you don't even get to the <literal>import copy</literal> on the next line.</para>  
      459 <para>我们使用 &classattr; 属性来查看是否 &self; 是一个 &userdict_classname;,如果是,太好了,因为我们知道如何拷贝一个 &userdict_classname;:只要创建一个新的 &userdict_classname; ,并传给它真正的字典,这个字典已经存放在 <varname>self.data</varname> 中了。[todo] Then you immediately return the new &userdict_classname; you don't even get to the <literal>import copy</literal> on the next line.</para>  
    457 459 </callout>  
    458 460 <callout arearefs="fileinfo.userdict.2.4">  
    459   <para>If <literal>&self;.&classattr;</literal> is not &userdict_classname;, then &self; must be some subclass of &userdict_classname; (like maybe &fileinfo_classname;), in which case life gets trickier.  &userdict_classname; doesn't know how to make an exact copy of one of its descendants; there could, for instance, be other data attributes defined in the subclass, so you would need to iterate through them and make sure to copy all of them.  Luckily, &python; comes with a module to do exactly this, and it's called &copy;.  I won't go into the details here (though it's a wicked cool module, if you're ever inclined to dive into it on your own).  Suffice it to say that &copy; can copy arbitrary &python; objects, and that's how you're using it here.</para>  
      461 <para>如果 <literal>&self;.&classattr;</literal> 不是 &userdict_classname;,那么 &self; 一定是 &userdict_classname; 的某个子类(如可能为 &fileinfo_classname;),生活总是存在意外。 &userdict_classname;  不知道如何生成它的子类的一个原样的拷贝,例如,有可能在子类中定义了其它的数据属性,所以我们只能完全复制它们,确定拷贝了它们的全部内容。幸运的是,&python; 带了一个模块可以正确地完成这件事,它叫做 &copy;。在这里我不想深入细节(然而它是一个绝对酷的模块,是否你想到要自已研究它了呢?)。说 &copy; 能够拷贝任何 &python; 对象就够了,这就是为什么我们在这里用它的原因。</para>  
    459 461 </callout>  
    460 462 <callout arearefs="fileinfo.userdict.2.5">  
    461   <para>The rest of the methods are straightforward, redirecting the calls to the built-in methods on <varname>self.data</varname>.</para>  
      463 <para>其余的方法是直截了当的重定向到 <varname>self.data</varname> 的内置函数上。</para>  
    461 463 </callout>  
    462 464 </calloutlist>  
    463 465 </example>  
    464   <note>  
      466 <note>[todo]  
    464 466 <title>Historical Note</title>  
    465 467 <para>In versions of &python; prior to 2.2, you could not directly subclass built-in datatypes like strings, lists, and dictionaries.  To compensate for this, &python; comes with wrapper classes that mimic the behavior of these built-in datatypes: <classname>UserString</classname>, <classname>UserList</classname>, and &userdict_classname;.  Using a combination of normal and special methods, the &userdict_classname; class does an excellent imitation of a dictionary.  In &python; 2.2 and later, you can inherit classes directly from built-in datatypes like &dict;.  An example of this is given in the examples that come with this book, in <filename>fileinfo_fromdict.py</filename>.</para>  
     
    490 492 </example>  
    491 493 <itemizedlist role="furtherreading">  
    492   <title>Further Reading on &userdict;</title>  
    493   <listitem><para>&pythonlibraryreference; documents the <ulink url="&url_pythonlibraryreference;module-UserDict.html">&userdict; module</ulink> and the <ulink url="&url_pythonlibraryreference;module-copy.html">&copy; module</ulink>.</para></listitem>  
      494 <title>进一步阅读</title>  
      495 <listitem><para>&pythonlibraryreference; 提供了 <ulink url="&url_pythonlibraryreference;module-UserDict.html">&userdict; 模块</ulink> 和 <ulink url="&url_pythonlibraryreference;module-copy.html">&copy; 模块</ulink>的文档。</para></listitem>  
    494 496 </itemizedlist>  
    495 497 </section>  
    496 498 <section id="fileinfo.specialmethods">  
    497 499 <?dbhtml filename="object_oriented_framework/special_class_methods.html"?>  
    498   <title>Special Class Methods</title>  
      500 <title>专用类方法</title>  
    498 500 <abstract>  
    499 501 <title/>  
    500   <para>In addition to normal class methods, there are a number of special methods that &python; classes can define.  Instead of being called directly by your code (like normal methods), special methods are called for you by &python; in particular circumstances or when specific syntax is used.</para>  
      502 <para>除了普通的类方法,还有一些对于 &python; 类可以定义的专用方法。专用方法是在特殊情况下或当使用特别语法时由 &python; 替你调用的,而不是在代码中直接调用(象普通的方法那样)。</para>  
    500 502 </abstract>  
    501   <para>As you saw in the <link linkend="fileinfo.userdict">previous section</link>, normal methods go a long way towards wrapping a dictionary in a class.  But normal methods alone are not enough, because there are a lot of things you can do with dictionaries besides call methods on them.  For starters, you can <link linkend="odbchelper.dict.define">get</link> and <link linkend="odbchelper.dict.modify">set</link> items with a syntax that doesn't include explicitly invoking methods.  This is where special class methods come in: they provide a way to map non-method-calling syntax into method calls.</para>  
      503 <para>就象你在 <link linkend="fileinfo.userdict">上一节</link> 所看到的,普通的方法对在类中封装字典很有帮助。但是只有普通方法是不够的,因为除了对字典调用方法之外,还有很多事情可以做的。例如,你可以通过一种没有包括显式方法调用的语法来 <link linkend="odbchelper.dict.define">获得</link> 和 <link linkend="odbchelper.dict.modify">设置</link> 数据项。这就是专用方法产生的原因:它们提供了一种方法,可以将非方法调用语法映射到方法调用上。</para>  
    501 503 <section>  
    502   <title>Getting and Setting Items</title>  
      504 <title>获得和设置数据项</title>  
    502 504 <example>  
    503   <title>The &getitem; Special Method</title>  
      505 <title>&getitem; 专用方法</title>  
    503 505 <programlisting>  
    504 506 &userdict_getitem;</programlisting>  
     
    517 519 <calloutlist>  
    518 520 <callout arearefs="fileinfo.specialmethods.1.1">  
    519   <para>The &getitem; special method looks simple enough.  Like the normal methods &clear;, &keys;, and &values;, it just redirects to the dictionary to return its value.  But how does it get called?  Well, you can call &getitem; directly, but in practice you wouldn't actually do that; I'm just doing it here to show you how it works.  The right way to use &getitem; is to get &python; to call it for you.</para>  
      521 <para>&getitem; 专用方法很简单。象普通的方法 &clear;,&keys;和 &values;一样,它只是重定向到字典,返回字典的值。但是怎么调用它呢?哦,你可以直接调用  &getitem;,但是在实际中你其实不会那样做:我在这里执行它只是要告诉你它是如何工作的。正确地使用  &getitem; 的方法是让 &python; 来替你调用。</para>  
    519 521 </callout>  
    520 522 <callout arearefs="fileinfo.specialmethods.1.2">  
    521   <para>This looks just like the syntax you would use to <link linkend="odbchelper.dict.define">get a dictionary value</link>, and in fact it returns the value you would expect.  But here's the missing link: under the covers, &python; has converted this syntax to the method call <literal>f.__getitem__("name")</literal>.  That's why &getitem; is a special class method; not only can you call it yourself, you can get &python; to call it for you by using the right syntax.</para>  
      523 <para>这个看上去就象你用来 <link linkend="odbchelper.dict.define">得到一个字典值</link> 的语法,事实上它返回你期望的值。下面是隐藏起来的一个环节:暗地里,&python; 已经将这个语法转化为 <literal>f.__getitem__("name")</literal> 的方法调用。这就是为什么 &getitem; 是一个专用类方法的原因,不仅仅是你可以自已调用它,还可以通过使用正确的语法让 &python; 来替你调用。</para>  
    521 523 </callout>  
    522 524 </calloutlist>  
    523 525 </example>  
    524   <para>Of course, &python; has a &setitem; special method to go along with &getitem;, as shown in the next example.</para>  
      526 <para>当然, &python; 有一个与 &getitem; 类似的 &setitem; 专用方法, 参见下面的例子。</para>  
    524 526 <example id="fileinfo.specialmethods.setitem.example">  
    525   <title>The &setitem; Special Method</title>  
      527 <title>&setitem; 专用方法</title>  
    525 527 <programlisting>  
    526 528 &userdict_setitem;</programlisting>  
     
    539 541 <calloutlist>  
    540 542 <callout arearefs="fileinfo.specialmethods.2.1">  
    541   <para>Like the &getitem; method, &setitem; simply redirects to the real dictionary <varname>self.data</varname> to do its work.  And like &getitem;, you wouldn't ordinarily call it directly like this; &python; calls &setitem; for you when you use the right syntax.</para>  
      543 <para>与 &getitem; 方法一样,&setitem; 简单地重定向到真正的字典 <varname>self.data</varname> ,让它来进行工作。并且象 &getitem; 一样,通常你不会直接调用它,当你使用了正确的语法,&python; 会替你调用 &setitem; 。</para>  
    541 543 </callout>  
    542 544 <callout arearefs="fileinfo.specialmethods.2.2">  
    543   <para>This looks like regular dictionary syntax, except of course that <varname>f</varname> is really a class that's trying very hard to masquerade as a dictionary, and &setitem; is an essential part of that masquerade.  This line of code actually calls <literal>f.__setitem__("genre", 32)</literal> under the covers.</para>  
      545 <para>这个看上去象正常的字典语法,当然除了 <varname>f</varname> 实际上是一个类,它尽可能地打扮成一个字典,并且 &setitem; 是打扮的一个重点。这行代码实际上暗地里调用了 <literal>f.__setitem__("genre", 32)</literal>。</para>  
    543 545 </callout>  
    544 546 </calloutlist>  
    545 547 </example>  
    546   <para>&setitem; is a special class method because it gets called for you, but it's still a class method.  Just as easily as the &setitem; method was defined in &userdict_classname;, you can redefine it in the descendant class to override the ancestor method.  This allows you to define classes that act like dictionaries in some ways but define their own behavior above and beyond the built-in dictionary.</para>  
    547   <para>This concept is the basis of the entire framework you're studying in this chapter.  Each file type can have a handler class that knows how to get metadata from a particular type of file.  Once some attributes (like the file's name and location) are known, the handler class knows how to derive other attributes automatically.  This is done by overriding the &setitem; method, checking for particular keys, and adding additional processing when they are found.</para>  
    548   <para>For example, &mp3fileinfo_classname; is a descendant of &fileinfo_classname;.  When an &mp3fileinfo_classname;'s <literal>name</literal> is set, it doesn't just set the <literal>name</literal> key (like the ancestor &fileinfo_classname; does); it also looks in the file itself for &mp3; tags and populates a whole set of keys.  The next example shows how this works.</para>  
      548 <para>&setitem;  是一个专用类方法,因为它可以让 &python; 来替你调用,但是它仍然是一个类方法。就象在 &userdict_classname; 中定义 &setitem;  方法一样容易,我们可以在子类中重新定义它,对父类的方法进行覆盖。这就允许我们定义出在某些方面象字典一样动作的类,但是可以定义它自已的行为,超过和超出内置的字典。</para>  
      549 <para>这个概念是本章中我们正在学习的整个框架的基础。每个文件类型可以拥有一个处理器类,这些类知道如何从一个特殊的文类型得到元数据。一但知道了某些属性(象文件名和位置),处理器类就知道如何自动地得到其它的属性。它的实现是通过覆盖 &setitem; 方法,检查特别的关键字,然后当找到后加入额外的处理。</para>  
      550 <para>例如,&mp3fileinfo_classname; 是 &fileinfo_classname; 的子类。在设置了一个 &mp3fileinfo_classname; 类的 <literal>name</literal> 时,并不只是设置 <literal>name</literal> 关键字(象父类 &fileinfo_classname; 所做的),它还要在文件自身内进行搜索 &mp3; 的标记然后填充一整套关键字集合。 下面的例子将展示其如何工作。</para>  
    549 551 <example>  
    550   <title>Overriding &setitem; in &mp3fileinfo_classname;</title>  
      552 <title>在 &mp3fileinfo_classname; 中覆盖 &setitem;</title>  
    550 552 <programlisting>  
    551 553 &fileinfo_mp3setitemdef;         <co id="fileinfo.specialmethods.3.1"/>  
     
    558 560 <calloutlist>  
    559 561 <callout arearefs="fileinfo.specialmethods.3.1">  
    560   <para>Notice that this &setitem; method is defined exactly the same way as the ancestor method.  This is important, since &python; will be calling the method for you, and it expects it to be defined with a certain number of arguments.  (Technically speaking, the names of the arguments don't matter; only the number of arguments is important.)</para>  
      562 <para>注意我们的 &setitem; 方法严格按照父类方法相同的形式进行定义。这一点很重要,因为 &python; 将替你执行方法,则它希望这个函数用确定个数的参数进行定义。 (从技术上说,参数的名字没有关系,只是个数。)</para>  
    560 562 </callout>  
    561 563 <callout arearefs="fileinfo.specialmethods.3.2">  
    562   <para>Here's the crux of the entire &mp3fileinfo_classname; class: if you're assigning a value to the <literal>name</literal> key, you want to do something extra.</para>  
      564 <para>这里就是整个 &mp3fileinfo_classname; 类的难点:如果给 <literal>name</literal> 关键字赋一个值,我们还想做些额外的事情。</para>  
    562 564 </callout>  
    563 565 <callout arearefs="fileinfo.specialmethods.3.3">  
    564   <para>The extra processing you do for <literal>name</literal>s is encapsulated in the &fileinfo_parse; method.  This is another class method defined in &mp3fileinfo_classname;, and when you call it, you qualify it with <varname>self</varname>.  Just calling <function>__parse</function> would look for a normal function defined outside the class, which is not what you want.  Calling <function>self.__parse</function> will look for a class method defined within the class.  This isn't anything new; you reference <link linkend="fileinfo.userdict.normalmethods">data attributes</link> the same way.</para>  
      566 <para>我们对 <literal>name</literal> 所做的额外处理封装在了 &fileinfo_parse; 方法中。这是定义在 &mp3fileinfo_classname; 中的另一个类方法,则当我们调用它时,我们用 <varname>self</varname> 对其限定。仅是调用 <function>__parse</function> 将只会看成定义在类外的普通方法,调用 <function>self.__parse</function> 将会看成定义在类中的一个类方法。这不是什么新东西,你用同样的方法来引用 <link linkend="fileinfo.userdict.normalmethods">数据属性</link>。</para>  
    564 566 </callout>  
    565 567 <callout arearefs="fileinfo.specialmethods.3.4">  
    566   <para>After doing this extra processing, you want to call the ancestor method.  Remember that this is never done for you in &python;; you must do it manually.  Note that you're calling the immediate ancestor, &fileinfo_classname;, even though it doesn't have a &setitem; method.  That's okay, because &python; will walk up the ancestor tree until it finds a class with the method you're calling, so this line of code will eventually find and call the &setitem; defined in &userdict_classname;.</para>  
      568 <para>在做完我们额外的处理之后,我们需要调用父类的方法。记住,在 &python; 中不会自动为你完成,需手工执行。注意,我们在调用直接父类, &fileinfo_classname;,尽管它没有一个 &setitem; 方法。没问题,因为 &python; 将会沿着父类树走,直到它找到一个有着我们正在调用方法的类,所以这行代码最终会找到并且调用定义在 &userdict_classname; 中的 &setitem;。</para>  
    566 568 </callout>  
    567 569 </calloutlist>  
     
    574 576 <!--<title>Calling Other Class Methods</title>-->  
    575 577 <title/>  
    576   <para>When accessing data attributes within a class, you need to qualify the attribute name: <literal>self.<replaceable>attribute</replaceable></literal>.  When calling other methods within a class, you need to qualify the method name: <literal>self.<replaceable>method</replaceable></literal>.</para>  
      578 <para>当在一个类中存取数据属性时,你需要限定属性名:<literal>self.<replaceable>attribute</replaceable></literal>。当调用类中的其它方法时,你属要限定方法名:<literal>self.<replaceable>method</replaceable></literal>。</para>  
    576 578 </note>  
    577 579 <example id="fileinfo.specialmethods.setname">  
    578   <title>Setting an &mp3fileinfo_classname;'s <literal>name</literal></title>  
      580 <title>设置 &mp3fileinfo_classname; 的 <literal>name</literal></title>  
    578 580 <screen>&prompt;<userinput>import fileinfo</userinput>  
    579 581 &prompt;<userinput>mp3file = fileinfo.MP3FileInfo()</userinput>                   <co id="fileinfo.specialmethods.4.1"/>  
     
    594 596 <calloutlist>  
    595 597 <callout arearefs="fileinfo.specialmethods.4.1">  
    596   <para>First, you create an instance of &mp3fileinfo_classname;, without passing it a filename.  (You can get away with this because the <varname>filename</varname> argument of the &init; method is <link linkend="apihelper.optional">optional</link>.)  Since &mp3fileinfo_classname; has no &init; method of its own, &python; walks up the ancestor tree and finds the &init; method of &fileinfo_classname;.  This &init; method manually calls the &init; method of &userdict_classname; and then sets the <literal>name</literal> key to <varname>filename</varname>, which is &none;, since you didn't pass a filename.  Thus, <varname>mp3file</varname> initially looks like a dictionary with one key, <literal>name</literal>, whose value is &none;.  
    597   </para>  
      598 <para>首先,我们创建了一个 &mp3fileinfo_classname; 的实例,没有传递给它文件名。(我们可以不用它,因为 &init; 方法的 <varname>filename</varname> 参数是 <link linkend="apihelper.optional">可选的</link>。) 因为 &mp3fileinfo_classname; 没有它自已的 &init; 方法,&python; 沿着父类树走,发现了 &fileinfo_classname; 的 &init; 方法。这个 &init; 方法手工调用了 &userdict_classname; 的 &init; 方法,然后设置 <literal>name</literal> 关键字为 <varname>filename</varname>,它为 &none;,因为我们还没有传入一个文件名。所以,<varname>mp3file</varname> 最初看上去象有一个关键字, <literal>name</literal>,它的值为 &none; 的字典。</para>  
    598 599 </callout>  
    599 600 <callout arearefs="fileinfo.specialmethods.4.2">  
    600   <para>Now the real fun begins.  Setting the <literal>name</literal> key of <varname>mp3file</varname> triggers the &setitem; method on &mp3fileinfo_classname; (not &userdict_classname;), which notices that you're setting the <literal>name</literal> key with a real value and calls <function>self.__parse</function>.  Although you haven't traced through the <function>__parse</function> method yet, you can see from the output that it sets several other keys: <literal>album</literal>, <literal>artist</literal>, <literal>genre</literal>, <literal>title</literal>, <literal>year</literal>, and <literal>comment</literal>.  
    601   </para>  
      601 <para>现在真正有趣的开始了。设置 <varname>mp3file</varname> 的 <literal>name</literal> 关键字触发了 &mp3fileinfo_classname; 上的 &setitem; 方法(不是 &userdict_classname;),这个方法注意到我们正在用一个真实的值来设置 <literal>name</literal> 关键字,接着调用 <function>self.__parse</function>。尽管我们完全还没有研究过 <function>__parse</function> 方法,从它的输出你可以看出,它设置了其它几个关键字:<literal>album</literal>, <literal>artist</literal>, <literal>genre</literal>, <literal>title</literal>, <literal>year</literal> 和 <literal>comment</literal>。</para>  
    602 602 </callout>  
    603 603 <callout arearefs="fileinfo.specialmethods.4.3">  
    604   <para>Modifying the <literal>name</literal> key will go through the same process again: &python; calls &setitem;, which calls <function>self.__parse</function>, which sets all the other keys.  
    605   </para>  
      604 <para>修改 <literal>name</literal> 关键字将再次经受同样的处理过程:&python; 调用 &setitem;,&setitem;调用 <function>self.__parse</function>,<function>self.__parse</function> 设置其它所有的关键字。</para>  
    606 605 </callout>  
    607 606 </calloutlist>  
     
    611 610 <section id="fileinfo.morespecial">  
    612 611 <?dbhtml filename="object_oriented_framework/special_class_methods2.html"?>  
    613   <title>Advanced Special Class Methods</title>  
      612 <title>高级专用类方法</title>  
    613 612 <abstract>  
    614 613 <title/>  
    615   <para>&python; has more special methods than just &getitem; and &setitem;.  Some of them let you emulate functionality that you may not even know about.</para>  
      614 <para>除了 &getitem; 和 &setitem; 之外 &python;  还有更多的专用函数。某些可以让你模拟出你甚至可能不知道的功能。</para>  
    615 614 </abstract>  
    616   <para>This example shows some of the other special methods in &userdict;.</para>  
      615 <para>下面的例子将展示 &userdict; 一些其他专用方法。</para>  
    616 615 <example id="fileinfo.morespecial.example">  
    617   <title>More Special Methods in &userdict_classname;</title>  
      616 <title>&userdict_classname; 中更多的专用方法</title>  
    617 616 <programlisting>  
    618 617 &userdict_repr; <co id="fileinfo.morespecial.1.1"/>  
     
    630 629 <calloutlist>  
    631 630 <callout arearefs="fileinfo.morespecial.1.1">  
    632   <para>&reprspecial; is a special method that is called when you call <literal>repr(<replaceable>instance</replaceable>)</literal>.  The &repr; function is a built-in function that returns a string representation of an object.  It works on any object, not just class instances.  You're already intimately familiar with &repr; and you don't even know it.  In the interactive window, when you type just a variable name and press the <keycap>ENTER</keycap> key, &python; uses &repr; to display the variable's value.  Go create a dictionary <varname>d</varname> with some data and then <literal>print repr(d)</literal> to see for yourself.</para>  
      631 <para>&reprspecial; 是一个专用的方法,在当调用 <literal>repr(<replaceable>instance</replaceable>)</literal> 时被调用。&repr; 函数是一个内置函数,它返回一个对象的字符串表示。它可以用在任何对象上,不仅仅是类的实例。你已经对 &repr; 相当熟悉了,尽管你不知道它。在交互式窗口中,当你只敲入一个变量名,接着按<keycap>ENTER</keycap>,&python; 使用 &repr; 来显示变量的值。自已用一些数据来创建一个字典 <varname>d</varname> ,然后用 <literal>print repr(d)</literal> 来看一看吧。</para>  
    632 631 </callout>  
    633 632 <callout arearefs="fileinfo.morespecial.1.2">  
    634   <para>&cmpspecial; is called when you compare class instances.  In general, you can compare any two &python; objects, not just class instances, by using &comparisonequals;.  There are rules that define when built-in datatypes are considered equal; for instance, dictionaries are equal when they have all the same keys and values, and strings are equal when they are the same length and contain the same sequence of characters.  For class instances, you can define the &cmpspecial; method and code the comparison logic yourself, and then you can use &comparisonequals; to compare instances of your class and &python; will call your &cmpspecial; special method for you.</para>  
      633 <para>&cmpspecial; 在比较类实例时被调用。通常,你可以通过使用 &comparisonequals; 比较任意两个 &python; 对象,不只是类实例。有一些规则,定义了何时内置数据类型被认为是相等的,例如,字典在有着全部相同的关键字和值时是相等的。对于类实例,你可以定义 &cmpspecial; 方法,自已编写比较逻辑,然后你可以使用 &comparisonequals; 来比较你的类,&python; 将会替你调用你的 &cmpspecial; 专用方法。</para>  
    634 633 </callout>  
    635 634 <callout arearefs="fileinfo.morespecial.1.3">  
    636   <para>&lenspecial; is called when you call <literal>len(<replaceable>instance</replaceable>)</literal>.  The &len; function is a built-in function that returns the length of an object.  It works on any object that could reasonably be thought of as having a length.  The &len; of a string is its number of characters; the &len; of a dictionary is its number of keys; the &len; of a list or tuple is its number of elements.  For class instances, define the &lenspecial; method and code the length calculation yourself, and then call <literal>len(<replaceable>instance</replaceable>)</literal> and &python; will call your &lenspecial; special method for you.</para>  
      635 <para>&lenspecial; 在调用 <literal>len(<replaceable>instance</replaceable>)</literal> 时被调用。&len;  是一个内置函数,可以返回一个对象的长度。它可以用于任何被认为理应有长度的对象。字符串的 &len;  是它的字符个数;字典的 &len; 是它的关键字的个数;列表或序列的 &len;  是元素的个数。对于类实例,定义 &lenspecial; 方法,接着自已编写长度的计算,然后调用 <literal>len(<replaceable>instance</replaceable>)</literal>,&python; 将替你调用你的 &lenspecial; 专用方法。</para>  
    636 635 </callout>  
    637 636 <callout arearefs="fileinfo.morespecial.1.4">  
    638   <para>&delitem; is called when you call <literal>del <replaceable>instance</replaceable>[<replaceable>key</replaceable>]</literal>, which you may remember as the way to <link linkend="odbchelper.dict.del">delete individual items from a dictionary</link>.  When you use &del; on a class instance, &python; calls the &delitem; special method for you.</para>  
      637 <para>&delitem; 在调用 <literal>del <replaceable>instance</replaceable>[<replaceable>key</replaceable>]</literal> 时调用 ,你可能记得它作为 <link linkend="odbchelper.dict.del">从字典中删除单个元素</link>的方法。当你在类实例中使用 &del; 时,&python; 替你调用 &delitem; 专用方法。</para>  
    638 637 </callout>  
    639 638 </calloutlist>  
     
    645 644 <note id="compare.strequals.java" role="compare" vendor="java">  
    646 645 <title>&python; &vs; &java; equality and identity</title>  
    647   <para>In &java;, you determine whether two string variables reference the same physical memory location by using <literal>str1 == str2</literal>.  This is called <emphasis>object identity</emphasis>, and it is written in &python; as <literal>str1 is str2</literal>.  To compare string values in &java;, you would use <literal>str1.equals(str2)</literal>; in &python;, you would use <literal>str1 == str2</literal>.  &java; programmers who have been taught to believe that the world is a better place because &comparisonequals; in &java; compares by identity instead of by value may have a difficult time adjusting to &python;'s lack of such <quote>gotchas</quote>.</para>  
      646 <para>在 &java; 中,通过使用 <literal>str1 == str2</literal> 可以决定两个字符串变量是否指向同一块物理内存位置。这就做 <emphasis>对象同一性</emphasis>,在 &python; 中写为 <literal>str1 is str2</literal>。在 &java; 中为了比较两个字符串值,你要使用 <literal>str1.equals(str2)</literal>;在 &python; 中,你要使用 <literal>str1 == str2</literal>。 某些 &java; 程序员,他们已经被教授得认为,因为在 &java; 中 &comparisonequals; 是通过一致性而不是值来进行比较的,所以 &java; 是更好的地方。这些人要转到 &python; 上来可能要花些时间。  
      647 [todo]  
      648 In &java;, you determine whether two string variables reference the same physical memory location by using <literal>str1 == str2</literal>.  This is called <emphasis>object identity</emphasis>, and it is written in &python; as <literal>str1 is str2</literal>.  To compare string values in &java;, you would use <literal>str1.equals(str2)</literal>; in &python;, you would use <literal>str1 == str2</literal>.  &java; programmers who have been taught to believe that the world is a better place because &comparisonequals; in &java; compares by identity instead of by value may have a difficult time adjusting to &python;'s lack of such <quote>gotchas</quote>.</para>  
    648 649 </note>  
    649   <para>At this point, you may be thinking, <quote>All this work just to do something in a class that I can do with a built-in datatype.</quote>  And it's true that life would be easier (and the entire &userdict_classname; class would be unnecessary) if you could inherit from built-in datatypes like a dictionary.  But even if you could, special methods would still be useful, because they can be used in any class, not just wrapper classes like &userdict_classname;.</para>  
    650   <para>Special methods mean that <emphasis>any class</emphasis> can store key/value pairs like a dictionary, just by defining the &setitem; method.  <emphasis>Any class</emphasis> can act like a sequence, just by defining the &getitem; method.  Any class that defines the &cmpspecial; method can be compared with &comparisonequals;.  And if your class represents something that has a length, don't define a <function>GetLength</function> method; define the &lenspecial; method and use <literal>len(<replaceable>instance</replaceable>)</literal>.</para>  
      650 <para>在这个地方,你可能会想,<quote>所有这些工作只是为了在类中做一些我可以对一个内置数据类型所做的操作</quote>。不错,如果你能够从象字典一样的内置数据类型进行继承的话,事情就容易多了(那样整个 &userdict_classname; 类将完全不需要了)。但是也许你可以,专用方法仍然是有用的,因为它们可以用于任何的类,而不只是象 &userdict_classname; 的封装类。</para>  
      651 <para>专用方法意味着 <emphasis>任何类</emphasis> 可以象字典一样保存键-值对,只要定义  &setitem; 方法。任何类可以表现得象一个序列,只要通过定义 &getitem; 方法。任何定义了 &cmpspecial; 方法的类可以用 &comparisonequals; 进行比较。并且如果你的类表现拥有类似长度的东西,不要定义 <function>GetLength</function> 方法,而定义 &lenspecial; 方法,使用 <literal>len(<replaceable>instance</replaceable>)</literal>。</para>  
    651 652 <note id="note.physical.v.logical">  
    652 653 <!--<title>Physical &vs; Logical Models</title>-->  
    653 654 <title/>  
    654   <para>While other object-oriented languages only let you define the physical model of an object (<quote>this object has a <function>GetLength</function> method</quote>), &python;'s special class methods like &lenspecial; allow you to define the logical model of an object (<quote>this object has a length</quote>).</para>  
      655 <para>其它的面向对象语言仅让你定义一个对象的物理模型(<quote>这个对象有 <function>GetLength</function> 方法</quote>),而 &python; 的专用类方法象 &lenspecial; 允许你定义一个对象的逻辑模型(<quote>这个对象有一个长度</quote>)。  
      656 </para>  
    655 657 </note>  
    656   <para>&python; has a lot of other special methods.  There's a whole set of them that let classes act like numbers, allowing you to add, subtract, and do other arithmetic operations on class instances.  (The canonical example of this is a class that represents complex numbers, numbers with both real and imaginary components.)  The &callspecial; method lets a class act like a function, allowing you to call a class instance directly.  And there are other special methods that allow classes to have read-only and write-only data attributes; you'll talk more about those in later chapters.</para>  
      658 <para>&python; 存在许多其它的专用方法。有一整套的专用方法,可以让类表现得象数值一样,允许你在类实例上进行加,减,和执行其它算数操作。(关于这一点典型的例子就是表示复数的类,数值带有实数和虚数部分。) &callspecial; 方法让一个类表现得象一个函数,允许你直接调用一个类实例。并且存在其它的专用函数,允许类拥有只读或只写数据属性,在后面的章节中我们会更多地谈到这些。</para>  
    656 658 <itemizedlist role="furtherreading">  
    657   <title>Further Reading on Special Class Methods</title>  
    658   <listitem><para>&pythonlanguagereference; documents <ulink url="&url_pythonlanguagereference;specialnames.html">all the special class methods</ulink>.</para></listitem>  
      659 <title>进一步阅读</title>  
      660 <listitem><para>&pythonlanguagereference; 提供了 <ulink url="&url_pythonlanguagereference;specialnames.html">所有专用类方法</ulink>的文档。</para></listitem>  
    659 661 </itemizedlist>  
    660 662 </section>  
    661 663 <section id="fileinfo.classattributes">  
    662 664 <?dbhtml filename="object_oriented_framework/class_attributes.html"?>  
    663   <title>Introducing Class Attributes</title>  
      665 <title>类属性介绍</title>  
    663 665 <abstract>  
    664 666 <title/>  
    665   <para>You already know about <link linkend="fileinfo.userdict.init.example">data attributes</link>, which are variables owned by a specific instance of a class.  &python; also supports class attributes, which are variables owned by the class itself.</para>  
      667 <para>你已经知道了 <link linkend="fileinfo.userdict.init.example">数据属性</link>,它们是被一个特定的类定例所拥有的变量。&python; 也支持类属性,它们是由类本身所拥有的。</para>  
    665 667 </abstract>  
    666 668 <example id="fileinfo.classattributes.intro">  
    667   <title>Introducing Class Attributes</title>  
      669 <title>类属性介绍</title>  
    667 669 <programlisting>  
    668 670 &fileinfo_mp3def;  
     
    693 695 <calloutlist>  
    694 696 <callout arearefs="fileinfo.classattributes.1.1">  
    695   <para>&mp3fileinfo_classname; is the class itself, not any particular instance of the class.</para>  
      697 <para>&mp3fileinfo_classname; 是类本身,不是任何类的特别实例。</para>  
    695 697 </callout>  
    696 698 <callout arearefs="fileinfo.classattributes.1.2">  
    697   <para>&tagdatamap; is a class attribute: literally, an attribute of the class.  It is available before creating any instances of the class.</para>  
      699 <para>&tagdatamap; 是一个类属性:字面的意思,一个类的属性。它是在创建任何类实例之前就有效了。</para>  
    697 699 </callout>  
    698 700 <callout arearefs="fileinfo.classattributes.1.3">  
    699   <para>Class attributes are available both through direct reference to the class and through any instance of the class.</para>  
      701 <para>类属性既可以通过直接对类的引用,也可以通过对类的任意实例的引用来使用。</para>  
    699 701 </callout>  
    700 702 </calloutlist>  
     
    705 707 <note id="compare.classattr.java" role="compare" vendor="java">  
    706 708 <title>&python; vs. &java; attribute definitions</title>  
    707   <para>In &java;, both static variables (called class attributes in &python;) and instance variables (called data attributes in &python;) are defined immediately after the class definition (one with the <literal>static</literal> keyword, one without).  In &python;, only class attributes can be defined here; data attributes are defined in the &init; method.</para>  
      709 <para>在 &java; 中,静态变量(在 &python; 中叫类属性)和实例变量(在 &python; 中叫数据属性)两者是紧跟在类定义之后定义的(一个有 <literal>static</literal> 关键字,一个没有)。在 &python; 中,只有类属性可以定义在这里,数据属性定义在 &init; 方法中定义。</para>  
    707 709 </note>  
    708   <para>Class attributes can be used as class-level constants (which is how you use them in &mp3fileinfo_classname;), but they are not really constants.  You can also change them.</para>  
      710 <para>类属性可以作为类级别的常量来使用(这就是为什么我们在 &mp3fileinfo_classname; 中使用它们),但是它们不是真正的常量。你也可以修改它们。</para>  
    708 710 <note>  
    709 711 <title/>  
    710   <para>There are no constants in &python;.  Everything can be changed if you try hard enough.  This fits with one of the core principles of &python;: bad behavior should be discouraged but not banned.  If you really want to change the value of &none;, you can do it, but don't come running to me when your code is impossible to debug.</para>  
      712 <para>在 &python; 中没有常量。如果你试图努力的话什么都可以改变。这一点满足 &python; 的核心原则之一:坏的行为应该被克服而不是被取缔。如果你真正想改变 &none; 的值,也可以做到,但当无法调试的时候别来找我。</para>  
    710 712 </note>  
    711 713 <example id="fileinfo.classattributes.writeable.example">  
    712   <title>Modifying Class Attributes</title>  
      714 <title>修改类属性</title>  
    712 714 <screen>&prompt;<userinput>class counter:</userinput>  
    713 715 &continuationprompt;<userinput>count = 0</userinput>                     <co id="fileinfo.classattributes.2.1"/>  
     
    737 739 <calloutlist>  
    738 740 <callout arearefs="fileinfo.classattributes.2.1">  
    739   <para><varname>count</varname> is a class attribute of the <classname>counter</classname> class.</para>  
      741 <para><varname>count</varname> 是 <classname>counter</classname> 类的一个类属性。</para>  
    739 741 </callout>  
    740 742 <callout arearefs="fileinfo.classattributes.2.2">  
    741   <para><literal>__class__</literal> is a built-in attribute of every class instance (of every class).  It is a reference to the class that <varname>self</varname> is an instance of (in this case, the <classname>counter</classname> class).</para>  
      743 <para><literal>__class__</literal> 是每个类实例的一个内置属性(也是每个类的)。它是一个类的引用,而 <varname>self</varname> 是一个类(在本例中, 是 <classname>counter</classname> 类)的实例。</para>  
    741 743 </callout>  
    742 744 <callout arearefs="fileinfo.classattributes.2.3">  
    743   <para>Because <varname>count</varname> is a class attribute, it is available through direct reference to the class, before you have created any instances of the class.</para>  
      745 <para>因为 <varname>count</varname> 是一个类属性,它可以在我们创建任何类实例之前,通过直接对类引用而得到。</para>  
    743 745 </callout>  
    744 746 <callout arearefs="fileinfo.classattributes.2.4">  
    745   <para>Creating an instance of the class calls the &init; method, which increments the class attribute <varname>count</varname> by &one;.  This affects the class itself, not just the newly created instance.</para>  
      747 <para>创建一个类实例会调用 &init; 方法,它会给类属性 <varname>count</varname> 加 &one;。这样会影响到类自身,不只是新创建的实例。</para>  
    745 747 </callout>  
    746 748 <callout arearefs="fileinfo.classattributes.2.5">  
    747   <para>Creating a second instance will increment the class attribute <varname>count</varname> again.  Notice how the class attribute is shared by the class and all instances of the class.</para>  
      749 <para>创建第二个实例将再次增加类属性 <varname>count</varname>。注意类属性是如何被类和所有类实例所共享的。</para>  
    747 749 </callout>  
    748 750 </calloutlist>  
     
    756 758 <section id="fileinfo.private">  
    757 759 <?dbhtml filename="object_oriented_framework/private_functions.html"?>  
    758   <title>Private Functions</title>  
    759   <para>Like most languages, &python; has the concept of private elements:</para>  
      760 <title>私有函数</title>  
      761 <para>与大多数语言一样,&python; 也有私有的概念:</para>  
    760 762 <itemizedlist>  
    761   <listitem><para>Private functions, which can't be called from outside their module</para></listitem>  
    762   <listitem><para>Private class methods, which can't be called from outside their class</para></listitem>  
    763   <listitem><para>Private attributes, which can't be accessed from outside their class.</para></listitem>  
      763 <listitem><para>私有函数不可以从它们的模块外面被调用</para></listitem>  
      764 <listitem><para>私有类方法不能够从它们的类外面被调用</para></listitem>  
      765 <listitem><para>私有属性不能够从它们的类外面被访问</para></listitem>  
    764 766 </itemizedlist>  
    765 767 <abstract>  
    766 768 <title/>  
    767   <para>Unlike in most languages, whether a &python; function, method, or attribute is private or public is determined entirely by its name.</para>  
      769 <para>与大多数的语言不同,一个 &python; 函数,方法,或属性是私有还是公有,完全取决于它的名字。</para>  
    767 769 </abstract>  
    768   <para>If the name of a &python; function, class method, or attribute starts with (but doesn't end with) two underscores, it's private; everything else is public.  &python; has no concept of <emphasis>protected</emphasis> class methods (accessible only in their own class and descendant classes).  Class methods are either private (accessible only in their own class) or public (accessible from anywhere).</para>  
    769   <para>In &mp3fileinfo_classname;, there are two methods: <function>__parse</function> and &setitem;.  As you have already discussed, &setitem; is a <link linkend="fileinfo.specialmethods.setitem.example">special method</link>; normally, you would call it indirectly by using the dictionary syntax on a class instance, but it is public, and you could call it directly (even from outside the &fileinfo_modulename; module) if you had a really good reason.  However, <function>__parse</function> is private, because it has two underscores at the beginning of its name.</para>  
      770 <para>如果一个 &python; 函数,类方法,或属性的名字以两个下划线开始(但不是结束),它是私有的;其它所有的都是公有的。  
      771 &python; 没有类方法 <emphasis>保护</emphasis> 的概念(只能用于它们自已的类和子类中)。类方法或者是私有(只能在它们自已的类中使用)或者是公有(任何地方都可使用)。</para>  
      772 <para>在 &mp3fileinfo_classname; 中,有两个方法:<function>__parse</function> 和 &setitem;。正如我们已经讨论过的,&setitem; 是一个 <link linkend="fileinfo.specialmethods.setitem.example">专有方法</link>;通常,你不直接调用它,而是通过在一个类上使用字典语法来调用,但它是公有的,并且如果有一个真正好的理由,你可以直接调用它(甚至从 &fileinfo_modulename; 模块的外面)。然而,<function>__parse</function> 是私有的,因为在它的名字前面有两个下划线。</para>  
    770 773 <note id="tip.specialmethodnames">  
    771 774 <title>Method Naming Conventions</title>  
    772   <para>In &python;, all special methods (like <link linkend="fileinfo.specialmethods.setitem.example">&setitem;</link>) and built-in attributes (like <link linkend="odbchelper.import">&doc;</link>) follow a standard naming convention: they both start with and end with two underscores.  Don't name your own methods and attributes this way, because it will only confuse you (and others) later.</para>  
      775 <para>在 &python; 中,所有的专用方法(象 <link linkend="fileinfo.specialmethods.setitem.example">&setitem;</link>)和内置属性(象 <link linkend="odbchelper.import">&doc;</link>)遵守一个标准的命名习惯:开始和结束都有两个下划下。不要对你自已的方法和属性用这种方法命名;到后面,它只会把你(或其它人)搞乱。</para>  
    772 775 </note>  
    773 776 <example>  
    774   <title>Trying to Call a Private Method</title>  
      777 <title>尝试调用一个私有方法</title>  
    774 777 <screen>&prompt;<userinput>import &fileinfo_name;</userinput>  
    775 778 &prompt;<userinput>m = fileinfo.MP3FileInfo()</userinput>  
    782 785 <calloutlist>  
    783 786 <callout arearefs="fileinfo.private.1.1">  
    784   <para>If you try to call a private method, &python; will raise a slightly misleading exception, saying that the method does not exist.  Of course it does exist, but it's private, so it's not accessible outside the class.</para>  
    785   <para>Strictly speaking, private methods are accessible outside their class, just not <emphasis>easily</emphasis> accessible.  Nothing in &python; is truly private; internally, the names of private methods and attributes are mangled and unmangled on the fly to make them seem inaccessible by their given names.  You can access the <function>__parse</function> method of the &mp3fileinfo_classname; class by the name <function>_MP3FileInfo__parse</function>.  Acknowledge that this is interesting, but promise to never, ever do it in real code.  Private methods are private for a reason, but like many other things in &python;, their privateness is ultimately a matter of convention, not force.</para>  
      787 <para>如果你试图调用一个私有方法,&python; 将引发一个有些误导的异常,宣称那个方法不存在。当然它确实存在,但是它是私有的,所以在类外是不可使用的。</para>  
      788 <para>严格地说,私有方法在它们的类外是可以访问的,只是不 <emphasis>容易</emphasis> 处理。在 &python; 中没有什么是真正私有的;在内部,私有方法和属性的名字被忽然改变和恢复,以致于使得它们看上去用它们给定的名字是无法使用的。你可以通过 <function>_MP3FileInfo__parse</function> 名字来使用 &mp3fileinfo_classname; 类的 <function>__parse</function> 方法。 知道了这个方法很有趣,然后要保证决不在真正的代码中使用它。私有方法由于某种原因而私有,但是象其它很多在Python中的东西一样,它们的私有化基本上是习惯问题,而不是强迫的。</para>  
    786 789 </callout>  
    787 790 </calloutlist>  
    788 791 </example>  
    789 792 <itemizedlist role="furtherreading">  
    790   <title>Further Reading on Private Functions</title>  
    791   <listitem><para>&pythontutorial; discusses the inner workings of <ulink url="&url_pythontutorial;node11.html#SECTION0011600000000000000000">private variables</ulink>.</para></listitem>  
      793 <title>进一步阅读</title>  
      794 <listitem><para>&pythontutorial; 讨论了 <ulink url="&url_pythontutorial;node11.html#SECTION0011600000000000000000">私有变量</ulink>的内部工作方式。</para></listitem>  
    792 795 </itemizedlist>  
    793 796 </section>  
    794 797 <section id="fileinfo.summary">  
    795 798 <?dbhtml filename="object_oriented_framework/summary.html"?>  
    796   <title>Summary</title>  
      799 <title>小结</title>  
    796 799 <abstract>  
    797 800 <title/>  
    798   <para>That's it for the hard-core object trickery.  You'll see a real-world application of special class methods in <xref linkend="soap" endterm="soap.numberonly"/>, which uses &getattr; to create a proxy to a remote web service.</para>  
      801 <para>[todo]That's it for the hard-core object trickery.  你将在 <xref linkend="soap" endterm="soap.numberonly"/> 中看到一个真实世界应用程序的专有类方法, 它使用 &getattr; 创建一个到远程 Web 服务的代理。</para>  
    798 801 </abstract>  
    799   <para>The next chapter will continue using this code sample to explore other &python; concepts, such as exceptions, file objects, and &for; loops.</para>  
    800   <para>Before diving into the next chapter, make sure you're comfortable doing all of these things:</para>  
      802 <para>下一章将继续使用本章的例程探索其他 &python; 的概念, 例如:异常, 文件对象 和 &for; 循环。</para>  
      803 <para>在研究下一章之前,确保你可以无困难地完成下面的事情:</para>  
    801 804 <itemizedlist>  
    802   <listitem><para>Importing modules using either <link linkend="odbchelper.import">&importmodule;</link> or <link linkend="fileinfo.fromimport">&frommoduleimport;</link></para></listitem>  
    803   <listitem><para><link linkend="fileinfo.class">Defining</link> and <link linkend="fileinfo.create">instantiating</link> classes</para></listitem>  
    804   <listitem><para>Defining <link linkend="fileinfo.class.example">&init; methods</link> and other <link linkend="fileinfo.specialmethods">special class methods</link>, and understanding when they are called</para></listitem>  
    805   <listitem><para>Subclassing <link linkend="fileinfo.userdict">&userdict_classname;</link> to define classes that act like dictionaries</para></listitem>  
    806   <listitem><para>Defining <link linkend="fileinfo.userdict.init.example">data attributes</link> and <link linkend="fileinfo.classattributes">class attributes</link>, and understanding the differences between them</para></listitem>  
    807   <listitem><para>Defining <link linkend="fileinfo.private">private attributes and methods</link></para></listitem>  
      805 <listitem><para>使用 <link linkend="odbchelper.import">&importmodule;</link> 或 <link linkend="fileinfo.fromimport">&frommoduleimport;</link>导入模块</para></listitem>  
      806 <listitem><para><link linkend="fileinfo.class">定义</link> 和 <link linkend="fileinfo.create">实例化</link>类</para></listitem>  
      807 <listitem><para>定义 <link linkend="fileinfo.class.example">&init; 方法</link> 和其他 <link linkend="fileinfo.specialmethods">专用类方法</link>, 并理解它们何时会调用</para></listitem>  
      808 <listitem><para>子类化 <link linkend="fileinfo.userdict">&userdict_classname;</link> 来定义作为象字典的类</para></listitem>  
      809 <listitem><para>定义 <link linkend="fileinfo.userdict.init.example">数据属性</link> 和 <link linkend="fileinfo.classattributes">类属性</link>, 并理解它们之间的不同</para></listitem>  
      810 <listitem><para>定义 <link linkend="fileinfo.private">私有属性和方法</link></para></listitem>  
    808 811 </itemizedlist>  
    809 812 </section>