面向对象程序设计
注意:本章笔记代码模块中的__,部分场景由于显示问题,将双下划线连接在一起,实际上为双下划线(编译环境中显示样式:_ _)
-
概念
- 面向对象编程:定义类→实例化→执行动作
- eg. 把水蜜桃装进冰箱(Hint:水蜜桃属于水果类)
- 面向对象:定义类(水果)→实例化(水蜜桃)→执行动作(把水蜜桃放进冰箱)
- 面向过程:打开冰箱(怎么打开)→装水蜜桃(怎么装)→关闭冰箱(怎么关闭)
- 对比,处理新水果:西瓜
- 面向对象:实例化新实例(西瓜)→执行动作
- 面向过程:西瓜比水蜜桃大,思考怎么装进冰箱;西瓜太重,怎么顺手开冰箱
- 面向对象编程:定义类→实例化→执行动作
-
类:
-
定义
-
实例化
- () 不可少
-
# 定义方法:
class Classname: # 定义规范,类名首字母大写
pass
# ---------------------------------------------------------------------------------
# 实例化
example = Classname() # ()不可少
class Game:
pass
wzry = Game() # 类的实例化,游戏类:王者荣耀wzry
print(type(Game)) # 表示Game的类型为class
print(type(wzry)) # 表示wzry的类型是当前程序的Game类的实例
-
补充知识:
- 对象三特征:value,id,type
- 函数:面向过程
- 方法:面向对象
- 特例:类中的_ _init_ _为构造函数
- 显示类包含的内容 : classname._ _dict_ _()
- 构造函数:构造实例的进程函数
- 语法 : def _ _init_ _(self):
- self表示当前实例,不可缺少
- 不能设置return值
- class执行当前实例的函数
- 方法:
- 包含普通方法和类方法
- 语法 : def methodname(self)
- self表示当前实例
- 任意返回值
- 调用类中方法的语法 : Classname.methodname()
- self不用输入参数
- eg.
class Game:
# self 表示类实例化后的当前实例
def __init__(self): # 建立实例构造函数
pass
# 不能设return值,否则报错
def methodname(self): # 定义普通方法,类方法下文会提到
pass
# 正常设置return值
-
类属性:
- classname._ _dict_ _ 显示类/
- 类属性由类下所有实例共享
- 实例仅访用类
- 可以访问类属性,使用方法(含类方法),但数据不在实例dict里,默认为访问
- 若实例无新定义类属性:
- print自动打印类属性(默认设置为访问)
- ._ _dict_ _显示实例无类属性
# 验证实例仅访用类
# 实例仅访用类定义:
# 实例可以访问类属性,使用方法(含类方法),但数据不在实例dict里,默认方式为访问
class Game:
system = 'mobile game' # 类属性:所有实例可以访问
type = 'MOBA' # 类属性:所有实例可以访问
wzry = Game() # 类的实例化,游戏类:王者荣耀wzry
print(wzry.type)
print(Game.__dict__)
print('没有新定义实例属性后,实例的dict:')
print(wzry.__dict__)
jdqs = Game()
jdqs.type = 'FPS'
print('新定义实例属性后,实例的dict:')
print(jdqs.__dict__)
- 输出结果:
- 解释:
- 第6行语句输出MOBA,表示实例的type属性可以访问类属性type(MOBA)
- 第9行语句输出实例的dict显示为空,表示实例dict无类属性type
- 第6、9行语句验证了实例仅访用类的概念
- 第12行语句新定义实例的type属性
- 第14行语句输出实例的dict显示含新定义的'FPS',表示实例dict有属性type='FPS'
-
类方法:
- 直接调用类属性
- 类方法示例:
class Game:
classgametype = 'FPS'
def __init__(self,formgametype): #设置外部数据传入实例属性的入口,形参formgametype
self.gametype = formgametype #设置实例的一个属性gametype,并传入外部数据
def Gametype(self): #打印实例属性定义的gametype的方法
print('实例属性定义的游戏类型是:', self.gametype)
# 类方法语句模块------------------------------------------------------------------------
@classmethod # 类方法声明,声明这个方法是类方法
def Gametypeclass(cls):
#打印类属性定义的gametype的方法 #方法变量名为当前通用标识符为cls,此处可替换为类名Game
print('类属性定义的游戏类型是:', cls.classgametype)
#调用当前类属性classgametype #语法:通用标识符cls.类属性名,此处可替换为Game.
# ---------------------------------------------------------------------------------
wzry = Game('MOBA') # 外部数据通过形参导入实例属性
wzry.Gametype() # 打印实例属性定义的Gametype
wzry.Gametypeclass() # 打印类属性定义的Gametype
- 类方法统计实例化个数,示例:
class Game:
num = 0 # 计数记录
def __init__(self,formgametype):#设置外部数据传入实例属性的入口,形参formgametype
self.gametype = formgametype #设置实例的一个属性gametype,并传入外部数据
Game.num += 1 # 每实例化一次后,num+1,可用_ _class_ _.num替换,方便修改
@classmethod
def numcount(cls): # 注意括号内为cls,表示当前类
print('一共实例化', cls.num, '个实例') # 直接调用类属性
wzry = Game('MOBA')
jdqs = Game('FPS')
Game.numcount() # 调用类Game中的方法numcount
# 输出结果:
# 一共实例化了2个实例
-
构造函数
-
基本知识
- 构造实例的进程函数
- 语法 : def _ _init_ _(self)
- self表示当前实例,不可缺少
- 不能设置return值
- class执行当前实例的函数
-
参数传递
# self 表示当前实例!!!!!!!!
class Game:
gametype = 'FPS' # 类属性,验证这个功能时可以略去
systemtype = 'mobile game' # 加入可观察验证仅访用机制
# self 表示当前实例!!!!!!!!
def __init__(self,sgametype,ssystem): # 定义参数(外部数据)传入入口
self.gametype = sgametype # 设置实例的第一个属性gametype
self.systemtype = ssystem # 设置实例的第二个属性systemtype
# self 表示当前实例!!!!!!!!
wzry = Game('MOBA','PC') # 实例化语句,传入参数(外部数据)给实例属性
print(wzry.gametype, wzry.systemtype) # 打印实例wzry的两个属性
print(wzry.__dict__) # 检验实例字典,结果说明参数成功传入实例,并保存在实例dict里
-
-
构造函数内的参数调用
- Y参数传入构造函数,其他方法也可以调用Y参数, 语法:self.parameter
- eg.
class Game:
def __init__(self, sgametype): # 定义形参Y:sgametype
self.gametype = sgametype
def printgametype(self):
print('这个游戏的类型是:', self.gametype) # self.xxx调用Y参数
wzry = Game('MOBA') # 实例化,并传入形参的内容
wzry.printgametype() # 实例调用类方法
-
静态方法
-
访问权限控制
- @property:将方法变成属性,访问方式改变,方法必须有返回值,因为是属性
- 原,访问方式:class.method()
- 使用@property后,访问方式:class.method
- class内部私有方法:前置双下划线def _ _methodname(self)
- 表示仅class内部可访问,class外不可访问,_ _表示隐藏符号
- 用_ _后,class内部调用标识符为._ _parameter,不是.parameter
- class内部私有变量:前置双下划线self._ _parameter
- @property:将方法变成属性,访问方式改变,方法必须有返回值,因为是属性
# 无限制访问
class School:
area = 'China'
def __init__(self,formpnum):
self.pnum = formpnum
HKU = School(1000)
print(HKU.pnum)
# 打印得到 1000
# --------------------------------------------------------------------------------
# _ _设置class内部访问权限后
class School:
area = 'China'
def __init__(self,pnum):
self.__pnum = pnum # 限制class内部访问权限
HKU = School(1000)
print(HKU.__pnum)
# 打印得到:
# AttributeError: 'School' object has no attribute 'pnum'
# 属性错误:'School'对象没有'pnum'属性
# --------------------------------------------------------------------------------
class School:
area = 'China'
def __init__(self,pnum):
self.__pnum = pnum # 限制class内部访问权限
# 以下语句涉及的过程有:建立打印私有变量 self.__pnum的解决办法,将方法变为类属性的过程
@property
def getpnum(self):
return self.__pnum
HKU = School(1000)
print(HKU.getpnum)
# 打印得到 1000
-
父子类:
-
概念
- 继承:下级有上级的所有功能,并且可以有新的功能
- 父类
- 子类(继承父类属性+行为,同时有自己属性/行为/属性+行为)
- 抽象类比:
- 父类:属性:西瓜;行为:解渴
- 父类的继承子类A:属性:有籽,西瓜;行为:解渴
- 父类的继承子类B:属性:无籽,西瓜;行为:解渴
-
子类继承父类
- 语法:四步走
- 子类名后添加父类名+括号
- class Student(Human):
- 子类实例属性添加父类实例属性变量
- def __init__(self, weight, height, hobby):
- 子类构造函数内添加继承语句,并且键入父类实例属性变量(weight,height)
- super().__init__(weight, height)
- 实例化赋予父类实例属性(63,178)+子类实例属性('basketball')
- A = Student(63,178,'basketball')
- 若在第三步中,提前赋予父类实例属性,则第四步只要赋予子类实例属性(后续代码有演示)
-
# 语法实例
# 区分:父类实例、子类实例、类属性、实例属性、父类实例属性、子类实例属性
# self:当前实例,__init__(self,parameters)中的parameters为实例属性
# 定义父类
class Human:
goal = 'love and peace'
def __init__(self, weight, height):
self.weight = weight
self.height = height
def Run(self):
print(self.height, '在跑步')
# -----------------------------------------------------------------------
# 定义继承父类的子类
class Student(Human): # 添加括号加父类名字(fathername)
def __init__(self, weight, height, hobby):
self.hobby = hobby
super().__init__(weight, height) # 子类继承父类的实例属性(weight、height)、父类方法
print('继承的父类-类属性为', self.goal) # 子类实例可以访问父类的类属性
print(self.__dict__) # 检验是否存入子类实例dict中
self.Run() # 子类实例使用父类方法
# 17、18、19行结果表明父子类继承中——子类实例遵循'仅仿用'父类机制,不计入dict
# 个人理解:因为子类实例继承父类实例,而父类实例 '仅仿用' 父类,
# 所以子类实例'仅仿用' 父类
A = Student(63,178,'basketball') # 子类实例需要输入父2+子1个属性值
# 若将 17 行改为:super().__init__(63, 178)
# 则 24 行随之更改为:A = Student('basketball')
# 上述为继承时,同时键入原理
# 输出内容为:
-
方法重写
- 继承父类的子类下,重写方法原则:子类方法名、方法变量名与父类相同