面向对象程序设计
面向对象程序设计是在面向过程程序设计的基础上发展而来的,它比面向编程具有更强的灵活性和扩展性,本次学习需要了解以下内容;
①了解什么是面向对象;
②掌握如何定义和使用类;
③掌握如何创建类的属性;
④掌握继承的基本语法;
⑤掌握方法重写;
1、面向对象概述
面向对象是一种设计思想,从20世纪60年代提出面向对象的概念到现在,它已经发展成为一种比较成熟的编程思想,并且逐步成为目前软件开发领域的主流技术,如我们经常听说的面向对象编程就是主要针对大型软件设计而提出的,它可以使软件设计更加灵活,并且能更好地进行代码复用。
1.1、对象
对象,是一个抽象概念,表示任意存在的事物,通常将对象划分为两个部分,即静态部分与动态部分。静态部分被称为“属性”,任何对象都具备自身属性,这些属性不仅是客观存在的,而且是不能被忽视的,如人的性别。动态部分是对象的行为,即对象执行的动作,如人的行走。
1.2、类
类是封装对象的属性和行为的载体,反过来说,具有相同属相和行为的一类实体被称为类,在Python中,类是一种抽象概念,如定义一个大雁类(Geese),在该类中,可以定义每个对象共有的属性和方法,而一只要从北方飞往南方的大雁则是大雁类的一个对象,对象是类的实例。
1.3、面向对象程序设计的特点
面向对象程序设计具有三大基本特征:封装、继承、多态。
1.3.1、封装
封装是面向对象编程的核心思想,将对象的属性和行为封装起来,而将对象的属性和行为封装起来的载体就是类,类通常对客户隐藏其实现细节,这就是封装思想。
1.3.2、继承
在Python中,继承是实现重复利用的重要手段,子类通过继承复用了父类的属性和行为的同时,又添加子类特有的属性和行为。
1.3.3、多态
将父类对象应用于子类的特征就是多态。
2、类的定义和使用
在Python中,类表示具有相同属性和方法的对象的集合,在使用类时,需要先定义类,然后再创建类的实例,
2.1、定义类
在Python中,类的定义使用class关键字来实现,语法如下;
class ClassName
'''类的帮助信息'''
statement
其中,ClassName用于指定类名,一般使用大写字母开头;statement表示类体,主要是由类变量(或类成员)、方法和属性等语句组成,如果在定义类时,没想好类的具体功能,也可以在类体中直接使用pass语句代替。
2.2、创建类的实例
class语句本身并不创建该类的任何实例,所以在类定义完成后,可以创建类的实例,即实例化该类的对象,基本语法为:
ClassName(paramenterlist)
其中,ClassName是必选参数,用于指定具体的类;paramenterlist是可选参数;
例如,创建Geese类的实例;
class Geese:
pass
wildGoose = Geese()
print(wildGoose)
执行代码后,显示的结果为:
<__main__.Geese object at 0x0000000002E48EB8>
2.3、创建__init__()方法
例如,以大雁为例声明一个类,并且创建__init__()方法,代码如下:
class Geese:
def __init__(self):
print("我是大雁!")
wildGoose = Geese()
运行代码,输出的内容为;
我是大雁!
在__init__()方法中,除了self参数外,还可以定义一些参数,参数间使用逗号“,”进行分割,例如:
class Geese:
'''大雁类'''
def __init__(self,beak,wing,claw): # 构造方法
print("我是大雁类!我有以下特征:")
print(beak) # 输出喙的特征
print(wing) # 输出翅膀的特征
print(claw) # 输出爪子的特征
beak_1 = "喙的基部较高,长度和头部的长度几乎相等" # 喙的特征
wing_1 = "翅膀长而尖" # 翅膀的特征
claw_1 = "爪子是蹼状的" # 爪子的特征
wildGoose = Geese(beak_1,wing_1,claw_1) # 创建大雁类的实例
执行代码,运行结果如下所示:
2.4、创建类的成员并访问
类的成员主要由实例方法和数据成员组成,在类中创建了类的成员后,可以通过类的实例进行访问。
2.4.1、创建实例方法并访问
所谓实例方法,是指在类中的定义函数,该函数是一种在类的实例上操作的函数,创建实例方法的语法格式如下:
def functionName(self,parameterlist)
block
例如:创建大雁类并定义飞行方法。
class Geese:
'''大雁类'''
def __init__(self,beak,wing,claw): # 构造方法
print("我是大雁类!我有以下特征:")
print(beak) # 输出喙的特征
print(wing) # 输出翅膀的特征
print(claw) # 输出爪子的特征
def fly(self,state): # 定义飞行方法
print(state)
'''**************调用方法*********************'''
beak_1 = "喙的基部较高,长度和头部的长度几乎相等" # 喙的特征
wing_1 = "翅膀长而尖" # 翅膀的特征
claw_1 = "爪子是蹼状的" # 爪子的特征
wildGoose = Geese(beak_1,wing_1,claw_1) # 创建大雁类的实例
wildGoose.fly("我飞行的时候,一会儿排成个人字,一会排成个一字") # 调用实例方法
运行结果为:
2.4.2、创建数据成员并访问
数据成员是指在中定义的变量,即属性,根据定义位置,又可以分为类属性和实例属性,
①类属性
类属性是指定义在类中,并且在函数体外得属性。类属性可以在类的所有实例之间共享值,也就是在所有实例化的对象中公用。
例如:通过类属性统计类的实例个数。
class Geese:
'''雁类'''
neck = "脖子较长" # 类属性(脖子)
wing = "振翅频率高" # 类属性(翅膀)
leg = "腿位于身份的中心支点,行走自如" # 类属性(腿)
number = 0 # 编号
def __init__(self): # 构造方法
Geese.number += 1 # 将编号加1
print("\n我是第"+str(Geese.number)+"只大雁,我属于雁类!我有以下特征:")
print(Geese.neck) # 输出脖子的特征
print(Geese.wing) # 输出翅膀的特征
print(Geese.leg) # 输出腿的特征
# 创建4个雁类的对象(相当于有4只大雁)
list1 = []
for i in range(4): # 循环4次
list1.append(Geese()) # 创建一个雁类的实例
print("一共有"+str(Geese.number)+"只大雁")
运行结果如图:
②实例属性
实例属性是指定义在类的方法中的属性,只作用于当前实例中。
对于实例属性也可以通过实例名称修改,与属性不同,通过实例名称修改实例属性后,并不影响该类的另一个实例中相应的实例属性的值,例如:
class Geese:
'''雁类'''
def __init__(self): # 实例方法
self.neck = "脖子较长"
print(self.neck)
goose1 = Geese()
goose2 = Geese()
goose1.neck = "脖子没有天鹅的长"
print("goose1的neck属性:",goose1.neck)
print("goose2的neck属性:",goose2.neck)
2.5、访问限制
在类的内部可以定义属性和方法,而在类的外部则可以直接调用属性或方法来操作数据,从而隐藏了类内部的复杂逻辑,但是,在Python并没有对属性和方法的访问权限进行限制,为了保证类内部的某些属性或方法不被外部访问,可以在属性或方法名前面添加下划线(_foo)、双下划线 ( __foo) 或首尾加双下划线 ,从而限制访问权限。
① _foo:以单下划线开头的表示protected类型的成员,只允许类本身和子类进行访问,
② __foo:双下划线表示private类型的成员,只允许定义该方法的类本身进行访问,而且也不能通过类的实例进行访问,但是可以通过“类的实例名.类名__xxx”方式访问。
③ foo首尾双下滑线表示定义特殊方法,一般是系统定义的名字,如__init()。
3、属性
3.1、创建用于计算的属性
在Python中,可以通过@property将一个方法转换为属性,从而实现用于计算的属性,通过@property创建用于计算的属性的语法格式如下;
@property
def methodname(self)
block
其中,methodname:用于指定方法名,一般使用小写字母开头;self是必选参数,表示类的实例;block是方法体,实现的具体功能。
3.2、为属性添加安全保护机制
在Python中,默认情况下,创建的类属性或者实例是可以在类体外进行修改的,如果想要限制其不能在类体外修改,可以将其设置为私有的,但设置为私有后,在类体外也不能获取它的值,如果想要创建一个可以读取,但不能修改的属性,那么可以使用@property实现只读属性。
例如,创建一个电视节目类TVshow,再创建一个show属性,用于显示当前播放的电视节目,代码如下:
class TVshow:
def __init__(self,show):
self.__show = show
@property
def show(self):
return self.__show
tvshow = TVshow("正在播放《复联4》")
print("默认:",tvshow.show)
执行代码,结果如下所示:
默认: 正在播放《复联4》
例如:在模拟电影点播功能时应用属性;
class TVshow: # 定义电视节目类
list_film = ["战狼2","红海行动","西游记女儿国","熊出没·变形记"]
def __init__(self,show):
self.__show = show
@property # 将方法转换为属性
def show(self): # 定义show()方法
return self.__show # 返回私有属性的值
@show.setter # 设置setter方法,让属性可修改
def show(self,value):
if value in TVshow.list_film: # 判断值是否在列表中
self.__show = "您选择了《" + value + "》,稍后将播放" # 返回修改的值
else:
self.__show = "您点播的电影不存在"
tvshow = TVshow("战狼2") # 创建类的实例
print("正在播放:《",tvshow.show,"》") # 获取属性值
print("您可以从",tvshow.list_film,"中选择要点播放的电影")
tvshow.show = "红海行动" # 修改属性值
print(tvshow.show) # 获取属性值
运行结果为:
4、继承
在编写类时,并不是每次都要从空白开始,当要编写的类和另一个已经存在的类之间存在一定的继承关系时,就可以通过继承来达到代码重用的目的,提高开发效率。
4.1、继承的基本语法
继承是面向对象编程重要的特殊之一,它源于人们认识客观世界的过程,是自然界普遍存在的一种现象。
在Python中,可以在类定义语句中,类名右侧使用一对小括号将要继承的基类名称括起来,从而实现类的继承。
class ClassName(baseclasslist)
Statement
其中,ClassName:用于指定类名;baseclasslist用于指定要继承的基类,可以有多个,类名之间用逗号“,”分割。statement表示类体,主要由类变量(或类成员)、方法和属性等定义语句组成。
例如:创建水果基类及其派生类。
class Fruit: # 定义水果类(基类)
color = "绿色" # 定义类属性
def harvest(self, color):
print("水果是:" + color + "的!") # 输出的是形式参数color
print("水果已经收获……")
print("水果原来是:" + Fruit.color + "的!"); # 输出的是类属性color
class Apple(Fruit): # 定义苹果类(派生类)
color = "红色"
def __init__(self):
print("我是苹果")
class Orange(Fruit): # 定义橘子类(派生类)
color = "橙色"
def __init__(self):
print("\n我是橘子")
apple = Apple() # 创建类的实例(苹果)
apple.harvest(apple.color) # 调用基类的harvest()方法
orange = Orange() # 创建类的实例(橘子)
orange.harvest(orange.color) # 调用基类的harvest()方法
运行结果为:
4.2、方法重写
基类的成员都会被派生类继承,当基类中的某个方法不完全适用于派生类时,就需要在派生类中重写父类的这个方法。
class Orange(Fruit):
color = "橙色"
def __init__(self):
print("\n 我是橘子")
def harvest(self,color):
print("橘子是:"+ color + "的!")
print("橘子已经收获......")
print("橘子原来是:"+ Fruit.color +"的!");
class Apple(Fruit): # 定义苹果类(派生类)
color = "红色"
def __init__(self):
print("我是苹果")
class Orange(Fruit): # 定义橘子类(派生类)
color = "橙色"
def __init__(self):
print("\n我是橘子")
apple = Apple() # 创建类的实例(苹果)
apple.harvest(apple.color) # 调用基类的harvest()方法
orange = Orange() # 创建类的实例(橘子)
orange.harvest(orange.color) # 调用基类的harvest()方法
4.3、派生类中调用基类的 __ init__()方法
在派生类中定义 __ init__()方法时,不会自动调用基类的 __ init__()方法。
例如:在派生类中调用基类的 __ init__()方法定义类属性。定义一个水果类Fruit(作为基类),并在该类中定义 __ init__()方法,在该方法中定义一个类属性,然后在Fruit类中定义一个harvest()方法,再创建Apple类和Sapodilla类,都继承自Fruit类,最后创建Apple类和Sapodilla类的实例,并调用harvest()方法。
class Fruit: # 定义水果类(基类)
def __init__(self,color = "绿色"):
Fruit.color = color # 定义类属性
def harvest(self, color):
print("水果是:" + self.color + "的!") # 输出的是形式参数color
print("水果已经收获……")
print("水果原来是:" + Fruit.color + "的!"); # 输出的是类属性color
class Apple(Fruit): # 定义苹果类(派生类)
color = "红色"
def __init__(self):
print("我是苹果")
super().__init__()
class Aapodilla(Fruit): # 定义人参果类(派生类)
def __init__(self,color):
print("\n我是人参果")
super().__init__(color)
# 重写harvest()方法的代码
def harvest(self,color):
print("人参果是:"+color+"的!") # 输出的是形式参数color
print("人参果已经收获……")
print("人参果原来是:"+Fruit.color+"的!"); # 输出的是类属性color
apple = Apple() # 创建类的实例(苹果)
apple.harvest(apple.color) # 调用基类的harvest()方法
sapodilla = Aapodilla("白色") # 创建类的实例(人参果)
sapodilla.harvest("金黄色带紫色条纹") # 调用基类的harvest()方法
执行代码,运行结果为: