首页 » 与孩子一起学编程 » 与孩子一起学编程全文在线阅读

《与孩子一起学编程》14.5 创建对象

关灯直达底部

Python 中创建对象包括两步。

第一步是定义对象看上去什么样,会做什么,也就是它的属性和方法。但是创建这个描述并不会真正创建一个对象。这有点像一个房子的蓝图。蓝图可以告诉你房子看上去怎么样,但是蓝图本身并不是一个房子。你不可能住在一个蓝图里。只能用它来建造真正的房子。实际上,可以使用蓝图盖很多的房子。

在 Python 中,对象的描述或蓝图称 为一个类(class)。

第二步是使用类来建立一个真正的对象。这个对象称为这个类的一个实例(instance)。

下面来看一个建立类和实例的例子。代码清单 14-1 显示了一个简单的 Ball 类的类定义。

代码清单 14-1 创建一个简单的 Ball 类

代码清单 14-1 是一个球的类定义,其中只有一个方法 bounce。不过,属性呢?嗯,属性并不属于类,它们属于各个实例。因为每个实例可以有不同的属性。

设置实例属性有两种方法。后面的小节中我们会分别了解这两种方法。

创建一个对象实例

前面提到过,类定义并不是一个对象。这只是蓝图。现在来盖真正的房子。

如果想创建 Ball 的一个实例,可以这样做:

>>> myBall = Ball

这个球还没有任何属性,所以下面给它提供一些属性:

>>> myBall.direction = /"down/">>> myBall.color = /"green/">>> myBall.size = /"small/"

这是为对象定义属性的一种方法。下一节还会学习另一种方法。

现在来试试它的方法。我们要这样使用 bounce 方法:

>>> myBall.bounce

下面把这些都放在一个程序里,增加一些 print 语句来看发生了什么。程序见代码清单 14-2。

代码清单 14-2 使用 Ball 类

运行这个程序,可以看到下面的结果:

注意,调用 bounce 方法会把球的方向(direction)从下(down)改为上(up),这正是 bounce 方法中的代码所要做的。

初始化对象

创建球对象时,并没有在 sizecolordirection 中填入任何内容。必须在创建对象之后填充这些内容。不过有一种方法可以在创建对象时设置属性。这称为初始化对象。

术语箱
初始化(Initializing)表示“开始时做好准备”。在软件中对某个东西初始化时,就是把它设置成一种我们希望的状态或条件,以备使用。

创建类定义时,可以定义一个特定的方法,名为 __init__,只要创建这个类的一个新实例,就会运行这个方法。可以向 __init__ 方法传递参数,这样创建实例时就会把属性设置为你希望的值。代码清单 14-3 显示了这是如何实现的。

代码清单 14-3 增加一个 __init__

如果这个程序,得到的输出应该与代码清单 14-2 的相同。区别在于,代码清单 14-3 使用了 __init__ 方法来设置属性。

谢谢你的提醒,Carter。在下一节中,我们将会了解这些“魔法”方法到底是什么。

“魔法”方法 :__str__

就像 Carter 说的,Python 中的对象有一些“魔法”方法,当然它们并不是真的有魔法!这些只是在你创建类时 Python 自动包含的一些方法。Python 程序员通常把它们叫做特殊方法(special method)。

我们已经知道,__init__ 方法会在对象创建时完成初始化。每个对象都内置有一个 __init__ 方法。如果你在类定义中没有加入自己的 __init__ 方法,就会有这样一个内置方法接管,它的工作就是创建对象。

另一个特殊方法是 __str__,它会告诉 Python 打印(print)一个对象时具体显示什么内容。Python 会默认以下内容。

 
  • 实例在哪里定义(Carter 的例子中,就是在 __main__ 中,这是程序的主部分)。

  • 类名(Ball)。

  • 存储实例的内存位置(0x00BB83A0 部分)。

不过,如果你希望 print 为对象显示其他的内容,可以定义自己的 __str__,这会覆盖内置的 __str__ 方法。代码清单 14-4 举了个例子。

代码清单 14-4 使用 __str__ 改变打印对象的方式

现在运行这个程序,可以得到下面的结果:

>>> ================= RESTART =================>>>Hi, I/'m a small red ball!>>>

这看起来比 <__main__.Ball instance at 0x00BB83A0> 好多了,你认为呢?

什么是 self

你可能已经注意到,在类属性和方法定义中多处出现了“self”,比如:

def bounce(self):

self 是什么意思?嗯,我们说过,可以使用蓝图盖很多个房子,还记得吧?使用一个类也可以创建多个对象实例,例如:

调用其中一个实例的方法时,像这样:

warrensBall.bounce

方法必须知道是哪个实例调用了它。是 cartersBall 需要反弹吗?还是 warrens Ball ? self 参数会告诉方法哪个对象调用它。这称为实例引用(instance reference)。

不过先等等!调用方法时,warrensBall.bounce 的括号里没有参数,但是方法里却有一个 self 参数。既然我们并没有传入任何东西,这个 self 参数从哪里来的?这是 Python 处理对象的另外一个“魔法”。调用一个类方法时,究竟是哪个实例调用了这个方法?这个信息(也就是实例引用)会自动传递给方法。

这就像写成:

Ball.bounce(warrensBall)

在这种情况下,我们告诉了 bounce 方法哪个球要反弹。实际上,这个代码也能正常工作,因为写成 warrensBall.bounce 时,Python 在后台确实也是这么做的。

顺便说一句,self 这个名字在 Python 中没有任何特殊的含义。只不 过所有人都使用这个实例引用名。这也是让代码更易读的一个约定。也可以把这个实例变量命名为你想要的任何名字,不过强烈建议你遵循这个约定,因为使用 self 能减少混乱。

我们在第 11 章建立了一个热狗程序。现在作为使用对象的例子,我们来为热狗建立一个类。