目标
- 多态
面向对象三大特性
1,封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中
- 定义类的准则
2,继承 实现代码的重用,相同的代码不需要重复的编写
- 设计类的技巧
- 子类针对自己特有的需求,编写特定的代码
3,多态 不同的 子类对象 调用相同的 父类方法,产生不同的执行结果
- 多态 可以 增加代码的灵活度
- 以 继承 和 重写父类方法 为前提
- 是调用方法的技巧,不会影响到类的内部设计
多态案例演练
需求
1,在Dog
类中封装方法 game
- 普通狗只是能简单的玩耍
2,定义 XiaoTianQuan
继承自 Dog
,并且重写 game
方法
- 哮天犬需要在天上玩耍
3,定义 Person
类,并封装一个 和狗玩 的方法
- 在方法内部,直接让 狗对象 调用
game
方法
class Dog(object): def __init__(self, name): self.name = name def game(self): print("普通狗 [%s] :蹦蹦跳跳旺旺旺~~~" % self.name) class XiaoTianQuan(Dog): def game(self): print("神仙狗 [%s] : 飞天入地吼吼吼~~~" % self.name) class Person(object): def __init__(self, name): self.name = name def game_with_dog(self, dog): print("[%s] 带着 [%s] 愉快的玩耍" % (self.name, dog.name)) # 让狗玩耍 dog.game() # 1,创建一个狗对象 # xiaobudian = Dog("小不点") xiaobudian = XiaoTianQuan("小不点") # 2,创建一个人对象 namei = Person("娜美") # 3,调用方法 namei.game_with_dog(xiaobudian) # 结果呈现 [娜美] 带着 [小不点] 愉快的玩耍 神仙狗 [小不点] : 飞天入地吼吼吼~~~
小结
Person
类中只需要让 狗对象 调用game
方法,而不关心具体是 什么狗game
方法是在Dog
父类中定义的
- 在程序执行时,传入不同的 狗对象 实参,就会产生不同的执行结果
01,类的结构
1.1 术语 -- 实例
1,使用面向对象开发,第一步 是设计 类
2,使用 类名()
创建对象, 创建对象 的动作有两步
- 1) 在内存中为对象 分配空间
- 2) 调用初始化方法
__init__
为 对象初始化
3,对象创建后,内存 中就有了一个对象的 实实在在 的内存 —— 实例
因此,
1,创建出来的 对象 叫做 类 的 实例 2,创建对象的 动作 叫做 实例化 3,对象的属性 叫做 实例属性 4,对象调用的方法 叫做 实例化方法在程序执行时:
1,对象各自拥有自己的 实例属性 2,调用对象方法,可以通过self.
- 访问自己的属性
- 调用自己的方法
结论
- 每一个对象 都有自己 独立的内存空间,保存各自不同的属性
- 多个对象的方法,在内存中只有一份,在调用方法时,需要把对象的引用 传递到方法内部
1.2 类是一个特殊的对象
Python
中 一切皆对象:
class AAA:
定义的类属于 类对象obj1 = AAA()
属于 实例对象- 在程序运行时,类 同样 会被加载到内存
- 在
python
中,类 是一个特殊的对象 --- 类对象 - 在程序运行时,类对象 在内存中 只有一份 ,使用 一个类 可以创建出 很多个对象实例
- 除了封装 实例 的 属性 和 方法 外,类对象 还可以拥有自己的 属性 和 方法 1,类属性 2,类方法
通过
类名.
的方式可以 访问类的属性 或者 调用类的方法
02,类的属性和实例属性
2.1 概念和使用
- 类属性 就是给 类对象 中定义的 属性
- 通常用来记录 与这个类相关 的特征
- 类属性 不会用于记录 具体对象的特征
示例需求
- 定义一个 工具类
- 每件工具都有自己的
name
- 需求 --- 知道使用这个类,创建了多少个工具对象?
class Tool(object): # 使用赋值语句定义类属性,记录所有工具对象数量 count = 0 def __init__(self, name): self.name = name # 让类属性的值 +1 Tool.count += 1 # 1, 创建工具对象 tool1 = Tool("方天画戟") tool2 = Tool("青龙偃月刀") tool3 = Tool("涯角枪") tool4 = Tool("丈八蛇矛") tool5 = Tool("双铁戟") tool6 = Tool("古锭刀") tool7 = Tool("青釭剑") tool8 = Tool("雌雄双剑") tool9 = Tool("诸葛连弩") # 2,输出的工具对象的数量 print(Tool.count) # 结果呈现 9
2.2 属性的获取机制
- 在
python
中 属性的获取 存在一个 向上查找的机制
- 因此,要访问类属性有两种发式:
类名.类属性
对象.类对象
(不推荐)
注意
- 如果使用
对象.类对象 = 值
赋值语句,只会 给对象添加一个属性, 而不会影响到 类属性的值
class Tool(object): # 使用赋值语句定义类属性,记录所有工具对象数量 count = 0 def __init__(self, name): self.name = name # 让类属性的值 +1 Tool.count += 1 # 1, 创建工具对象 tool1 = Tool("方天画戟") tool2 = Tool("青龙偃月刀") tool3 = Tool("涯角枪") tool4 = Tool("丈八蛇矛") tool5 = Tool("双铁戟") tool6 = Tool("古锭刀") tool7 = Tool("青釭剑") tool8 = Tool("雌雄双剑") tool9 = Tool("诸葛连弩") # 2,输出的工具对象的数量 print("对象.类对象 对象总数 %d" % tool6.count) tool6.count = 99 print("对象.类对象 对象总数 %d" % tool6.count) print("类名.类属性 对象总数 %d" % Tool.count) # 结果呈现 对象.类对象 对象总数 9 对象.类对象 对象总数 99 类名.类属性 对象总数 9
03,类方法和静态方法
3.1 类方法
- 类属性 就是针对 类对象 定义的属性
- 使用 赋值语句 在
class
关键字下方可以定义 类属性 - 类属性 用于记录 与这个类相关 的特征
- 使用 赋值语句 在
- 类方法 就是针对 类对象 定义的方法
- 在 类方法 内部可以直接访问 类属性 或者调用其它的 类方法
语法如下
@classmethoddef 类方法名(cls): pass
- 类方法需要用 修饰器
@classmethod
来标识,告诉解释器这是一个类方法 - 类方法的 第一个参数 应该是
cls
- 由 哪一类 调用的方法,方法内的
cls
就是 哪一个类的引用 - 这个参数和 实例方法 的第一个参数是
self
类似 - 提示 使用其他名称也可以,不过习惯使用
cls
- 由 哪一类 调用的方法,方法内的
- 通过 类名,调用 类方法,调用方法时,不需要传递
cls
参数 - 在方法内部
- 可以通过
cls
访问类的属性 - 也可以通过
cls
调用其它的类方法
- 可以通过
示例需求
- 定义一个 工具类
- 每件工具都有自己的
name
- 需求 - - - 在 类 封装一个
show_tool_count
的类方法,输出使用当前这个类,创建的对象个数
class Tool(object): # 使用赋值语句定义类属性,记录所有工具对象数量 count = 0 @classmethod def show_tool_count(cls): print("类方法: 对象总数 %d" % cls.count) def __init__(self, name): self.name = name # 让类属性的值 +1 Tool.count += 1 # 1, 创建工具对象 tool1 = Tool("方天画戟") tool2 = Tool("青龙偃月刀") tool3 = Tool("涯角枪") tool4 = Tool("丈八蛇矛") tool5 = Tool("双铁戟") tool6 = Tool("古锭刀") tool7 = Tool("青釭剑") tool8 = Tool("雌雄双剑") tool9 = Tool("诸葛连弩") # 2,输出的工具对象的数量 print("类名.类属性 对象总数 %d" % Tool.count) Tool.show_tool_count() # 结果呈现 类名.类属性 对象总数 9 类方法: 对象总数 9
注 在类方法内部,可以直接使用 cls
访问 类属性 或者 调用类方法
3.2 静态方法
- 在开发时,如果需要在 类 中封装一个方法,这个方法:
- 既 不需要 访问 实例属性 或者调用 实例方法
- 也 不需要 访问 ** 类属性** 或者调用 类方法
- 这个时候,可以把这个方法封装成一个 静态方法
语法如下
@staticmethoddef 静态方法名(): pass
- 静态方法 需要用 修饰器
@staticmethod
来标识,告诉解释器这是一个静态方法 - 通过 类名,调用 静态方法
class Dog(object): @staticmethod def run(): # 不需要访问实例属性/类属性 print("小猫要跑。。。") # 通过类名.调用静态方法 - - 不需要创建对象 Dog.run() # 结果呈现 小猫要跑。。。
3.3 方法综合案例
需求
1,设计一个Game
类 2,属性:
- 定义一个 类属性
top_score
记录游戏的 历史最高分 - 定义一个 实例属性
player_name
记录 ** 当前游戏的玩家名称**
3,方法:
- 静态方法
show_help
显示游戏帮助信息 - 类方法
show_top_score
显示历史最高分 - 实例方法
start_game
开始当前玩家的游戏
4,主程序步骤
- 查看帮助信息
- 查看历史最高分
- 创建游戏对象,开始游戏
class Game(object): # 类属性 # 历史最高分 top_score = 0 # 初始化方法中定义实例属性 def __init__(self, player_name): self.player_name = player_name # 静态方法 @staticmethod def show_help(): print("帮助信息:让僵尸进入大门") # 类方法 @classmethod def show_top_score(cls): print("历史最高纪录 %d " % cls.top_score) # 对象实例方法 def start_game(self): print("%s 开始游戏啦 ..." % self.player_name) # 1,查看游戏的帮助信息 Game.show_help() # 2,查看历史最高分 Game.show_top_score() # 3,创建游戏对象 name = Game("小游") name.start_game() # 结果呈现 帮助信息:让僵尸进入大门 历史最高纪录 0 小游 开始游戏啦 ...
小结
1,实例方法 - - 方法内部需要访问 实例属性- 实例方法 内部可以使用 类名,访问类属性
2,类方法 - - 方法内部 只 需要访问 类属性
3,静态方法 - - 方法内部 不需要 访问 **实例属性 和 类属性*8
提问:
如果方法内部 即需要访问 实例属性,又需要访问 类属性,应该定义成什么方法?答案- 应该定义 实例方法
- 因为,类只有一个,在 实例方法 内部可以使用 类名,访问类属性