第九章 面向对象-4
9.2继承与多态
面向对象编程的主要优点是面向对象编程符合人类的思维习惯;代码可维护性高,封装可以确保只能使用类允许公开的数据;还有一个重要的是代码复用,代码复用主要通过继承机制实现的。还记得前面我们留下的一个问题吗?
class Person(object):# object这个问题下一节解释(9.2继承与多态)
这里我们多加了一个object,因为Python规定所有的类如果不特殊指定,都继承自object类,所以我们之前定义的类括号里什么都没写,跟这里写了object的是一样的,都是表示类继承自object。通过继承创建的新类称为子类或派生类,被继承的类称为父类、基类或超类。所以Person类是子类,object类是父类,而且object类是所有类的父类。object类定义了多种“魔法”方法,就是名字是__xxxx__()的方法,这类方法具有特殊的功能,如我们学过的__init__方法。除此之外还有__del__,__str__,__new__,__eq__等等。下面通过举例简单介绍一下继承概念。
首先定义一个Shape类,在此基础上派生出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__() #调用父类__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()
运行结果如下:
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__
下面我们看一下多态,类的多态特性要满足以下 2 个前提条件:
继承:多态一定是发生在子类和父类之间;
重写:子类重写了父类的方法。
上面我们在子类中写了__init__,__del__和__str__,子类对象调用时,只调用了自己的方法,父类的同名方法被覆盖。再看下面的例子加深一下理解。
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())
运行结果如下:
动物怎么叫?
喵喵喵...喵喵喵...
汪汪汪...汪汪汪...
咩咩咩...咩咩咩...
此程序中,通过给函数say()添加一个 someone参数,其内部利用传入的 someone调用 say() 方法。这意味着,当调用say() 函数时,我们传给 someone参数的是哪个类的实例对象,它就会调用那个类中的 say() 方法。
下面再看一个继承和多态的综合例子,最后一个例子了!
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
'''
在一个函数中,如果我们接收一个变量 x,则无论该 x 是 Person、Student还是 Teacher,都可以正确打印出结果:
'''
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)
运行结果如下:
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