·类(2)
@ 继承(inheritance)
什么是继承:编程
B继承A:A是父类(超类),B是子类(基类)。继承能够实现代码重复利用,实现属性和方法继承。函数
继承可使子类拥有父类的属性和方法,也能够从新定义某些属性、重写某些方法,即覆盖父类原有的属性和方法,使其得到父类不一样的功能。固然,也能够在子类中新设置属性和方法。从技术上看,OOP里继承最主要的用途是实现多态,对于多态而言,最重要的是接口的继承性(属性和方法是否存在继承性),这是不必定的。继承也不是全为了代码的重复利用,而是为了理顺关系。post
对于 Python 中的继承,前面一直在使用,那就是咱们写的类都是新式类,全部新式类都是继承自 object 类。不要忘记,新式类的一种写法:spa
class NewStyle(object): pass
这就是典型的继承。code
继承的基本概念:orm
class Person: def __init__(self,name): self.name = name def get_name(self): print ("hello,{}!".format(self.name)) def setHeight(self, n): self.length = n def breast(self, n): print ("My breast is: ",n) class Boy(Person): def setHeight(self): print ("The height is:1.80m .") j = Boy('jimmy') j.get_name() j.setHeight() j.breast(90) 打印结果: hello,jimmy! The height is:1.80m . My breast is: 90
首先,定义了一个父类 Person,定义一个子类 Boy,Boy类的括号中是Person,这就意味着 Boy 继承了 Person,Boy 是 Person 的子类,Person 是 Boy 的父类。那么 Boy 就所有拥有了 Person 中的方法和属性。blog
若是 Boy 里面有一个和 Person 一样名称的方法,那么就把 Person 中的同一个方法遮盖住了,显示的是 Boy 中的方法,这叫作方法的重写。实例化类 Boy以后,执行实例方法 j.setHeight(),因为在类 Boy中重写了 setHeight 方法,那么 Person 中的那个方法就不显做用了,在这个实例方法中执行的是类 Boy 中的方法。继承
虽然在类 Boy 中没有看到 get_name() 方法,可是由于它继承了 Person,因此 j.get_name() 就执行类 Person 中的方法。同理 j.breast(90) ,它们就好像是在类 Boy 里面已经写了这两个方法同样。既然继承了,就可使用。接口
多重继承:get
子类继承多个父类:
class Person: def eye(self): print("two eyss") def breast(self,n): print("the breast is:",n) class Girl: age = 18 def color(self): print("the girl is white.") class HotGirl(Person,Girl): pass
在类的名字后面的括号中把所继承的两个类的名字写上,HotGirl 就继承了Person 和 Girl这两个类。实例化类 HotGirl,既然继承了上面的两个类,那么那两个类的方法就都可以拿过来使用。在类 Girl 中, age = 28,在对 HotGirl 实例化以后,由于继承的缘由,这个类属性也被继承到 HotGirl 中,所以经过实例获得它。
继承的特色,即将父类的方法和属性所有承接到子类中;若是子类重写了父类的方法,就使用子类的该方法,父类的被遮盖。
多重继承的顺序:
若是一个子类继承了两个父类,而且两个父类有一样的方法或者属性,那么在实例化子类后,调用那个方法或属性,是属于哪一个父类的呢?造一个没有实际意义,纯粹为了解决这个问题的程序:
class K1(object): def foo(self): print("K1-foo") class K2(object): def foo(self): print("K2-foo") def bar(self): print("K2-bar") class J1(K1, K2): pass class J2(K1, K2): def bar(self): print("J2-bar") class C(J1, J2): pass print(C.__mro__) m = C() m.foo() m.bar() 打印结果: (<class '__main__.C'>, <class '__main__.J1'>, <class '__main__.J2'>, <class '__main__.K1'>, <class '__main__.K2'>, <class 'object'>) K1-foo J2-bar
print C.__mro__打印出类的继承顺序。
从上面清晰看出来了,若是要执行 foo() 方法,首先看 J1,没有,看 J2,尚未,看 J1 里面的 K1,有了,即 C(没有)==>J1(没有)==>J2(没有)==>K1(找到了);bar() 也是按照这个顺序,在 J2 中就找到了一个。
这种对继承属性和方法搜索的顺序称之为“广度优先”。新式类用以及 Python3.x 中都是按照此顺序原则搜寻属性和方法的。
可是,在旧式类中,是按照“深度优先”的顺序的。由于后面读者也基本不用旧式类,因此不举例。
@ super函数
对于初始化函数的继承,跟通常方法的继承不一样:
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): 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)) cang = Girl() cang.about("wangguniang")
打印结果:
Traceback (most recent call last):
File "test1.py", line 14, in <module>
cang.about("wangguniang")
File "test1.py", line 11, in about
print("{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast))
AttributeError: 'Girl' object has no attribute 'height'
在上面这段程序中,类 Girl 继承了类 Person。在类 Girl 中,初始化设置了 self.breast = 90,因为继承了 Person,按照前面的经验,Person 的初始化函数中的 self.height = 160 也应该被 Girl 所继承过来。而后在重写的 about 方法中,就是用 self.height。
实例化类 Girl,并执行 cang.about("wangguniang"),试图打印出一句话 wangguniang is a hot girl, she is about 160, and her bereast is 90。保存程序,运行报错!
信息显示 self.height 是不存在的。也就是说类 Girl 没有从 Person 中继承过来这个属性。
在 Girl中发现, about 方法重写了,__init__方法,也被重写了。它跟类 Person 中的__init__重名了,也一样是重写了那个初始化函数。这是由于在子类中重写了某个方法以后,父类中一样的方法被遮盖了。
使用super 函数:
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().__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)) cang = Girl() cang.about("wangguniang") 打印结果: wangguniang is a hot girl, she is about 160, and her breast is 90
在子类中,__init__方法重写了,为了调用父类同方法,使用 super(Girl, self).__init__()的方式。super 函数的参数,第一个是当前子类的类名字,第二个是 self,而后是点号,点号后面是所要调用的父类的方法。一样在子类重写的 about 方法中,也能够调用父类的 about 方法。
最后要提醒注意:super 函数仅仅适用于新式类。
@ 绑定方法与非绑定方法
要经过实例来调用类的方法(函数),常常要将类实例化。方法是类内部定义函数,只不过这个函数的第一个参数是 self。(能够认为方法是类属性,但不是实例属性)。必须将类实例化以后,才能经过实例调用该类的方法。调用的时候在方法后面要跟括号(括号中默认有 self 参数,能够不写出来)。经过实例调用方法,称这个方法绑定在实例上。