Python's class mechanism adds classes to the language with a minimum of new syntax and semantics. It is a mixture of the class mechanisms found in C++ and Modula-3. As is true for modules, classes in Python do not put an absolute barrier between definition and user, but rather rely on the politeness of the user not to ``break into the definition.'' The most important features of classes are retained with full power, however: the class inheritance mechanism allows multiple base classes, a derived class can override any methods of its base class or classes, a method can call the method of a base class with the same name. Objects can contain an arbitrary amount of private data.
Python 在盡可能不增加新的語(yǔ)法和語(yǔ)義的情況下加入了類機(jī)制。這種機(jī)制是 C++ 和 Modula-3 的混合。Python中的類沒(méi)有在用戶和定義之間建立一個(gè)絕對(duì)的屏障,而是依賴于用戶自覺(jué)的不去“破壞定義”。然而,類機(jī)制最重要的功能都完整的保留下來(lái)。類繼承機(jī)制允許多繼承,派生類可以覆蓋(override)基類中的任何方法,方法中可以調(diào)用基類中的同名方法。對(duì)象可以包含任意數(shù)量的私有成員。
In C++ terminology, all class members (including the data members) are public, and all member functions are virtual. There are no special constructors or destructors. As in Modula-3, there are no shorthands for referencing the object's members from its methods: the method function is declared with an explicit first argument representing the object, which is provided implicitly by the call. As in Smalltalk, classes themselves are objects, albeit in the wider sense of the word: in Python, all data types are objects. This provides semantics for importing and renaming. Unlike C++ and Modula-3, built-in types can be used as base classes for extension by the user. Also, like in C++ but unlike in Modula-3, most built-in operators with special syntax (arithmetic operators, subscripting etc.) can be redefined for class instances.
用 C++ 術(shù)語(yǔ)來(lái)講,所有的類成員(包括數(shù)據(jù)成員)都是公有( public )的,所有的成員函數(shù)都是虛擬( virtual )的。沒(méi)有特定的構(gòu)造和析構(gòu)函數(shù)。用Modula-3的術(shù)語(yǔ)來(lái)講,在成員方法中沒(méi)有什么簡(jiǎn)便的方式(shorthands)可以引用對(duì)象的成員:方法函數(shù)在定義時(shí)需要以引用的對(duì)象做為第一個(gè)參數(shù),調(diào)用時(shí)則會(huì)隱式引用對(duì)象。這樣就形成了語(yǔ)義上的引入和重命名。( This provides semantics for importing and renaming. )但是,像 C++ 而非 Modula-3 中那樣,大多數(shù)帶有特殊語(yǔ)法的內(nèi)置操作符(算法運(yùn)算符、下標(biāo)等)都可以針對(duì)類的需要重新定義。
Lacking universally accepted terminology to talk about classes, I will make occasional use of Smalltalk and C++ terms. (I would use Modula-3 terms, since its object-oriented semantics are closer to those of Python than C++, but I expect that few readers have heard of it.)
由于沒(méi)有什么關(guān)于類的通用術(shù)語(yǔ),我從 Smalltalk 和 C++ 中借用一些(我更希望用 Modula-3 的,因?yàn)樗拿嫦驅(qū)ο髾C(jī)制比 C++更接近Python,不過(guò)我想沒(méi)多少讀者聽(tīng)說(shuō)過(guò)它)。
I also have to warn you that there's a terminological pitfall for object-oriented readers: the word ``object'' in Python does not necessarily mean a class instance. Like C++ and Modula-3, and unlike Smalltalk, not all types in Python are classes: the basic built-in types like integers and lists are not, and even somewhat more exotic types like files aren't. However, all Python types share a little bit of common semantics that is best described by using the word object.
我要提醒讀者,這里有一個(gè)面向?qū)ο蠓矫娴男g(shù)語(yǔ)陷阱,在 Python 中“對(duì)象”這個(gè)詞不一定指類實(shí)例。Python 中并非所有的類型都是類:例如整型、鏈表這些內(nèi)置數(shù)據(jù)類型就不是,甚至某些像文件這樣的外部類型也不是,這一點(diǎn)類似于 C++ 和 Modula-3,而不像 Smalltalk。然而,所有的 Python 類型在語(yǔ)義上都有一點(diǎn)相同之處:描述它們的最貼切詞語(yǔ)是“對(duì)象”。
Objects have individuality, and multiple names (in multiple scopes) can be bound to the same object. This is known as aliasing in other languages. This is usually not appreciated on a first glance at Python, and can be safely ignored when dealing with immutable basic types (numbers, strings, tuples). However, aliasing has an (intended!) effect on the semantics of Python code involving mutable objects such as lists, dictionaries, and most types representing entities outside the program (files, windows, etc.). This is usually used to the benefit of the program, since aliases behave like pointers in some respects. For example, passing an object is cheap since only a pointer is passed by the implementation; and if a function modifies an object passed as an argument, the caller will see the change -- this eliminates the need for two different argument passing mechanisms as in Pascal.
對(duì)象是被特化的,多個(gè)名字(在多個(gè)作用域中)可以綁定同一個(gè)對(duì)象。這相當(dāng)于其它語(yǔ)言中的別名。通常對(duì) Python 的第一印象中會(huì)忽略這一點(diǎn),使用那些不可變的基本類型(數(shù)值、字符串、元組)時(shí)也可以很放心的忽視它。然而,在 Python 代碼調(diào)用字典、鏈表之類可變對(duì)象,以及大多數(shù)涉及程序外部實(shí)體(文件、窗體等等)的類型時(shí),這一語(yǔ)義就會(huì)有影響。這通用有助于優(yōu)化程序,因?yàn)閯e名的行為在某些方面類似于指針。例如,很容易傳遞一個(gè)對(duì)象,因?yàn)樵谛袨樯现皇莻鬟f了一個(gè)指針。如果函數(shù)修改了一個(gè)通過(guò)參數(shù)傳遞的對(duì)象,調(diào)用者可以接收到變化--在 Pascal 中這需要兩個(gè)不同的參數(shù)傳遞機(jī)制。
Before introducing classes, I first have to tell you something about Python's scope rules. Class definitions play some neat tricks with namespaces, and you need to know how scopes and namespaces work to fully understand what's going on. Incidentally, knowledge about this subject is useful for any advanced Python programmer.
在介紹類之前,我首先介紹一些有關(guān) Python 作用域的規(guī)則:類的定義非常巧妙的運(yùn)用了命名空間,要完全理解接下來(lái)的知識(shí),需要先理解作用域和命名空間的工作原理。另外,這一切的知識(shí)對(duì)于任何高級(jí) Python 程序員都非常有用。
Let's begin with some definitions.
我們從一些定義開(kāi)始。
A namespace is a mapping from names to objects. Most namespaces are currently implemented as Python dictionaries, but that's normally not noticeable in any way (except for performance), and it may change in the future. Examples of namespaces are: the set of built-in names (functions such as abs(), and built-in exception names); the global names in a module; and the local names in a function invocation. In a sense the set of attributes of an object also form a namespace. The important thing to know about namespaces is that there is absolutely no relation between names in different namespaces; for instance, two different modules may both define a function ``maximize'' without confusion -- users of the modules must prefix it with the module name.
命名空間是從命名到對(duì)象的映射。當(dāng)前命名空間主要是通過(guò) Python 字典實(shí)現(xiàn)的,不過(guò)通常不關(guān)心具體的實(shí)現(xiàn)方式(除非出于性能考慮),以后也有可能會(huì)改變其實(shí)現(xiàn)方式。以下有一些命名空間的例子:內(nèi)置命名(像 <#2558#>abs() 這樣的函數(shù),以及內(nèi)置異常名)集,模塊中的全局命名,函數(shù)調(diào)用中的局部命名。某種意義上講對(duì)象的屬性集也是一個(gè)命名空間。關(guān)于命名空間需要了解的一件很重要的事就是不同命名空間中的命名沒(méi)有任何聯(lián)系,例如兩個(gè)不同的模塊可能都會(huì)定義一個(gè)名為“maximize”的函數(shù)而不會(huì)發(fā)生混淆--用戶必須以模塊名為前綴來(lái)引用它們。
By the way, I use the word attribute for any name following a
dot -- for example, in the expression z.real
, real
is
an attribute of the object z
. Strictly speaking, references to
names in modules are attribute references: in the expression
modname.funcname
, modname
is a module object and
funcname
is an attribute of it. In this case there happens to
be a straightforward mapping between the module's attributes and the
global names defined in the module: they share the same namespace!
9.1
順便提一句,我稱 Python 中任何一個(gè)“.”之后的命名為屬性--例如,表達(dá)式 z.real
中的 real
是對(duì)象 z
的一個(gè)屬性。嚴(yán)格來(lái)講,從模塊中引用命名是引用屬性:表達(dá)式 modname.funcname
中, modname
是一個(gè)模塊對(duì)象,funcname
是它的一個(gè)屬性。因此,模塊的屬性和模塊中的全局命名有直接的映射關(guān)系:它們共享同一命名空間!9.2
Attributes may be read-only or writable. In the latter case,
assignment to attributes is possible. Module attributes are writable:
you can write "modname.the_answer = 42". Writable attributes may
also be deleted with the del statement. For example,
"del modname.the_answer" will remove the attribute
the_answer from the object named by modname
.
屬性可以是只讀過(guò)或?qū)懙。后一種情況下,可以對(duì)屬性賦值。你可以這樣作:
"modname.the_answer = 42"。可寫的屬性也可以用 del
語(yǔ)句刪除。例如:"del modname.the_answer" 會(huì)從
modname
對(duì)象中刪除 the_answer 屬性。
Name spaces are created at different moments and have different lifetimes. The namespace containing the built-in names is created when the Python interpreter starts up, and is never deleted. The global namespace for a module is created when the module definition is read in; normally, module namespaces also last until the interpreter quits. The statements executed by the top-level invocation of the interpreter, either read from a script file or interactively, are considered part of a module called __main__, so they have their own global namespace. (The built-in names actually also live in a module; this is called __builtin__.)
不同的命名空間在不同的時(shí)刻創(chuàng)建,有不同的生存期。包含內(nèi)置命名的命名空間在 Python 解釋器啟動(dòng)時(shí)創(chuàng)建,會(huì)一直保留,不被刪除。模塊的全局命名空間在模塊定義被讀入時(shí)創(chuàng)建,通常,模塊命名空間也會(huì)一直保存到解釋器退出。由解釋器在最高層調(diào)用執(zhí)行的語(yǔ)句,不管它是從腳本文件中讀入還是來(lái)自交互式輸入,都是 __main__ 模塊的一部分,所以它們也擁有自己的命名空間。(內(nèi)置命名也同樣被包含在一個(gè)模塊中,它被稱作 __builtin__ 。)
The local namespace for a function is created when the function is called, and deleted when the function returns or raises an exception that is not handled within the function. (Actually, forgetting would be a better way to describe what actually happens.) Of course, recursive invocations each have their own local namespace.
當(dāng)函數(shù)被調(diào)用時(shí)創(chuàng)建一個(gè)局部命名空間,函數(shù)反正返回過(guò)拋出一個(gè)未在函數(shù)內(nèi)處理的異常時(shí)刪除。(實(shí)際上,說(shuō)是遺忘更為貼切)。當(dāng)然,每一個(gè)遞歸調(diào)用擁有自己的命名空間。
A scope is a textual region of a Python program where a namespace is directly accessible. ``Directly accessible'' here means that an unqualified reference to a name attempts to find the name in the namespace.
盡管作用域是靜態(tài)定義,在使用時(shí)他們都是動(dòng)態(tài)的。每次執(zhí)行時(shí),至少有三個(gè)命名空間可以直接訪問(wèn)的作用域嵌套在一起:包含局部命名的使用域在最里面,首先被搜索;其次搜索的是中層的作用域,這里包含了同級(jí)的函數(shù);最后搜索最外面的作用域,它包含內(nèi)置命名。
Although scopes are determined statically, they are used dynamically. At any time during execution, there are at least three nested scopes whose namespaces are directly accessible: the innermost scope, which is searched first, contains the local names; the namespaces of any enclosing functions, which are searched starting with the nearest enclosing scope; the middle scope, searched next, contains the current module's global names; and the outermost scope (searched last) is the namespace containing built-in names.
盡管作用域是靜態(tài)定義,在使用時(shí)他們都是動(dòng)態(tài)的。每次執(zhí)行時(shí),至少有三個(gè)命名空間可以直接訪問(wèn)的作用域嵌套在一起:包含局部命名的使用域在最里面,首先被搜索;其次搜索的是中層的作用域,這里包含了同級(jí)的函數(shù);最后搜索最外面的作用域,它包含內(nèi)置命名。
If a name is declared global, then all references and assignments go directly to the middle scope containing the module's global names. Otherwise, all variables found outside of the innermost scope are read-only.
如果一個(gè)命名聲明為全局的,那么所有的賦值和引用都直接針對(duì)包含模全局命名的中級(jí)作用域。另外,從外部訪問(wèn)到的所有內(nèi)層作用域的變量都是只讀的。
Usually, the local scope references the local names of the (textually) current function. Outside of functions, the local scope references the same namespace as the global scope: the module's namespace. Class definitions place yet another namespace in the local scope.
從文本意義上講,局部作用域引用當(dāng)前函數(shù)的命名。在函數(shù)之外,局部作用域與全局使用域引用同一命名空間:模塊命名空間。類定義也是局部作用域中的另一個(gè)命名空間。
It is important to realize that scopes are determined textually: the global scope of a function defined in a module is that module's namespace, no matter from where or by what alias the function is called. On the other hand, the actual search for names is done dynamically, at run time -- however, the language definition is evolving towards static name resolution, at ``compile'' time, so don't rely on dynamic name resolution! (In fact, local variables are already determined statically.)
作用域決定于源程序的文本:一個(gè)定義于某模塊中的函數(shù)的全局作用域是該模塊的命名空間,而不是該函數(shù)的別名被定義或調(diào)用的位置,了解這一點(diǎn)非常重要。另一方面,命名的實(shí)際搜索過(guò)程是動(dòng)態(tài)的,在運(yùn)行時(shí)確定的——然而,Python 語(yǔ)言也在不斷發(fā)展,以后有可能會(huì)成為靜態(tài)的“編譯”時(shí)確定,所以不要依賴于動(dòng)態(tài)解析。ㄊ聦(shí)上,局部變量已經(jīng)是靜態(tài)確定了。)
A special quirk of Python is that assignments always go into the
innermost scope. Assignments do not copy data -- they just
bind names to objects. The same is true for deletions: the statement
"del x" removes the binding of x
from the namespace
referenced by the local scope. In fact, all operations that introduce
new names use the local scope: in particular, import statements and
function definitions bind the module or function name in the local
scope. (The global statement can be used to indicate that
particular variables live in the global scope.)
Python 的一個(gè)特別之處在于其賦值操作總是在最里層的作用域。賦值不會(huì)復(fù)制數(shù)據(jù)——只是將命名綁定到對(duì)象。刪除也是如此:"del
x" 只是從局部作用域的命名空間中刪除命名 x
。事實(shí)上,所有引入新命名的操作都作用于局部作用域。特別是 import 語(yǔ)句和函數(shù)定將模塊名或函數(shù)綁定于局部作用域。(可以使用 global 語(yǔ)句將變量引入到全局作用域。)
Classes introduce a little bit of new syntax, three new object types, and some new semantics.
類引入了一點(diǎn)新的語(yǔ)法,三種新的對(duì)象類型,以及一些新的語(yǔ)義。
The simplest form of class definition looks like this:
最簡(jiǎn)單的類定義形式如下:
class ClassName: <statement-1> . . . <statement-N>
Class definitions, like function definitions (def statements) must be executed before they have any effect. (You could conceivably place a class definition in a branch of an if statement, or inside a function.)
類的定義就像函數(shù)定義( def 語(yǔ)句),要先執(zhí)行才能生效。(你當(dāng)然可以把它放進(jìn) if 語(yǔ)句的某一分支,或者一個(gè)函數(shù)的內(nèi)部。)
In practice, the statements inside a class definition will usually be function definitions, but other statements are allowed, and sometimes useful -- we'll come back to this later. The function definitions inside a class normally have a peculiar form of argument list, dictated by the calling conventions for methods -- again, this is explained later.
習(xí)慣上,類定義語(yǔ)句的內(nèi)容通常是函數(shù)定義,不過(guò)其它語(yǔ)句也可以,有時(shí)會(huì)很有用——后面我們?cè)倩剡^(guò)頭來(lái)討論。類中的函數(shù)定義通常包括了一個(gè)特殊形式的參數(shù)列表,用于方法調(diào)用約定——同樣我們?cè)诤竺嬗懻撨@些。
When a class definition is entered, a new namespace is created, and used as the local scope -- thus, all assignments to local variables go into this new namespace. In particular, function definitions bind the name of the new function here.
定義一個(gè)類的時(shí)候,會(huì)創(chuàng)建一個(gè)新的命名空間,將其作為局部作用域使用——因此,所以對(duì)局部變量的賦值都引入新的命名空間。特別是函數(shù)定義將新函數(shù)的命名綁定于此。
When a class definition is left normally (via the end), a class object is created. This is basically a wrapper around the contents of the namespace created by the class definition; we'll learn more about class objects in the next section. The original local scope (the one in effect just before the class definitions was entered) is reinstated, and the class object is bound here to the class name given in the class definition header (ClassName in the example).
類定義完成時(shí)(正常退出),就創(chuàng)建了一個(gè)類對(duì)象;旧纤菍(duì)類定義創(chuàng)建的命名空間進(jìn)行了一個(gè)包裝;我們?cè)谙乱还?jié)進(jìn)一步學(xué)習(xí)類對(duì)象的知識(shí)。原始的局部作用域(類定義引入之前生效的那個(gè))得到恢復(fù),類對(duì)象在這里綁定到類定義頭部的類名(例子中是 ClassName )。
Class objects support two kinds of operations: attribute references and instantiation.
類對(duì)象支持兩種操作:屬性引用和實(shí)例化。
Attribute references use the standard syntax used for all
attribute references in Python: obj.name
. Valid attribute
names are all the names that were in the class's namespace when the
class object was created. So, if the class definition looked like
this:
屬性引用使用和 Python 中所有的屬性引用一樣的標(biāo)準(zhǔn)語(yǔ)法:obj.name
。類對(duì)象創(chuàng)建后,類命名空間中所有的命名都是有效屬性名。所以如果類定義是這樣:
class MyClass: "A simple example class" i = 12345 def f(self): return 'hello world'
then MyClass.i
and MyClass.f
are valid attribute
references, returning an integer and a method object, respectively.
Class attributes can also be assigned to, so you can change the value
of MyClass.i
by assignment. __doc__ is also a valid
attribute, returning the docstring belonging to the class: "A
simple example class"
.
那么 MyClass.i
和 MyClass.f
是有效的屬性引用,分別返回一個(gè)整數(shù)和一個(gè)方法對(duì)象。也可以對(duì)類屬性賦值,你可以通過(guò)給MyClass.i
賦值來(lái)修改它。 __doc__ 也是一個(gè)有效的屬性,返回類的文檔字符串: "A simple example class"
。
Class instantiation uses function notation. Just pretend that the class object is a parameterless function that returns a new instance of the class. For example (assuming the above class):
類的實(shí)例化使用函數(shù)符號(hào)。只要將類對(duì)象看作是一個(gè)返回新的類實(shí)例的無(wú)參數(shù)函數(shù)即可。例如(假設(shè)沿用前面的類):
x = MyClass()
creates a new instance of the class and assigns this object to
the local variable x
.
以上創(chuàng)建了一個(gè)新的類實(shí)例并將該對(duì)象賦給局部變量 x
。
The instantiation operation (``calling'' a class object) creates an empty object. Many classes like to create objects in a known initial state. Therefore a class may define a special method named __init__(), like this:
這個(gè)實(shí)例化操作(“調(diào)用”一個(gè)類對(duì)象)來(lái)創(chuàng)建一個(gè)空的對(duì)象。很多類都傾向于將對(duì)象創(chuàng)建為有初始狀態(tài)的。因此類可能會(huì)定義一個(gè)名為 __init__() 的特殊方法,像下面這樣:
def __init__(self): self.data = []
When a class defines an __init__() method, class instantiation automatically invokes __init__() for the newly-created class instance. So in this example, a new, initialized instance can be obtained by:
類定義了 __init__() 方法的話,類的實(shí)例化操作會(huì)自動(dòng)為新創(chuàng)建的類實(shí)例調(diào)用 __init__() 方法。所以在下例中,可以這樣創(chuàng)建一個(gè)新的實(shí)例:
x = MyClass()
Of course, the __init__() method may have arguments for greater flexibility. In that case, arguments given to the class instantiation operator are passed on to __init__(). For example,
當(dāng)然,出于彈性的需要, __init__() 方法可以有參數(shù)。事實(shí)上,參數(shù)通過(guò) __init__() 傳遞到類的實(shí)例化操作上。例如:
>>> class Complex: ... def __init__(self, realpart, imagpart): ... self.r = realpart ... self.i = imagpart ... >>> x = Complex(3.0, -4.5) >>> x.r, x.i (3.0, -4.5)
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.
現(xiàn)在我們可以用實(shí)例對(duì)象作什么?實(shí)例對(duì)象唯一可用的操作就是屬性引用。有兩種有效的屬性名。
The first I'll call data attributes. 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 x
is the instance of MyClass created above,
the following piece of code will print the value 16
, without
leaving a trace:
第一種稱作數(shù)據(jù)屬性。這相當(dāng)于 Smalltalk 中的“實(shí)例變量”或 C++中的“數(shù)據(jù)成員”。和局部變量一樣,數(shù)據(jù)屬性不需要聲明,第一次使用時(shí)它們就會(huì)生成。例如,如果 x
是前面創(chuàng)建的 MyClass 實(shí)例,下面這段代碼會(huì)打印出 16
而不會(huì)有任何多余的殘留:
x.counter = 1 while x.counter < 10: x.counter = x.counter * 2 print x.counter del x.counter
The second kind of attribute references understood by instance objects are methods. 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.)
第二種為實(shí)例對(duì)象所接受的引用屬性是方法。方法是屬于一個(gè)對(duì)象的函數(shù)。(在 Python 中,方法不止是類實(shí)例所獨(dú)有:其它類型的對(duì)象也可有方法。例如,鏈表對(duì)象有 append,insert,remove,sort 等等方法。然而,在這里,除非特別說(shuō)明,我們提到的方法特指類方法)
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, x.f
is a valid method reference, since
MyClass.f
is a function, but x.i
is not, since
MyClass.i
is not. But x.f
is not the same thing as
MyClass.f
-- it is a method object, not
a function object.
實(shí)例對(duì)象的有效名稱依賴于它的類。按照定義,類中所有(用戶定義)的函數(shù)對(duì)象對(duì)應(yīng)它的實(shí)例中的方法。所以在我們的例子中,x.f
是一個(gè)有效的方法引用,因?yàn)?MyClass.f
是一個(gè)函數(shù)。但 x.i
不是,因?yàn)?MyClass.i
是不是函數(shù)。不過(guò) x.f
和 MyClass.f
不同--它是一個(gè)方法對(duì)象,不是一個(gè)函數(shù)對(duì)象。
Usually, a method is called immediately:
通常方法是直接調(diào)用的:
x.f()
In our example, this will return the string 'hello world'
.
However, it is not necessary to call a method right away:
x.f
is a method object, and can be stored away and called at a
later time. For example:
在我們的例子中,這會(huì)返回字符串 'hello world'
。然而,也不是一定要直接調(diào)用方法。 x.f
是一個(gè)方法對(duì)象,它可以存儲(chǔ)起來(lái)以后調(diào)用。例如:
xf = x.f while True: print xf()
will continue to print "hello world" until the end of time.
會(huì)不斷的打印 "hello world" 。
What exactly happens when a method is called? You may have noticed
that x.f()
was called without an argument above, even though
the function definition for f 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...
調(diào)用方法時(shí)發(fā)生了什么?你可能注意到調(diào)用 x.f()
時(shí)沒(méi)有引用前面標(biāo)出的變量,盡管在 f 的函數(shù)定義中指明了一個(gè)參數(shù)。這個(gè)參數(shù)怎么了?事實(shí)上如果函數(shù)調(diào)用中缺少參數(shù),Python 會(huì)拋出異常--甚至這個(gè)參數(shù)實(shí)際上沒(méi)什么用……
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 x.f()
is exactly equivalent
to MyClass.f(x)
. In general, calling a method with a list of
n 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.
實(shí)際上,你可能已經(jīng)猜到了答案:方法的特別之處在于實(shí)例對(duì)象作為函數(shù)的第一個(gè)參數(shù)傳給了函數(shù)。在我們的例子中,調(diào)用 x.f()
相當(dāng)于 MyClass.f(x)
。通常,以 n 個(gè)參數(shù)的列表去調(diào)用一個(gè)方法就相當(dāng)于將方法的對(duì)象插入到參數(shù)列表的最前面后,以這個(gè)列表去調(diào)用相應(yīng)的函數(shù)。
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.
如果你還是不理解方法的工作原理,了解一下它的實(shí)現(xiàn)也許有幫助。引用非數(shù)據(jù)屬性的實(shí)例屬性時(shí),會(huì)搜索它的類。如果這個(gè)命名確認(rèn)為一個(gè)有效的函數(shù)對(duì)象類屬性,就會(huì)將實(shí)例對(duì)象和函數(shù)對(duì)象封裝進(jìn)一個(gè)抽象對(duì)象:這就是方法對(duì)象。以一個(gè)參數(shù)列表調(diào)用方法對(duì)象時(shí),它被重新拆封,用實(shí)例對(duì)象和原始的參數(shù)列表構(gòu)造一個(gè)新的參數(shù)列表,然后函數(shù)對(duì)象調(diào)用這個(gè)新的參數(shù)列表。
〔有些內(nèi)容可能需要明確一下……〕
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.
同名的數(shù)據(jù)屬性會(huì)覆蓋方法屬性,為了避免可能的命名沖突--這在大型程序中可能會(huì)導(dǎo)致難以發(fā)現(xiàn)的 bug --最好以某種命名約定來(lái)避免沖突?蛇x的約定包括方法的首字母大寫,數(shù)據(jù)屬性名前綴小寫(可能只是一個(gè)下劃線),或者方法使用動(dòng)詞而數(shù)據(jù)屬性使用名詞。
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.)
數(shù)據(jù)屬性可以由方法引用,也可以由普通用戶(客戶)調(diào)用。換句話說(shuō),類不能實(shí)現(xiàn)純的數(shù)據(jù)類型。事實(shí)上 Python 中沒(méi)有什么辦法可以強(qiáng)制隱藏?cái)?shù)據(jù)--一切都基本約定的慣例。(另一方法講,Python 的實(shí)現(xiàn)是用 C 寫成的,如果有必要,可以用 C 來(lái)編寫 Python 擴(kuò)展,完全隱藏實(shí)現(xiàn)的細(xì)節(jié),控制對(duì)象的訪問(wèn)。)
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.
客戶應(yīng)該小心使用數(shù)據(jù)屬性--客戶可能會(huì)因?yàn)殡S意修改數(shù)據(jù)屬性而破壞了本來(lái)由方法維護(hù)的數(shù)據(jù)一致性。需要注意的是,客戶只要注意避免命名沖突,就可以隨意向?qū)嵗刑砑訑?shù)據(jù)屬性而不會(huì)影響方法的有效性--再次強(qiáng)調(diào),命名約定可以省去很多麻煩。
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.
從方法內(nèi)部引用數(shù)據(jù)屬性(以及其它方法。](méi)有什么快捷的方式。我認(rèn)為這事實(shí)上增加了方法的可讀性:即使粗略的瀏覽一個(gè)方法,也不會(huì)有混淆局部變量和實(shí)例變量的機(jī)會(huì)。
Conventionally, the first argument of methods is often called
self
. This is nothing more than a convention: the name
self
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 class browser program be written which relies upon such a
convention.)
習(xí)慣上,方法的第一個(gè)參數(shù)命名為 self
。這僅僅是一個(gè)約定:對(duì) Python 而言,self
絕對(duì)沒(méi)有任何特殊含義。(然而要注意的是,如果不遵守這個(gè)約定,別的 Python 程序員閱讀你的代碼時(shí)會(huì)有不便,而且有些類瀏覽程序也是遵循此約定開(kāi)發(fā)的。)
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:
類屬性中的任何函數(shù)對(duì)象在類實(shí)例中都定義為方法。不是必須要將函數(shù)定義代碼寫進(jìn)類定義中,也可以將一個(gè)函數(shù)對(duì)象賦給類中的一個(gè)變量。例如:
# 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
Now f
, g
and h
are all attributes of class
C that refer to function objects, and consequently they are all
methods of instances of C -- h
being exactly equivalent
to g
. Note that this practice usually only serves to confuse
the reader of a program.
現(xiàn)在 f
, g
和 h
都是類 C 的屬性,引用的都是函數(shù)對(duì)象,因此它們都是 C 實(shí)例的方法-- h
嚴(yán)格等于 g
。要注意的是這種習(xí)慣通常只會(huì)迷惑程序的讀者。
Methods may call other methods by using method attributes of the
self
argument:
通過(guò) self
參數(shù)的方法屬性,方法可以調(diào)用其它的方法:
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)
Methods may reference global names in the same way as ordinary functions. The global scope associated with a method is the module containing the class definition. (The class itself is never used as a global scope!) While one rarely encounters a good reason for using global data in a method, there are many legitimate uses of the global scope: for one thing, functions and modules imported into the global scope can be used by methods, as well as functions and classes defined in it. Usually, the class containing the method is itself defined in this global scope, and in the next section we'll find some good reasons why a method would want to reference its own class!
方法可以像引用普通的函數(shù)那樣引用全局命名。與方法關(guān)聯(lián)的全局作用域是包含類定義的模塊。(類本身永遠(yuǎn)不會(huì)做為全局作用域使用。┍M管很少有好的理由在方法中使用全局?jǐn)?shù)據(jù),全局作用域確有很多合法的用途:其一是方法可以調(diào)用導(dǎo)入全局作用域的函數(shù)和方法,也可以調(diào)用定義在其中的類和函數(shù)。通常,包含此方法的類也會(huì)定義在這個(gè)全局作用域,在下一節(jié)我們會(huì)了解為何一個(gè)方法要引用自己的類!
Of course, a language feature would not be worthy of the name ``class'' without supporting inheritance. The syntax for a derived class definition looks as follows:
當(dāng)然,如果一種語(yǔ)言不支持繼承就,“類”就沒(méi)有什么意義。派生類的定義如下所示:
class DerivedClassName(BaseClassName): <statement-1> . . . <statement-N>
The name BaseClassName must be defined in a scope containing the derived class definition. Instead of a base class name, an expression is also allowed. This is useful when the base class is defined in another module,
命名 BaseClassName(示例中的基類名)必須與派生類定義在一個(gè)作用域內(nèi)。除了類,還可以用表達(dá)式,基類定義在另一個(gè)模塊中時(shí)這一點(diǎn)非常有用:
class DerivedClassName(modname.BaseClassName):
Execution of a derived class definition proceeds the same as for a base class. When the class object is constructed, the base class is remembered. This is used for resolving attribute references: if a requested attribute is not found in the class, it is searched in the base class. This rule is applied recursively if the base class itself is derived from some other class.
派生類定義的執(zhí)行過(guò)程和基類是一樣的。構(gòu)造派生類對(duì)象時(shí),就記住了基類。這在解析屬性引用的時(shí)候尤其有用:如果在類中找不到請(qǐng)求調(diào)用的屬性,就搜索基類。如果基類是由別的類派生而來(lái),這個(gè)規(guī)則會(huì)遞歸的應(yīng)用上去。
There's nothing special about instantiation of derived classes:
DerivedClassName()
creates a new instance of the class. Method
references are resolved as follows: the corresponding class attribute
is searched, descending down the chain of base classes if necessary,
and the method reference is valid if this yields a function object.
派生類的實(shí)例化沒(méi)有什么特殊之處:DerivedClassName()
(示列中的派生類)創(chuàng)建一個(gè)新的類實(shí)例。方法引用按如下規(guī)則解析:搜索對(duì)應(yīng)的類屬性,必要時(shí)沿基類鏈逐級(jí)搜索,如果找到了函數(shù)對(duì)象這個(gè)方法引用就是合法的
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 C++ programmers: all methods in Python are effectively virtual.)
派生類可能會(huì)覆蓋其基類的方法。因?yàn)榉椒ㄕ{(diào)用同一個(gè)對(duì)象中的其它方法時(shí)沒(méi)有特權(quán),基類的方法調(diào)用同一個(gè)基類的方法時(shí),可能實(shí)際上最終調(diào)用了派生類中的覆蓋方法。(對(duì)于 C++ 程序員來(lái)說(shuō),Python中的所有方法本質(zhì)上都是虛方法。)
An overriding method in a derived class may in fact want to extend rather than simply replace the base class method of the same name. There is a simple way to call the base class method directly: just call "BaseClassName.methodname(self, arguments)". This is occasionally useful to clients as well. (Note that this only works if the base class is defined or imported directly in the global scope.)
派生類中的覆蓋方法可能是想要擴(kuò)充而不是簡(jiǎn)單的替代基類中的重名方法。有一個(gè)簡(jiǎn)單的方法可以直接調(diào)用基類方法,只要調(diào)用:"BaseClassName.methodname(self, arguments)"。有時(shí)這對(duì)于客戶也很有用。(要注意的中只有基類在同一全局作用域定義或?qū)霑r(shí)才能這樣用。)
Python supports a limited form of multiple inheritance as well. A class definition with multiple base classes looks as follows:
Python同樣有限的支持多繼承形式。多繼承的類定義形如下例:
class DerivedClassName(Base1, Base2, Base3): <statement-1> . . . <statement-N>
The only rule necessary to explain the semantics is the resolution rule used for class attribute references. This is depth-first, left-to-right. Thus, if an attribute is not found in DerivedClassName, it is searched in Base1, then (recursively) in the base classes of Base1, and only if it is not found there, it is searched in Base2, and so on.
這里唯一需要解釋的語(yǔ)義是解析類屬性的規(guī)則。順序是深度優(yōu)先,從左到右。因此,如果在 DerivedClassName (示例中的派生類)中沒(méi)有找到某個(gè)屬性,就會(huì)搜索 Base1 ,然后(遞歸的)搜索其基類,如果最終沒(méi)有找到,就搜索 Base2,以此類推。
(To some people breadth first -- searching Base2 and Base3 before the base classes of Base1 -- looks more natural. However, this would require you to know whether a particular attribute of Base1 is actually defined in Base1 or in one of its base classes before you can figure out the consequences of a name conflict with an attribute of Base2. The depth-first rule makes no differences between direct and inherited attributes of Base1.)
(有些人認(rèn)為廣度優(yōu)先--在搜索Base1的基類之前搜索Base2和Base3
--看起來(lái)更為自然。然而,如果Base1和Base2之間發(fā)生了命名沖突,你需要了解這個(gè)屬性是定義于Base1還是Base1的基類中。而深度優(yōu)先不區(qū)分屬性繼承自基類還是直接定義。)
It is clear that indiscriminate use of multiple inheritance is a maintenance nightmare, given the reliance in Python on conventions to avoid accidental name conflicts. A well-known problem with multiple inheritance is a class derived from two classes that happen to have a common base class. While it is easy enough to figure out what happens in this case (the instance will have a single copy of ``instance variables'' or data attributes used by the common base class), it is not clear that these semantics are in any way useful.
顯然不加限制的使用多繼承會(huì)帶來(lái)維護(hù)上的噩夢(mèng),因?yàn)?Python 中只依靠約定來(lái)避免命名沖突。多繼承一個(gè)很有名的問(wèn)題是派生繼承的兩個(gè)基類都是從同一個(gè)基類繼承而來(lái)。目前還不清楚這在語(yǔ)義上有什么意義,然而很容易想到這會(huì)造成什么后果(實(shí)例會(huì)有一個(gè)獨(dú)立的“實(shí)例變量”或數(shù)據(jù)屬性復(fù)本作用于公共基類。)
There is limited support for class-private
identifiers. Any identifier of the form __spam
(at least two
leading underscores, at most one trailing underscore) is now textually
replaced with _classname__spam
, where classname
is the
current class name with leading underscore(s) stripped. This mangling
is done without regard of the syntactic position of the identifier, so
it can be used to define class-private instance and class variables,
methods, as well as globals, and even to store instance variables
private to this class on instances of other classes. Truncation
may occur when the mangled name would be longer than 255 characters.
Outside classes, or when the class name consists of only underscores,
no mangling occurs.
Python 對(duì)類的私有成員提供了有限的支持。任何形如 __spam
(以至少雙下劃線開(kāi)頭,至多單下劃線結(jié)尾)隨即都被替代為 _classname__spam
,去掉前導(dǎo)下劃線的 classname
即當(dāng)前的類名。這種混淆不關(guān)心標(biāo)識(shí)符的語(yǔ)法位置,所以可用來(lái)定義私有類實(shí)例和類變量、方法,以及全局變量,甚至于將其它類的實(shí)例保存為私有變量;煜L(zhǎng)度超過(guò)255個(gè)字符的時(shí)候可能會(huì)發(fā)生截?cái)唷T陬惖耐獠,或類名只包含下劃線時(shí),不會(huì)發(fā)生截?cái)唷?
Name mangling is intended to give classes an easy way to define ``private'' instance variables and methods, without having to worry about instance variables defined by derived classes, or mucking with instance variables by code outside the class. Note that the mangling rules are designed mostly to avoid accidents; it still is possible for a determined soul to access or modify a variable that is considered private. This can even be useful in special circumstances, such as in the debugger, and that's one reason why this loophole is not closed. (Buglet: derivation of a class with the same name as the base class makes use of private variables of the base class possible.)
命名混淆意在給出一個(gè)在類中定義“私有”實(shí)例變量和方法的簡(jiǎn)單途徑,避免派生類的實(shí)例變量定義產(chǎn)生問(wèn)題,或者與外界代碼中的變量搞混。要注意的是混淆規(guī)則主要目的在于避免意外錯(cuò)誤,被認(rèn)作為私有的變量仍然有可能被訪問(wèn)或修改。在特定的場(chǎng)合它也是有用的,比如調(diào)試的時(shí)候,這也是一直沒(méi)有堵上這個(gè)漏洞的原因之一(小漏洞:派生類和基類取相同的名字就可以使用基類的私有變量。)
Notice that code passed to exec
, eval()
or
evalfile()
does not consider the classname of the invoking
class to be the current class; this is similar to the effect of the
global
statement, the effect of which is likewise restricted to
code that is byte-compiled together. The same restriction applies to
getattr()
, setattr()
and delattr()
, as well as
when referencing __dict__
directly.
要注意的是傳入 exec
,eval()
或 evalfile()
的代碼不會(huì)將調(diào)用它們的類視作當(dāng)前類,這與 global
語(yǔ)句的情況類似,global
的作用局限于“同一批”進(jìn)行字節(jié)編譯的代碼。同樣的限制也適用于 getattr()
,setattr()
和delattr()
,以及直接引用 __dict__
的時(shí)候。
Sometimes it is useful to have a data type similar to the Pascal ``record'' or C ``struct'', bundling together a couple of named data items. An empty class definition will do nicely:
有時(shí)類似于Pascal中“記錄(record)”或C中“結(jié)構(gòu)(struct)”的數(shù)據(jù)類型很有用,它將一組已命名的數(shù)據(jù)項(xiàng)綁定在一起。一個(gè)空的類定義可以很好的實(shí)現(xiàn)這它:
class Employee: pass john = Employee() # Create an empty employee record # Fill the fields of the record john.name = 'John Doe' john.dept = 'computer lab' john.salary = 1000
A piece of Python code that expects a particular abstract data type can often be passed a class that emulates the methods of that data type instead. For instance, if you have a function that formats some data from a file object, you can define a class with methods read() and readline() that gets the data from a string buffer instead, and pass it as an argument.
某一段 Python 代碼需要一個(gè)特殊的抽象數(shù)據(jù)結(jié)構(gòu)的話,通?梢詡魅胍粋(gè)類,事實(shí)上這模仿了該類的方法。例如,如果你有一個(gè)用于從文件對(duì)象中格式化數(shù)據(jù)的函數(shù),你可以定義一個(gè)帶有 read() 和 readline() 方法的類,以此從字符串緩沖讀取數(shù)據(jù),然后將該類的對(duì)象作為參數(shù)傳入前述的函數(shù)。
Instance method objects have attributes, too: m.im_self
is the
object of which the method is an instance, and m.im_func
is the
function object corresponding to the method.
實(shí)例方法對(duì)象也有屬性: m.im_self
是一個(gè)實(shí)例方法所屬的對(duì)象,而 m.im_func
是這個(gè)方法對(duì)應(yīng)的函數(shù)對(duì)象。
User-defined exceptions are identified by classes as well. Using this mechanism it is possible to create extensible hierarchies of exceptions.
用戶自定義異常也可以是類。利用這個(gè)機(jī)制可以創(chuàng)建可擴(kuò)展的異常體系。
There are two new valid (semantic) forms for the raise statement:
以下是兩種新的有效(語(yǔ)義上的)異常拋出形式:
raise Class, instance raise instance
In the first form, instance
must be an instance of
Class or of a class derived from it. The second form is a
shorthand for:
第一種形式中,instance
必須是 Class 或其派生類的一個(gè)實(shí)例。第二種形式是以下形式的簡(jiǎn)寫:
raise instance.__class__, instance
A class in an except clause is compatible with an exception if it is the same class or a base class thereof (but not the other way around -- an except clause listing a derived class is not compatible with a base class). For example, the following code will print B, C, D in that order:
發(fā)生的異常其類型如果是異常子句中列出的類,或者是其派生類,那么它們就是相符的(反過(guò)來(lái)說(shuō)--發(fā)生的異常其類型如果是異常子句中列出的類的基類,它們就不相符)。例如,以下代碼會(huì)按順序打印B,C,D:
class B: pass class C(B): pass class D(C): pass for c in [B, C, D]: try: raise c() except D: print "D" except C: print "C" except B: print "B"
Note that if the except clauses were reversed (with "except B" first), it would have printed B, B, B -- the first matching except clause is triggered.
要注意的是如果異常子句的順序顛倒過(guò)來(lái)( "execpt B" 在最前),它就會(huì)打印B,B,B--第一個(gè)匹配的異常被觸發(fā)。
When an error message is printed for an unhandled exception which is a class, the class name is printed, then a colon and a space, and finally the instance converted to a string using the built-in function str().
打印一個(gè)異常類的錯(cuò)誤信息時(shí),先打印類名,然后是一個(gè)空格、一個(gè)冒號(hào),然后是用內(nèi)置函數(shù) str() 將類轉(zhuǎn)換得到的完整字符串。
By now, you've probably noticed that most container objects can be looped over using a for statement:
現(xiàn)在你可能注意到大多數(shù)容器對(duì)象都可以用 for
遍歷:
for element in [1, 2, 3]: print element for element in (1, 2, 3): print element for key in {'one':1, 'two':2}: print key for char in "123": print char for line in open("myfile.txt"): print line
This style of access is clear, concise, and convenient. The use of iterators pervades and unifies Python. Behind the scenes, the for statement calls iter() on the container object. The function returns an iterator object that defines the method next() which accesses elements in the container one at a time. When there are no more elements, next() raises a StopIteration exception which tells the for loop to terminate. This example shows how it all works:
這種形式的訪問(wèn)清晰、簡(jiǎn)潔、方便。這種迭代器的用法在 Python 中普遍而且統(tǒng)一。在后臺(tái),for
語(yǔ)句在容器對(duì)象中調(diào)用 iter() 。 該函數(shù)返回一個(gè)定義了 next() 方法的迭代器對(duì)象,它在容器中逐一訪問(wèn)元素。沒(méi)有后續(xù)的元素時(shí),next()拋出一個(gè) StopIteration 異常通知 for
語(yǔ)句循環(huán)結(jié)束。以下是其工作原理的示例:
>>> s = 'abc' >>> it = iter(s) >>> it <iterator object at 0x00A1DB50> >>> it.next() 'a' >>> it.next() 'b' >>> it.next() 'c' >>> it.next() Traceback (most recent call last): File "<pyshell#6>", line 1, in -toplevel- it.next() StopIteration
Having seen the mechanics behind the iterator protocol, it is easy to add
iterator behavior to your classes. Define a __iter__() method
which returns an object with a next() method. If the class defines
next(), then __iter__() can just return self
:
了解了迭代器協(xié)議的后臺(tái)機(jī)制,就可以很容易的給自己的類添加迭代器行為。定義一個(gè) __iter__() 方法,使其返回一個(gè)帶有 next() 方法的對(duì)象。如果這個(gè)類已經(jīng)定義了 next(),那么 __iter__() 只需要返回self:
>>> class Reverse: "Iterator for looping over a sequence backwards" def __init__(self, data): self.data = data self.index = len(data) def __iter__(self): return self def next(self): if self.index == 0: raise StopIteration self.index = self.index - 1 return self.data[self.index] >>> for char in Reverse('spam'): print char m a p s
Generators are a simple and powerful tool for creating iterators. They are written like regular functions but use the yield statement whenever they want to return data. Each time the next() is called, the generator resumes where it left-off (it remembers all the data values and which statement was last executed). An example shows that generators can be trivially easy to create:
生成器是創(chuàng)建迭代器的簡(jiǎn)單而強(qiáng)大的工具。它們寫起來(lái)就像是正則函數(shù),需要返回?cái)?shù)據(jù)的時(shí)候使用 yield 語(yǔ)句。每次 next() 被調(diào)用時(shí),生成器回復(fù)它脫離的位置(它記憶語(yǔ)句最后一次執(zhí)行的位置和所有的數(shù)據(jù)值)。以下示例演示了生成器可以很簡(jiǎn)單的創(chuàng)建出來(lái):
>>> def reverse(data): for index in range(len(data)-1, -1, -1): yield data[index] >>> for char in reverse('golf'): print char f l o g
Anything that can be done with generators can also be done with class based iterators as described in the previous section. What makes generators so compact is that the __iter__() and next() methods are created automatically.
前一節(jié)中描述了基于類的迭代器,它能作的每一件事生成器也能作到。因?yàn)樽詣?dòng)創(chuàng)建了 __iter__() 和 next() 方法,生成器顯得如此簡(jiǎn)潔。
Another key feature is that the local variables and execution state
are automatically saved between calls. This made the function easier to write
and much more clear than an approach using class variables like
self.index
and self.data
.
另外一個(gè)關(guān)鍵的功能是兩次調(diào)用之間的局部變量和執(zhí)行情況都自動(dòng)保存了下來(lái)。這樣函數(shù)編寫起來(lái)就比手動(dòng)調(diào)用
self.index
和 self.data
這樣的類變量容易的多。
In addition to automatic method creation and saving program state, when generators terminate, they automatically raise StopIteration. In combination, these features make it easy to create iterators with no more effort than writing a regular function.
除了創(chuàng)建和保存程序狀態(tài)的自動(dòng)方法,當(dāng)發(fā)生器終結(jié)時(shí),還會(huì)自動(dòng)拋出 StopIteration 異常。綜上所述,這些功能使得編寫一個(gè)正則函數(shù)成為創(chuàng)建迭代器的最簡(jiǎn)單方法。