添加新方法
子类还可以添加父类中没有的方法。回到 Car 类 和 Tesla 类,我们给 Tesla 类添加一个新的方法 need_a_push():
接着创建一个 Car 和一个 Tesla 对象:
Tesla 类的对象可以响应 need_a_push()方法:
但父类 Car 无法使用该方法:
至此,Yugo终于可以做一些 Car 做不到的事情了。它的与众不同的特征开始体现了出来。
Super
我们已经知道如何在子类中覆盖父类的方法,但如果想要调用父类的方法就要使用 super()。下面的例子将新定义一个新的类 EmailPerson,用于表示有电子邮箱的 Person。首先,来定义熟悉的Person类:
下面是子类的定义。注意,子类的初始化方法 init() 中添加了一个额外的 email 参数:
在子类中定义 init() 方法时,父类的 init() 方法会被覆盖。因此在子类中父类的初始化方法并不会被自动调用,我们必须显式调用它。以上代码实际上做了这样几件事情:
通过 super() 方法获取了父类 Person 的定义。
子类的 init() 调用了 Person.init() 方法。它会自动将 self 参数传递给父类。因此,你只需传入其余参数即可。在上面的例子中,Person() 能接受的其余参数指的是 name。
self.email = email 这行新的代码才真正起到了将 EmailPerson 与 Person 区分开的作用。
接下来,创建一个 EmailPerson 类的对象:
我们既可以访问 name 特性,也可访问 email 特性:
为什么不像下面这样定义 EmailPerson 类呢?
确实可以这么做,但这有悖我么使用继承的初衷。我们应该使用 super() 来让 Person 完成他应该做的事情,就像任何一个单纯的 Person 对象一样。除此之外,不这么写还有另一个好处,如果 Person 类的定义在未来发生改变,使用 super() 可以保证这些改变会自动体现在 EmailPersion类上,而不需要手动修改。
子类可以按照自己的方式处理问题,但如果人需要借助父类的帮助,使用 super() 是最佳的选择。
Self
Python 中经常被争议的一点(除了使用空格外)就是必须把 self 设置为实例方法的第一个参数。Python 使用 self 参数来找到正确的对象所包含的特性和方法。通过下面的例子,我会告诉你调用对象方法背后 Python 实际做的工作。
Python 在背后做了一下两件事:
查找 car 对象所属的类(Car);
把 car 对象作为 self 参数传给 Car 类所包含的 exclaim() 方法。
了解调用机制后,为了好玩,我们甚至可以像下面这样进行调用,这与普通的调用语法(car.exclaim())效果完全一致:
当然,我们没有理由使用这种臃肿的语法。
下周见
领取专属 10元无门槛券
私享最新 技术干货