📄 node11.html
字号:
<P><H2><A NAME="SECTION0011330000000000000000"></A><A NAME="instanceObjects"></A><BR>9.3.3 实例对象 Instance Objects </H2><P>Now what can we do with instance objects? The only operations
understood by instance objects are attribute references. There are
two kinds of valid attribute names.<P>现在我们可以用实例对象作什么?实例对象唯一可用的操作就是属性引用。有两种有效的属性名。<P>The first I'll call <em>data attributes</em>. These correspond to
``instance variables'' in Smalltalk, and to ``data members'' in
C++. Data attributes need not be declared; like local variables,
they spring into existence when they are first assigned to. For
example, if <code>x</code> is the instance of <tt class="class">MyClass</tt> created above,
the following piece of code will print the value <code>16</code>, without
leaving a trace:<P>第一种称作数据属性。这相当于 Smalltalk 中的“实例变量”或 C++中的“数据成员”。和局部变量一样,数据属性不需要声明,第一次使用时它们就会生成。例如,如果 <code>x</code> 是前面创建的 <tt class="class">MyClass</tt> 实例,下面这段代码会打印出 <code>16</code> 而不会有任何多余的残留:<P><div class="verbatim"><pre>
x.counter = 1
while x.counter < 10:
x.counter = x.counter * 2
print x.counter
del x.counter</pre></div><P>The second kind of attribute references understood by instance objects
are <em>methods</em>. A method is a function that ``belongs to'' an
object. (In Python, the term method is not unique to class instances:
other object types can have methods as well. For example, list objects have
methods called append, insert, remove, sort, and so on. However,
below, we'll use the term method exclusively to mean methods of class
instance objects, unless explicitly stated otherwise.)<P>第二种为实例对象所接受的引用属性是方法。方法是属于一个对象的函数。(在 Python 中,方法不止是类实例所独有:其它类型的对象也可有<em>方法</em>。例如,链表对象有 append,insert,remove,sort 等等方法。然而,在这里,除非特别说明,我们提到的方法特指类方法)<P>Valid method names of an instance object depend on its class. By
definition, all attributes of a class that are (user-defined) function
objects define corresponding methods of its instances. So in our
example, <code>x.f</code> is a valid method reference, since
<code>MyClass.f</code> is a function, but <code>x.i</code> is not, since
<code>MyClass.i</code> is not. But <code>x.f</code> is not the same thing as
<code>MyClass.f</code> -- it is a <a id='l2h-50' xml:id='l2h-50'></a><em>method object</em>, not
a function object.<P>实例对象的有效名称依赖于它的类。按照定义,类中所有(用户定义)的函数对象对应它的实例中的方法。所以在我们的例子中,<code>x.f</code> 是一个有效的方法引用,因为 <code>MyClass.f</code> 是一个函数。但 <code>x.i</code> 不是,因为 <code>MyClass.i</code> 是不是函数。不过 <code>x.f</code> 和 <code>MyClass.f</code> 不同--它是一个方法对象,不是一个函数对象。<P><H2><A NAME="SECTION0011340000000000000000"></A><A NAME="methodObjects"></A><BR>9.3.4 方法对象 Method Objects </H2><P>Usually, a method is called immediately:<P>通常方法是直接调用的:<P><div class="verbatim"><pre>
x.f()</pre></div><P>In our example, this will return the string <code>'hello world'</code>.
However, it is not necessary to call a method right away:
<code>x.f</code> is a method object, and can be stored away and called at a
later time. For example:<P>在我们的例子中,这会返回字符串 <code>'hello world'</code> 。然而,也不是一定要直接调用方法。 <code>x.f</code> 是一个方法对象,它可以存储起来以后调用。例如:<P><div class="verbatim"><pre>
xf = x.f
while True:
print xf()</pre></div><P>will continue to print "<tt class="samp">hello world</tt>" until the end of time.<P>会不断的打印 "<tt class="samp">hello world</tt>" 。<P>What exactly happens when a method is called? You may have noticed
that <code>x.f()</code> was called without an argument above, even though
the function definition for <tt class="method">f</tt> specified an argument. What
happened to the argument? Surely Python raises an exception when a
function that requires an argument is called without any -- even if
the argument isn't actually used...<P>调用方法时发生了什么?你可能注意到调用 <code>x.f()</code> 时没有引用前面标出的变量,尽管在 <tt class="method">f</tt> 的函数定义中指明了一个参数。这个参数怎么了?事实上如果函数调用中缺少参数,Python 会抛出异常--甚至这个参数实际上没什么用……<P>Actually, you may have guessed the answer: the special thing about
methods is that the object is passed as the first argument of the
function. In our example, the call <code>x.f()</code> is exactly equivalent
to <code>MyClass.f(x)</code>. In general, calling a method with a list of
<var>n</var> arguments is equivalent to calling the corresponding function
with an argument list that is created by inserting the method's object
before the first argument.<P>实际上,你可能已经猜到了答案:方法的特别之处在于实例对象作为函数的第一个参数传给了函数。在我们的例子中,调用 <code>x.f()</code> 相当于 <code>MyClass.f(x)</code> 。通常,以 <var>n</var> 个参数的列表去调用一个方法就相当于将方法的对象插入到参数列表的最前面后,以这个列表去调用相应的函数。<P>If you still don't understand how methods work, a look at the
implementation can perhaps clarify matters. When an instance
attribute is referenced that isn't a data attribute, its class is
searched. If the name denotes a valid class attribute that is a
function object, a method object is created by packing (pointers to)
the instance object and the function object just found together in an
abstract object: this is the method object. When the method object is
called with an argument list, it is unpacked again, a new argument
list is constructed from the instance object and the original argument
list, and the function object is called with this new argument list.<P>如果你还是不理解方法的工作原理,了解一下它的实现也许有帮助。引用非数据属性的实例属性时,会搜索它的类。如果这个命名确认为一个有效的函数对象类属性,就会将实例对象和函数对象封装进一个抽象对象:这就是方法对象。以一个参数列表调用方法对象时,它被重新拆封,用实例对象和原始的参数列表构造一个新的参数列表,然后函数对象调用这个新的参数列表。<P><H1><A NAME="SECTION0011400000000000000000"></A><A NAME="remarks"></A><BR>9.4 一些说明 Random Remarks </H1><P>〔有些内容可能需要明确一下……〕<P>Data attributes override method attributes with the same name; to
avoid accidental name conflicts, which may cause hard-to-find bugs in
large programs, it is wise to use some kind of convention that
minimizes the chance of conflicts. Possible conventions include
capitalizing method names, prefixing data attribute names with a small
unique string (perhaps just an underscore), or using verbs for methods
and nouns for data attributes.<P>同名的数据属性会覆盖方法属性,为了避免可能的命名冲突--这在大型程序中可能会导致难以发现的 bug --最好以某种命名约定来避免冲突。可选的约定包括方法的首字母大写,数据属性名前缀小写(可能只是一个下划线),或者方法使用动词而数据属性使用名词。<P>Data attributes may be referenced by methods as well as by ordinary
users (``clients'') of an object. In other words, classes are not
usable to implement pure abstract data types. In fact, nothing in
Python makes it possible to enforce data hiding -- it is all based
upon convention. (On the other hand, the Python implementation,
written in C, can completely hide implementation details and control
access to an object if necessary; this can be used by extensions to
Python written in C.)<P>数据属性可以由方法引用,也可以由普通用户(客户)调用。换句话说,类不能实现纯的数据类型。事实上 Python 中没有什么办法可以强制隐藏数据--一切都基本约定的惯例。(另一方法讲,Python 的实现是用 C 写成的,如果有必要,可以用 C 来编写 Python 扩展,完全隐藏实现的细节,控制对象的访问。)<P>Clients should use data attributes with care -- clients may mess up
invariants maintained by the methods by stamping on their data
attributes. Note that clients may add data attributes of their own to
an instance object without affecting the validity of the methods, as
long as name conflicts are avoided -- again, a naming convention can
save a lot of headaches here.<P>客户应该小心使用数据属性--客户可能会因为随意修改数据属性而破坏了本来由方法维护的数据一致性。需要注意的是,客户只要注意避免命名冲突,就可以随意向实例中添加数据属性而不会影响方法的有效性--再次强调,命名约定可以省去很多麻烦。<P>There is no shorthand for referencing data attributes (or other
methods!) from within methods. I find that this actually increases
the readability of methods: there is no chance of confusing local
variables and instance variables when glancing through a method.<P>从方法内部引用数据属性(以及其它方法!)没有什么快捷的方式。我认为这事实上增加了方法的可读性:即使粗略的浏览一个方法,也不会有混淆局部变量和实例变量的机会。<P>Conventionally, the first argument of methods is often called
<code>self</code>. This is nothing more than a convention: the name
<code>self</code> has absolutely no special meaning to Python. (Note,
however, that by not following the convention your code may be less
readable by other Python programmers, and it is also conceivable that
a <em>class browser</em> program be written which relies upon such a
convention.)<P>习惯上,方法的第一个参数命名为 <code>self</code> 。这仅仅是一个约定:对 Python 而言,<code>self</code> 绝对没有任何特殊含义。(然而要注意的是,如果不遵守这个约定,别的 Python 程序员阅读你的代码时会有不便,而且有些类浏览程序也是遵循此约定开发的。)<P>Any function object that is a class attribute defines a method for
instances of that class. It is not necessary that the function
definition is textually enclosed in the class definition: assigning a
function object to a local variable in the class is also ok. For
example:<P>类属性中的任何函数对象在类实例中都定义为方法。不是必须要将函数定义代码写进类定义中,也可以将一个函数对象赋给类中的一个变量。例如:<P><div class="verbatim"><pre>
# Function defined outside the class
def f1(self, x, y):
return min(x, x+y)
class C:
f = f1
def g(self):
return 'hello world'
h = g</pre></div><P>Now <code>f</code>, <code>g</code> and <code>h</code> are all attributes of class
<tt class="class">C</tt> that refer to function objects, and consequently they are all
methods of instances of <tt class="class">C</tt> -- <code>h</code> being exactly equivalent
to <code>g</code>. Note that this practice usually only serves to confuse
the reader of a program.<P>现在 <code>f</code>, <code>g</code> 和 <code>h</code> 都是类 <tt class="class">C</tt> 的属性,引用的都是函数对象,因此它们都是 <tt class="class">C</tt> 实例的方法-- <code>h</code> 严格等于 <code>g</code>。要注意的是这种习惯通常只会迷惑程序的读者。<P>Methods may call other methods by using method attributes of the
<code>self</code> argument:<P>通过 <code>self</code> 参数的方法属性,方法可以调用其它的方法:<P><div class="verbatim"><pre>
class Bag:
def __init__(self):
self.data = []
def add(self, x):
self.data.append(x)
def addtwice(self, x):
self.add(x)
self.add(x)</pre></div><P>Methods may reference global names in the same way as ordinary
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -