面向对象编程的学习
一、定义
首先跟大家介绍一位资深的程序员前辈说过的编程心得:
1、写重复代码是非常不好且低级的行为
2、完成的代码需要经常变更
所以根据以上两个心得,我们可以知道写的代码一定要遵循易读、易改的原则(可读性好、易扩展),这样的话面向对象编程是一个非常好的选择。
面向对象编程是最有效的软件编写方法之一。在面向对象编程中,你编写表示现实世界中的事物和情景的类,并基于这些类来创建对象。编写类时,你定义一大类对象都有的通用行为。基于类创建对象时,每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性。使用面向对象编程可模拟现实情境,其可达到非常高的逼真程度。
根据类来创建对象被称为实例化,这让你能够使用类的示例。在今天的学习中,我将介绍如何编写类并创建其示例。你将指定可在实例中存储什么信息,定义可对这些实例执行哪些操作。
下面简单介绍一下面向过程编程与面向对象编程的区别:
面向过程编程即程序从上到下一步步执行,一步步从上到下,从头到尾解决问题。适合做一些一次性任务,通常是一些简单的脚本。
面向对象编程,即object-oriented programming(OOP),利用‘类’和‘对象’来创建各种模型来实现对真实世界的描述,易于维护和扩展,并可大大提高程序开发效率,更易理解。只要是对象,就肯定属于某种品类,就肯定有属性。
面向对象编程的有两个核心特征:
1、class类
一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性和共同的方法。
2、object对象
一个对象即是一个类的实例化后的实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性。就像‘人类’指的是所有人,每个人是指具体的对象,人与人之间有共性,亦有不同。
面向对象编程的有三个特性:
1、封装(Encapsulation)
在类中对数据的赋值、内部调用对外部用户是透明的,这种类变成了一个胶囊或容器,里面包含着类的数据和方法。
2、继承(Inheritance)
一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承。
3、多态(Polymorphism)
‘一个接口,多种实现’,指一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一事物表现出的多种形态。
二、面向对象示例
1、接下来我们创建一个简单的类来描述一种动物——狗,并创建一个类的方法——叫。文件名为dog.py,具体代码如下:
class Dog():
def __init__(self,name): #构造函数
'''初始化属性name'''
self.name = name def bulk(self):
'''模拟小狗叫'''
print('%s: wang!wang!wang!'%self.name) #创建两个实例d1,d2
d1 = Dog('Ali')
d2 = Dog('Bob') #访问实例的属性
print(d1.name)
print(d2.name) d1.bulk()
d2.bulk()
代码执行结果如下:
2、接下来,我们利用类方法来写一个简单的‘警察与小偷’程序,即创建一个警察角色和小偷角色,两人都有拥有购买和使用武器的功能。具体代码实现如下:
class Role(object):
def __init__(self,name,role,weapon,life_value=100,money=15000):
#构造函数
#在实例化时,做一些类的初始化的工作
self.name = name #实例变量(静态属性),作用域就是实例本身
self.role = role
self.weapon = weapon
self.life_value = life_value
self.money = money #开枪功能
def shot(self):
print("shooting...") #被击中
def got_shot(self):
self.life_value -= 50
print("%s:ah...,I got shot..."%(self.name)) #买枪功能
def buy_gun(self,gun_name):
print("%s just bought %s" %(self.name,gun_name)) #显示角色状态
def show_status(self):
print('name:%s,weapon:%s,life_value:%s'%(self.name,self.weapon,self.__life_value)) def __del__(self):
#析构函数
#在实例释放、销毁的时候执行的,通常用于做一些收尾工作,如关闭一些数据库链接,打开临时文件等。
print('%s 彻底死了。。。'%self.name) r1 = Role('Alex','police','AK47') #把一个类变成具体对象的过程称作实例化(初始化一个类,造了一个对象)
r1.buy_gun('ak47')
r1.got_shot()
r1.shot()
r1.show_status() r2 = Role('Jack','terrorist','B22') #生成一个角色
r2.got_shot()
代码执行结果如下:
在这里我们看到类Role最后的析构函数的作用就是在每次实例化完一个角色后,自动执行析构函数的内容 。
3、私有方法
通过私有方法我们可以把‘类’下的方法设为私有,即外部不可调用,我们还以类Dog为例,具体如下:
class Dog():
def __init__(self,name): #构造函数
'''初始化属性name'''
self.name = name def __bulk(self): #方法前加'__'即可把原方法设为私有化方法
'''模拟小狗叫'''
print('%s: wang!wang!wang!'%self.name) #创建两个实例d1,d2
d1 = Dog('Ali')
d2 = Dog('Bob') #访问实例的属性
print(d1.name)
print(d2.name) d1.__bulk()
d2.__bulk()
代码执行结果如下:
可以看到到后面并没有调用__bulk方法。
三、继承
编写类时,并非总要从空白开始。如果你要编写的类时另一个现成的特殊版本,可使用继承。一个类继承一个类时,它将自动获得另一个类的所有属性和方法。原有的类称为父类,而新类称为子类。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。
接下来我们以男人和女人同属人类为例编写一个简单的继承小程序,具体代码如下:
class People():
#创建‘人类’类
def __init__(self,name,age):
self.name = name
self.age = age
#‘吃’方法
def eat(self):
print('%s is eating'%self.name)
#‘睡’方法
def sleep(self):
print('%s is sleeping'%self.name) class Relation(object):
#创建‘交朋友’类
def make_friends(self,obj):
print('%s is making friends with %s'%(self.name,obj.name)) class Man(People,Relation):
#类‘Man’继承类‘People’和‘Relation’
def __init__(self,name,age,money):
super().__init__(name,age) #新式类
self.money=money #'money'为类‘Man’独有的属性
print('%s have %s money'%(self.name,self.money))
def smoke(self):
#'smoke'为类‘Man’独有的方法
print('%s is smoking'%self.name) def sleep(self):
People.sleep(self)
#在继承类‘People’的sleep方法基础上添加了新功能
print('man is sleeping') class Women(People,Relation):
#类‘Women’继承类‘People’和‘Relation’
def get_birth(self):
#'get_birth'为类‘Women’独有的方法
print('%s is borning a baby'%self.name) m1 = Man('kobe',36,26)
m1.eat()
m1.sleep()
m1.smoke() w1 = Women('alice',45)
w1.get_birth() m1.make_friends(w1)
代码执行结果如下:
另外,若我们让实例w1去使用类Man中的‘smoke’方法,则会出现问题。如下所示:
class People():
#创建‘人类’类
def __init__(self,name,age):
self.name = name
self.age = age
#‘吃’方法
def eat(self):
print('%s is eating'%self.name)
#‘睡’方法
def sleep(self):
print('%s is sleeping'%self.name) class Relation(object):
#创建‘交朋友’类
def make_friends(self,obj):
print('%s is making friends with %s'%(self.name,obj.name)) class Man(People,Relation):
#类‘Man’继承类‘People’和‘Relation’
def __init__(self,name,age,money):
super().__init__(name,age) #新式类
self.money=money #'money'为类‘Man’独有的属性
print('%s have %s money'%(self.name,self.money))
def smoke(self):
#'smoke'为类‘Man’独有的方法
print('%s is smoking'%self.name) def sleep(self):
People.sleep(self)
#在继承类‘People’的sleep方法基础上添加了新功能
print('man is sleeping') class Women(People,Relation):
#类‘Women’继承类‘People’和‘Relation’
def get_birth(self):
#'get_birth'为类‘Women’独有的方法
print('%s is borning a baby'%self.name)
w1 = Women('alice',45)
w1.smoke()
结果如下图:
我们可以看到w1只能使用继承的类(People,Relation)和自己类(Women)下包含的方法。
最后,我们用学到的类来编写一个描述学校-老师-学生之间关系的小程序。其中老师有教课的方法,学生有交学费的方法。
具体如下:
class School():
def __init__(self,name,addr):
self.name = name
self.addr = addr
self.students = []
self.staffs = [] #为学生办理注册手续
def enroll(self,stu_obj):
print('为学员%s办理注册手续'%stu_obj.name)
self.students.append(stu_obj) #记录招募的员工情况
def hire(self,staff_obj):
self.staffs.append(staff_obj)
print('雇佣新员工%s'%staff_obj.name) #描述‘学校成员’的类
class SchoolMember():
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex class Teacher(SchoolMember):
def __init__(self,name,age,sex,salary,course):
super().__init__(name,age,sex)
self.salary = salary
self.course = course def tell(self):
print('''
---info of Teacher: %s---
Name: %s
Age: %s
Sex: %s
Salary: %s
Course: %s
'''%(self.name,self.name,self.age,self.sex,self.salary,self.course)) def teach(self):
print('%s is teaching course [%s]'%(self.name,self.course)) class Student(SchoolMember):
def __init__(self,name,age,sex,stu_id,grade):
super().__init__(name,age,sex)
self.stu_id = stu_id
self.grade = grade def tell(self):
print('''
---info of Student: %s---
Name: %s
Age: %s
Sex: %s
Stu_id: %s
Grade: %s
'''%(self.name,self.name,self.age,self.sex,self.stu_id,self.grade)) def pay_tuition(self,amount):
print('%s has paid tuition for $%s'%(self.name,amount)) #实例化
school=School('南京邮电大学','南京') t1=Teacher('Kobe',56,'M',200000,'Sport')
t2=Teacher('Justin',22,'M',3000,'Music') s1=Student('Chen',36,'F',1001,'Sport')
s2=Student('Xu',19,'M',1002,'Music') t1.tell()
s1.tell()
school.hire(t1)
school.enroll(s1)
school.enroll(s2) print(school.students)
print(school.staffs)
school.staffs[0].teach() for stu in school.students:
stu.pay_tuition(5000)
代码执行结果如下:
四、导入类
随着你不断给类添加新功能,文件可能变得很长,即使你妥善地使用了继承亦如此。为遵循Python的总体理念,应让文件尽可能简洁。为这方面提供帮助,Python允许你将类存储在模块中,然后在主程序中导入所需模块中,然后在主程序中导入所需的模块。
以上述dog.py中的Dog为例,我们新建一个文件——导入.py来实现导入类的功能。
导入.py的具体代码如下:
from dog import Dog
d3=Dog('bai')
d3.bulk()
代码执行结果如下:
通过上面的例子我们可以看到导入类是一种有效的编程方式。通过将这个类移到一个模块中,并导入该模块,你依然可以使用其所有功能,但主程序变得简洁而易于阅读了。这还能让你将大部分逻辑存储在独立的文件中。确定类像你希望的那样工作后,你就可以不管这些文件,而专注于主程序的高级逻辑了。