2.8 面向对象编程
面向对象编程是最有效的软件编写方法之一。在面向对象编程中,首先编写表示现实世界中的事物和情景的类,并基于这些类来创建对象。在编写类时,往往要定义一大类对象都有的通用行为。基于类创建对象时,每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性。
根据类来创建对象被称为实例化,实例化是面向对象编程不可或缺的一部分。在本节中,将会编写一些类并创建其实例。理解面向对象编程有助于我们像程序员那样看世界,还可以帮助我们真正明白自己编写的代码。了解类背后的概念可培养逻辑思维,让我们能够通过编写程序来解决遇到的几乎任何问题。
2.8.1 类与对象
类是一种广义的数据,这种数据类型的元素既包含数据,也包含操作数据的函数。
1.类的创建
在Python中,我们通过class关键字来创建类。类的格式一般如下:
class 类名: 类体
类一般由类头和类体两部分组成。类头由关键字class开头,后面紧跟着类名,类体包括所有细节,向右缩进对齐。
下面来编写一个表示小狗的简单类Dog。它表示的不是特定的小狗,而是任何小狗。对于小狗来说,它们都有名字和年龄;我们还知道,大多数小狗还会蹲下和打滚。由于大多数小狗都具备上述两项信息和两种行为,Dog类将包含它们。编写这个类后,我们将使用它来创建表示特定小狗的实例。
【例2-18】Dog类创建。
class Dog(): def __init__(self, name, age): # 初始化Dog类 self.name = name self.age = age def sit(self): # 定义类方法 print(self.name.title() + " is now sitting.") def roll_over(self): # 定义类方法 print(self.name.title() + " rolled over!")
根据Dog类创建的每个实例都将存储狗的名字和年龄。我们赋予了每条小狗蹲下sit()和打滚roll_over()的能力。
类中的函数称为方法,之前或今后学过的方法都适用于它。__init__()是一个特殊的方法,每当根据Dog类创建新实例时,Python都会自动运行它。
2.类的使用(实例化)
我们可将类视为有关如何创建实例的说明。例如:Dog类是一系列说明,让Python知道如何创建表示特定小狗的实例。下面我们根据Dog类创建一个实例。
紧接着例2-18,建立Dog类的实例化。
my_dog = Dog('wangcai', 6) print("My dog's name is " + my_dog.name.title()) print("My dog is " + str(my_dog.age) + " years old.")
程序运行结果如图2-26所示。
图2-26 Dog类实例化显示结果
3.属性和方法的访问
要访问实例的属性和方法,可使用句点表示法。例如:
my_dog.name my_dog.age
这两句代码可以访问Dog类中定义的name和age属性。
根据Dog类创建实例后,就可以使用句点表示法来调用Dog类中定义的任何方法。例如:
my_dog = Dog('wangcai', 6) my_dog.sit() my_dog.roll_over()
后两句代码可以访问Dog类中定义的sit和roll_over方法。
2.8.2 继承与多态
继承与多态是类的特点之一。我们在前一节简单介绍了类的创建和简单使用,下面继续介绍类的继承与多态。
1.继承
如果我们要编写的类是另一个现成类的特殊版本,可使用继承的方法。一个类继承另一个类时,它将自动获得另一个类的所有属性和方法。原有的类称为父类,新创建的类称为子类。子类除了继承父类的属性和方法以外,也有自己的属性和方法。
在Python中定义继承的一般格式为:
class 子类名(父类名): 类体
【例2-19】类的继承实例演示。
以学校成员为例,定义一个父类SchoolMember,然后定义子类Teacher和Student继承SchoolMember。
程序代码如下:
class SchoolMember(object): # 定义一个父类 '''学校成员父类''' member = 0 # 定义一个变量记录成员的数目 def __init__(self, name, age, sex):# 初始化父类的属性 self.name = name self.age = age self.sex = sex self.enroll() def enroll(self): # 定义一个父类方法,用于注册成员 '注册成员信息' print('just enrolled a new school member [%s].' % self.name) SchoolMember.member += 1 def tell(self): # 定义一个父类方法,用于输出新增成员的基本信息 print('----%s----' % self.name) for k, v in self.__dict__.items(): # 使用字典保存信息 print(k, v) print('----end-----') # 分隔线 def __del__(self): # 删除成员 print('开除了[%s]' % self.name) SchoolMember.member -= 1 class Teacher(SchoolMember): # 定义一个子类,继承SchoolMember类 '教师信息' def __init__(self, name, age, sex, salary, course): SchoolMember.__init__(self, name, age, sex)# 继承父类的属性 self.salary = salary self.course = course # 定义子类自身的属性 def teaching(self): # 定义子类的方法 print('Teacher [%s] is teaching [%s]' % (self.name, self.course)) class Student(SchoolMember): # 定义一个子类,继承SchoolMember类 '学生信息' def __init__(self, name, age, sex, course, tuition): SchoolMember.__init__(self, name, age, sex)# 继承父类的属性 self.course = course # 定义子类自身的属性 self.tuition = tuition self.amount = 0 def pay_tuition(self, amount): # 定义子类的方法 print('student [%s] has just paied [%s]' % (self.name, amount)) self.amount += amount # 实例化对象 t1 = Teacher('Mike', 48, 'M', 8000, 'python') t1.tell() s1 = Student('Joe', 18, 'M', 'python', 5000) s1.tell() s2 = Student('LiHua', 16, 'M', 'python', 5000) print(SchoolMember.member) # 输出此时父类中的成员数目 del s2 # 删除对象 print(SchoolMember.member) # 输出此时父类中的成员数目
程序的输出结果如图2-27所示。
图2-27 类的继承显示结果
2.多态
多态是指不同的对象收到同一种消息时产生的不同的行为。在Python中,消息就是指函数的调用,不同的行为是指执行不同的函数。
【例2-20】多态程序实例。
class Animal(object): # 定义一个父类Animal def __init__(self, name): # 初始化父类属性 self.name = name def talk(self): # 定义父类方法,抽象方法,由具体而定 pass class Cat(Animal): # 定义一个子类,继承父类Animal def talk(self): # 继承重构类方法 print('%s: 喵!喵!喵!' % self.name) class Dog(Animal): # 定义一个子类,继承父类Animal def talk(self): # 继承重构类方法 print('%s: 汪!汪!汪!' % self.name) def func(obj): # 一个接口,多种形态 obj.talk() # 实例化对象 c1 = Cat('Tom') d1 = Dog('wangcai') func(c1) func(d1)
程序运算结果如图2-28所示。
图2-28 多态显示结果
在上面的程序中,Animal类和两个子类中都有talk()方法,虽然同名,但是在每个类中所调用的函数是不一样的。当调用该方法时,所得结果取决于不同的对象。同样的信息在不同的对象下所得的结果不同,这就是多态的体现。