第九章 面向?qū)ο?4
9.2繼承與多態(tài)
面向?qū)ο缶幊痰闹饕獌?yōu)點是面向?qū)ο缶幊谭先祟惖乃季S習(xí)慣;代碼可維護(hù)性高,封裝可以確保只能使用類允許公開的數(shù)據(jù);還有一個重要的是代碼復(fù)用,代碼復(fù)用主要通過繼承機(jī)制實現(xiàn)的。還記得前面我們留下的一個問題嗎?
class Person(object):# object這個問題下一節(jié)解釋(9.2繼承與多態(tài))
這里我們多加了一個object,因為Python規(guī)定所有的類如果不特殊指定,都繼承自object類,所以我們之前定義的類括號里什么都沒寫,跟這里寫了object的是一樣的,都是表示類繼承自object。通過繼承創(chuàng)建的新類稱為子類或派生類,被繼承的類稱為父類、基類或超類。所以Person類是子類,object類是父類,而且object類是所有類的父類。object類定義了多種“魔法”方法,就是名字是__xxxx__()的方法,這類方法具有特殊的功能,如我們學(xué)過的__init__方法。除此之外還有__del__,__str__,__new__,__eq__等等。下面通過舉例簡單介紹一下繼承概念。
首先定義一個Shape類,在此基礎(chǔ)上派生出Circle類和Triangle類。Shape形狀類具有求周長求面積的方法,這個例子需要深入理解。
import math
class Shape():
??? def __init__(self,name="shape",color="black",isFilled=True):
??????? self.name=name
??????? self.color = color
??????? self.isFilled = isFilled
??????? print("Shape __init__")
?
??? def __del__(self):
??????? print("Shape __del__")
?
??? def __str__(self):
??????? return "Shape? name:"+self.name+" color:"+self.color+" isFilled:"+str(self.isFilled)
?
??? def getArea(self):
??????? return 0
?
??? def getPerimeter(self):
??????? return 0
?
class Circle(Shape):
??? # Construct a circle object
??? def __init__(self, radius=1):
??????? super().__init__()? #調(diào)用父類__init__()方法
??????? self.radius = radius
??????? print("Circle __init__")
?
??? def __del__(self):???? #覆蓋父類__del__()方法
??????? print("Circle __del__")
?
??? def __str__(self):???? #覆蓋父類__str__()方法
??????? return "Circle? name:" + self.name + " radius:" +str(self.radius) + " color:" + self.color + " isFilled:" + str(self.isFilled)
?
??? def getPerimeter(self):
??????? return 2 * self.radius * math.pi
?
??? def getArea(self):
??????? return self.radius * self.radius * math.pi
?
??? def setRadius(self, radius):
??????? self.radius = radius
?
class Triangle(Shape):
??? # Construct a triangle object
??? def __init__(self, s1=1, s2=1, s3=1):
??????? super().__init__()
??????? self.side1 = s1
??????? self.side2 = s2
??????? self.side3 = s3
??????? print("Circle __init__")
?
??? def __del__(self):
??????? print("Triangle __del__")
?
??? def __str__(self):
??????? return "Triangle? name:" + self.name + " side1:" + str(self.side1) \
?????????????? + " side2:" + str(self.side2)+ " side3:" + str(self.side3)+ \
?????????????? " color:" + self.color + " isFilled:" + str(self.isFilled)
?
??? def getPerimeter(self):
??????? return self.side1+self.side2+self.side3
?
??? def getArea(self):
??????? #海倫公式
??????? p=self.getPerimeter()/2
??????? s=math.sqrt(p*(p-self.side1)*(p-self.side2)*(p-self.side3))
??????? return s
?
?
def main():
??? c=Circle(2)
??? print(c)? #顯示__str__方法返回值
??? print("圓的周長和面積為:",format(c.getPerimeter(),".2f"),format(c.getArea(),".2f"))
?
??? t = Triangle(3, 4, 5)
??? print(t)? #顯示__str__方法返回值
??? print("三角形的周長和面積為:",t.getPerimeter(),t.getArea())
??? print("the end!")
main()
?
運(yùn)行結(jié)果如下:
Shape __init__
Circle __init__
Circle? name:shape radius:2 color:black isFilled:True
圓的周長和面積為: 12.57 12.57
Shape __init__
Circle __init__
Triangle? name:shape side1:3 side2:4 side3:5 color:black isFilled:True
三角形的周長和面積為: 12 6.0
the end!
Circle __del__
Triangle __del__
?
下面我們看一下多態(tài),類的多態(tài)特性要滿足以下 2 個前提條件:
繼承:多態(tài)一定是發(fā)生在子類和父類之間;
重寫:子類重寫了父類的方法。
上面我們在子類中寫了__init__,__del__和__str__,子類對象調(diào)用時,只調(diào)用了自己的方法,父類的同名方法被覆蓋。再看下面的例子加深一下理解。
def say(someone):
??????? someone.say()
?
class Animal:
??? def say(self):
??????? print("動物怎么叫?")
?
class Cat():
??? def say(self):
??????? print("喵喵喵...喵喵喵...")
?
class Dog():
??? def say(self):
??????? print("汪汪汪...汪汪汪...")
?
class Sheep():
??? def say(self):
??????? print("咩咩咩...咩咩咩...")
?
say(Animal())
say(Cat())
say(Dog())
say(Sheep())
?
運(yùn)行結(jié)果如下:
動物怎么叫?
喵喵喵...喵喵喵...
汪汪汪...汪汪汪...
咩咩咩...咩咩咩...
?
此程序中,通過給函數(shù)say()添加一個 someone參數(shù),其內(nèi)部利用傳入的 someone調(diào)用 say() 方法。這意味著,當(dāng)調(diào)用say() 函數(shù)時,我們傳給 someone參數(shù)的是哪個類的實例對象,它就會調(diào)用那個類中的 say() 方法。
下面再看一個繼承和多態(tài)的綜合例子,最后一個例子了!
class Person(object):
??? def __init__(self, name, gender):
??????? self.name = name
??????? self.gender = gender
?
??? def whoAmI(self):
??????? return 'I am a Person, my name is %s' % self.name
?
class Student(Person):
??? def __init__(self, name, gender, score):
??????? super(Student, self).__init__(name, gender)
??????? self.score = score
?
??? def whoAmI(self):
??????? return 'I am a Student, my name is %s' % self.name
?
class Teacher(Person):
??? def __init__(self, name, gender, course):
??????? super().__init__(name, gender)
??????? self.course = course
?
??? def whoAmI(self):
??????? return 'I am a Teacher, my name is %s' % self.name
?
'''
在一個函數(shù)中,如果我們接收一個變量 x,則無論該 x 是 Person、Student還是 Teacher,都可以正確打印出結(jié)果:
'''
?
def who_am_i(x):
??? print(x.whoAmI())
?
p = Person('Dan Gutman', 'Male')
s = Student('A.J.', 'Male', 68)
t = Teacher('Daisy', 'Female', 'English')
?
who_am_i(p)
who_am_i(s)
who_am_i(t)
?
運(yùn)行結(jié)果如下:
I am a Person, my name is Dan Gutman
I am a Student, my name is A.J.
I am a Teacher, my name is Daisy