7.2.2 对象的创建

一旦定义了类,就可以创建类的实例,也就是该类的一个对象②。类是抽象的,而对象

则是具体的,就好比“人”是抽象概念,而“张三”是个具体的人。一个类可以创建任意多 个实例(对象),所有实例都具有相同的行为(这是由类中定义的方法决定的),但各自的数 据值可以不同。创建类的实例采用如下形式:

<变量> = <类名>(<参数>)

这里将类名当成一个函数来用,称为类的构造器(constructor,或称构造函数)。构造器返回 一个新对象,通常需要定义<变量>来引用这个新对象。注意,虽然<变量>只是对新对象的引 用,但习惯上我们也常说<变量>就是新对象本身,这一般不会产生混淆。

如果希望创建对象时将对象定制成特定的初始状态,则可以在类中定义特殊的 __init__ 方法③。创建新对象时,Python 自动调用 __init__,实现对新对象的初始化,比如为该对象所 拥有的数据进行赋值。 __init__ 方法可以用参数(至少有一个 self 参数)来传递初始化所需的信息,调用 __init__ 时必须提供相应的实参。但由于 __init__ 不是直接调用的,无法直接将实 参传递给它,所以我们将所需实参传递给构造器,再由构造器自动传递给 __init__ 。不过,__init__ 的特殊参数 self 是一个例外,传递给 self 的实参是新创建的对象(更准确地说是对新 建对象的引用)。

① 如 Pascal 语言中的 record 和 C 语言中的 struct 类型。

② 本书中混用“实例”和“对象”这两个术语,视之为相同的概念。

③ 也可以说 init ()才是类的构造器,不过不能直接调用,而是通过类名来隐含地调用。

例如,下面的语句先导入 Person 类,然后创建一个 Person 对象,并使变量 p1 引用该对象:

>>> from person import Person
>>> p1 = Person("Lucy",2005)

创建对象时自动调用 init__方法,该方法所需的三个参数 self、n、y 分别用实参 p1、"Lucy"和 2005 代入,这相当于函数调用

__init__ (p1,"Lucy",2005)

从而导致执行 __init__的函数体,为新对象进行初始化:

p1.name = "Lucy" 
p1.year = 2005

图 7.6 给出了上述利用 Person 构造器创建对象 p1 并调用 __init__进行初始化的过程。

图 7.6 对象创建与初始化

注意, init 方法中对变量 name 和 year 所赋的值"Lucy"和 2005,是专属于新实例 p1 的,它们与同一个类的其他实例(例如下面将创建的 p2)没有关系。这两个变量都属于实例 变量(instance variable),意即它们的值是随实例的不同而不同的。下面再创建一个 Person 对象,并使变量 p2 引用这个新对象:

>>> p2 = Person("Tom",1990)

同样地,Python 自动调用 init 方法,只不过这次传递给该方法的参数是 p2、"Tom"和 1990, 即相当于函数调用

__init__ (p2,"Tom",1990)

从而导致执行 __init__的函数体,为新对象 p2 进行初始化:

p2.name = "Tom" 
p2.year = 1990

这里,对实例变量 name 和 year 所赋的值"Tom"和 1990 是专属于新实例 p2 的,与前面创建的实例 p1 没有关系。创建同一个类的多个实例的过程可参见图 7.7。

图 7.7 创建同一个类的多个实例

从图 7.7 可见,类与实例的关系就像模具与产品的关系,用同一个模具可以制造出大量 的产品,这些产品总体上是相似的,但可能各有不同的细节。p1 与 p2 是属于同一类的对象, 总体上非常相似,例如都有数据 name 和 year,但各有不同的数据值。