何为继承
- 在现实生活中,继承,意味着一个人从另外一个人那里得到了某些东西,比如优秀的品质或者万贯的家财。
- 在编程中,继承相对来说是有明确规定和预期结果的。类别A继承制类别B,那么A称之为子类,B称之为父类或者超类。
继承使得子类拥有父类的非私有方法和属性,子类中可以不用写重复的代码。而子类继承父类的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类原有的属性很方法,使其获得与父类不同的功能。子类可以有属于自己的属性和方法。
继承的意图和好处
- 可以实现代码重用,但不仅仅只是重用,有时根本就没有重用。
- 实现属性、方法的继承
从技术上说,OOP 里,继承最主要的用途是实现多态。对于多态而言,重要的是接口继承性,属性和行为是否存在继承性,这是不一定的。事实上,大量工程实践表明,重度的行为继承会导致系统过度复杂和臃肿,反而会降低灵活性。因此现在比较提倡的是基于接口的轻度继承理念。这种模型里因为父类(接口类)完全没有代码,因此根本谈不上什么代码复用了。
在 Python 里,因为存在 Duck Type,接口定义的重要性大大的降低,继承的作用也进一步的被削弱了。
另外,从逻辑上说,继承的目的也不是为了复用代码,而是为了理顺关系。
例子:
代码:
>>> class Person:
... def setName(self,n):
... print "my name is:",n
... def sayHello(self):
... print "hello word"
... def setAge(self,n):
... print "my age is:",n
...
>>> class Boy(Person):
... def setName(self):
... print "the name is : wxx"
... def setHeight(self):
... print "the height is 175"
...
>>> boy = Boy()
>>> boy.setName()
the name is : wxx
>>> boy.sayHello()
hello word
>>> boy.setAge(23)
my age is: 23
>>> boy.setHeight()
the height is 175
说明:
- 定义一个Person类,类中定义了三个方法,而且没有初始化函数,初始化函数在类中并不是不可或缺的。
- 又定义了一个Boy类,继承自Person类。因此,Boy是Person的子类,Person是Boy的父类。
- 在Boy中,拥有了父类Person的三个方法,因此实例化之后可以调用父类的方法。setName(self) 则是方法的重写。setName()则是子类自己的方法。
多重继承
即父类不止一个。
>>> class AA(object):
... def ADef(self):
... print "AA ADef"
...
>>> class BB(object):
... def BDef(self):
... print "BB BDef"
...
>>> class CC(AA,BB):
... pass
...
>>> cc = CC() #实例化CC类
>>> cc.ADef()
AA ADef
>>> cc.BDef()
BB BDef
>>>
多重继承的顺序
如果一个子类继承自两个父类,而两个父类中拥有相同的方法或属性,子类会调用谁的?
举个例子:
>>> class K1(object):
... def foo(self):
... print "K1-foo"
...
>>> class K2(object):
... def foo(self):
... print "K2-foo"
... def mod(self):
... print "K2-mod"
...
>>> class J1(K1,K2):
... pass
...
>>> class J2(K1,K2):
... def mod(self):
... print "J2-mod"
...
>>> class C(J1,J2):
... pass
...
>>> c = C()
>>> c.foo()
K1-foo
>>> c.mod()
J2-mod
从以上例子可以看出,实例化C()后,调用foo(),查找foo()的书顺序是:C -> J1 -> J2 ->K1;
而调用mod(),查找mod()的顺序是:C -> J1 -> J2。
以上这种继承的属性和方法的查找方式称之为“广度优先”。
super
例子
#!/usr/bin/env python
# coding=utf-8
__metaclass__ = type
class Person:
def __init__(self):
self.height = 160
def about(self, name):
print "{} is about {}".format(name, self.height)
class Girl(Person):
def __init__(self):
super(Girl, self).__init__()
self.breast = 90
def about(self, name):
print "{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)
super(Girl, self).about(name)
if __name__ == "__main__":
cang = Girl()
cang.about("wangguniang")
在子类中,init方法重写了,为了调用父类同方法,使用 super(Girl, self).init()的方式。super 函数的参数,第一个是当前子类的类名字,第二个是 self,然后是点号,点号后面是所要调用的父类的方法。同样在子类重写的 about 方法中,也可以调用父类的 about 方法。
执行结果:
$ python 20903.py
wangguniang is a hot girl, she is about 160, and her breast is 90
wangguniang is about 160
最后要提醒注意:super 函数仅仅适用于新式类。当然,你一定是使用的新式类。“喜新厌旧”是程序员的嗜好。