翻译:《实用的Python编程》04_02_Inheritance

继承(inheritance)是编写可扩展程序程序的常用手段。本节对继承的思想(idea)进行探讨。

简介

继承用于特殊化现有对象:

class Parent: ... class Child(Parent): ...

新类 Child 称为派生类(derived class)或子类(subclass)。类 Parent 称为基类(base class)或超类(superclass)。在子类名后的括号 () 中指定基类(Parent),class Child(Parent):。

扩展

使用继承,你可以获取现有的类,并且可以:

添加新方法

重新定义现有方法

向实例添加新属性

最后,你扩展了现有代码

示例

假设这是开始的类:

class Stock: def __init__(self, name, shares, price): self.name = name self.shares = shares self.price = price def cost(self): return self.shares * self.price def sell(self, nshares): self.shares -= nshares

你可以通过继承更改 Stock 类的任何部分。

添加新方法 class MyStock(Stock): def panic(self): self.sell(self.shares)

(译注:“panic” 在这里表示的是“panic selling”,恐慌性抛售)

使用示例:

>>> s = MyStock('GOOG', 100, 490.1) >>> s.sell(25) >>> s.shares 75 >>> s.panic() >>> s.shares 0 >>> 重新定义现有方法 class MyStock(Stock): def cost(self): return 1.25 * self.shares * self.price

使用示例:

>>> s = MyStock('GOOG', 100, 490.1) >>> s.cost() 61262.5 >>>

新的 cost() 方法代替了旧的 cost() 方法。其它的方法不受影响。

方法覆盖

有时候,一个类既想扩展现有方法,同时又想在新的定义中使用原有的实现。为此,可以使用 super() 函数实现(译注:方法覆盖 有时也译为 方法重写):

class Stock: ... def cost(self): return self.shares * self.price ... class MyStock(Stock): def cost(self): # Check the call to `super` actual_cost = super().cost() return 1.25 * actual_cost

使用内置函数 super() 调用之前的版本。

注意:在 Python 2 中,语法更加冗余,像下面这样:

actual_cost = super(MyStock, self).cost() __init__ 和继承

如果 __init__ 方法在子类中被重新定义,那么有必要初始化父类。

class Stock: def __init__(self, name, shares, price): self.name = name self.shares = shares self.price = price class MyStock(Stock): def __init__(self, name, shares, price, factor): # Check the call to `super` and `__init__` super().__init__(name, shares, price) self.factor = factor def cost(self): return self.factor * super().cost()

你需要使用 super 调用父类的 __init__() 方法,如前所示,这是调用先前版本的方法。

使用继承

有时候,继承用于组织相关的对象。

class Shape: ... class Circle(Shape): ... class Rectangle(Shape): ...

要组织相关的对象,可以考虑使用逻辑层次结构或者进行分类。然而,一种更常见(更实用)的做法是创建可重用和可扩展的代码。例如,一个框架可能会定义一个基类,并指导你对其进行自定义。

class CustomHandler(TCPHandler): def handle_request(self): ... # Custom processing

基类包含了通用代码。你的类继承基类并自定义特殊的部分。

“is a” 关系

继承建立了一种类型关系。

class Shape: ... class Circle(Shape): ...

检查对象实例:

>>> c = Circle(4.0) >>> isinstance(c, Shape) True >>>

重要提示:理想情况下,任何使用父类实例能正常工作的代码也能使用子类的实例正常工作。

object 基类

如果一个类没有父类,那么有时候你会看到它们使用 object 作为基类。

class Shape(object): ...

Python 中,object 是所有对象的基类。

注意:在技术上,它不是必需的,但是你通常会看到 object 在 Python 2 中被保留。如果省略,类仍然隐式继承自 object。

多重继承

你可以通过在类定义中指定多个基类来实现多重继承。

class Mother: ... class Father: ... class Child(Mother, Father): ...

Child 类继承了两个父类(Mother,Father)的特性。这里有一些相当棘手的细节。除非你知道你正在做什么,否则不要这样做。虽然更多信息会在下一节给到,但是我们不会在本课程中进一步使用多重继承。

练习

继承的一个主要用途是:以各种方式编写可扩展和可定制的代码——尤其是在库或框架中。要说明这点,请考虑 report.py 程序中的 print_report() 函数。它看起来应该像下面这样:

def print_report(reportdata): ''' Print a nicely formated table from a list of (name, shares, price, change) tuples. ''' headers = ('Name','Shares','Price','Change') print('%10s %10s %10s %10s' % headers) print(('-'*10 + ' ')*len(headers)) for row in reportdata: print('%10s %10d %10.2f %10.2f' % row)

当运行 report.py 程序,你应该会获得像下面这样的输出:

>>> import report >>> report.portfolio_report('Data/portfolio.csv', 'Data/prices.csv') Name Shares Price Change ---------- ---------- ---------- ---------- AA 100 9.22 -22.98 IBM 50 106.28 15.18 CAT 150 35.46 -47.98 MSFT 200 20.89 -30.34 GE 95 13.48 -26.89 MSFT 50 20.89 -44.21 IBM 100 106.28 35.84 练习 4.5:扩展性问题

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsxdfw.html