首页 > 程序开发 > Web开发 > Python >

Learn Python The Hard Way学习(44) - 继承还是组成?

2012-07-10

balabala...讲了一个故事,就不翻译了。只要记着:我们要尽量简单的使用继承,或者用组合代替继承,而且做好不要使用多继承。什么是继承?继承被用来指明一个类可以从它的父类取得大部分或者全部的特征。当你写c...

balabala...讲了一个故事,就不翻译了。

只要记着:我们要尽量简单的使用继承,或者用组合代替继承,而且做好不要使用多继承。

什么是继承?
继承被用来指明一个类可以从它的父类取得大部分或者全部的特征。当你写class Foo(Bar)的时候,继承就发生了。Foo类的实例和Bar类的实例一样工作。继承就是为了你能再Bar类中定义普通的方法,而在Foo类中定义特殊的方法。

当做了继承后,父类和子类有三个相互影响的方法:
子类的动作暗含了父类的动作
子类的动作覆盖了相应的父类动作
子类的动作改变了相应的父类动作
暗含继承
先在父类定义一个implicit函数,子类什么也不做。
[python]
class Parent(object):


def implicit(self):
print "parent implicit()"


class Child(Parent):
pass


dad = Parent()
son = Child()
dad.implicit()
son.implicit()


在子类中使用pass就是告诉python,这里是一个空的代码块。就是说子类完全继承父类的特征。运行代码的结果如下:
parent implicit()
parent implicit()

注意,我调用了son.implicit()在16行,但是子类并没有这个方法,它调用了父类的对应方法执行。这里告诉你,子类会自动取得父类的所有特征,不需要重复编写代码。

覆盖暗含
问题是有时候你希望子类继承的函数有不同的提现,解决办法就是覆盖父类的函数,定义一个同名的函数在子类中,代码如下:
[python]
class Parent(object):


def override(self):
print "parent override()"


class Child(Parent):


def override(self):
print "child override()"


dad = Parent()
son = Child()
dad.override()
son.override()


运行效果如下:
parent override()
child override()

正如你看到的,子类运行相应的函数的时候会运行覆盖过的函数,相当于子类的新版本。

改变之前或者之后
改变和覆盖有一些区别,我们需要先覆盖父类的函数,然后再通过super调用父类的函数,在调用的前后可以添加其他方法,例如如下:
[python] view plaincopy
class Parent(object):


def altered(self):
print "parent altered()"


class Child(Parent):


def altered(self):
print "child, before parent altered()"
super(Child, self).altered()
print "child, after parent altered()"


dad = Parent()
son = Child()
dad.altered()
son.altered()


第9和11行比较重要,当我调用son.altered()的时候做了下面这些事情:
因为我已经覆盖了父类的函数altered,所以第9行会在子类调用altered的时候执行。
我希望在第9行后执行父类的altered,所以我使用了super。
在第10行我调用super(child, self).altered(),有点像不久前使用的getattr函数,不过这里是从继承的父类那里调用函数。
然后,父类的函数运行,并打印信息。
最后,从父类函数返回,继续运行剩下的子类的语句。
运行结果如下:
parent altered()
child, before parent altered()
parent altered()
child, after parent altered()

混合使用三个方法
[python] view plaincopy
class Parent(object):


def implicit(self):
print "parent implicit()"


def override(self):
print "parent override()"


def altered(self):
print "parent altered()"


class Child(Parent):


def override(self):
print "child override()"


def altered(self):
print "child, before parent altered()"
super(Child, self).altered()
print "child, after parent altered()"


dad = Parent()
son = Child()
dad.implicit()
son.implicit()
dad.override()
son.override()
dad.altered()
son.altered()


给代码加上注释,区别这三种方式,运行如下:
parent implicit()
parent implicit()
parent override()
child override()
parent altered()
child, before parent altered()
parent altered()
child, after parent altered()

使用super()的理由
现在有个麻烦,就是多重继承,意思是一个类继承了多个类,像下面这样:
class SuperFun(Child, BadStuff):
pass

就像是说:”创建一个SuperFun,同时继承Child和BadStuff类。

这样的话,当SuperFun实例有隐含的动作的时候,python需要去两个类中取寻找,这就必须有一定的顺序。Python使用一个叫“Method Resolution Order”(MRO)和C3算法实现。

由于MRO很复杂,Python不可能让你直接使用它,所以给了一个super方法让你调用,使用后python会自动实现内部的调用。

在__init__中使用super()
通常super()都是在__init__中使用的,完成父类的初始化,下面是一个例子:
class Child(Parent):
def __init__(self, stuff):
self.stuff = stuff
super(Child, self).__init__()

组成
继承很有用,但是另外一个方法可以使用类和模块最相同的事情,而不依赖隐含继承。下面这种方法可以简单的实现上面那三种方式。看例子:
[python]
class Other(object):
def override(self):
print "other override()"


def implicit(self):
print "other implicit()"


def altered(self):
print "other altered()"


class Child(object):
def __init__(self):
self.other = Other()


def implicit(self):
self.other.implicit()


def override(self):
print "child override()"


def altered(self):
print "child, before other altered()"
self.other.altered()
print "child, after other altered()"


son = Child()
son.implicit()
son.override()
son.altered()


上面的代码我没有用Parent,以免产生is-a关系的误解,运行如下:
other implicit()
child override()
child, before other altered()
other altered()
child, after other altered()

你可以看到上面的代码完成了相同的功能。唯一不同的是我必须定义一个Child.implicit的函数。现在我可以说,我需要Other类的话,只要把它写到other.py文件中,然后通过模块调用就好了。

什么时候用继承,什么时候用组合
不管是继承还是组合,都是为了解决问题,继承可以让你继承父类的特征,组合可以让你简单的从其他类中调用函数。

他们都是解决重复使用的问题,到底用哪一个合适呢?这个问题是很主观的,不管我给出了我自己的三条规则:
不要使用多重继承,它太复杂了。一定要用的话,必须清楚的了解它。
使用组合打包你的代码,它可以在其他无关的地方使用你打包好的模块。
在非常明确的复用代码情况下才使用继承。
不管怎么样,不要墨守成规,你可以在工作中和同事制定你们自己的规则,能很好的解决问题就可以了。

加分练习
这里只有一个加分练习,因为这个练习比较大,去看看http://www.python.org/dev/peps/pep-0008/ 并且用到你的代码中。你会发现和我们书上说的不太一样,不过现在你必须去理解它的描述并且用到你的代码中。用了以后可能会让代码有点混乱,不过你必须理解它的重要性,这是一种好的规范。
作者:lixiang0522

相关文章
最新文章
热点推荐