Python面向对象特点的具体实现2(多态、类属性和类方法)
1.多态
复习面向对象的三大特性:
-
封装 :根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中
- 定义类的准则
-
继承 :实现代码的重用,相同的代码不需要重复的编写
- 设计类的技巧
- 子类针对自己特有的需求,编写特定的代码
-
多态 :不同的 子类对象 调用相同的 父类方法,产生不同的执行结果
- 多态 可以 增加代码的灵活度
- 以 继承 和 重写父类方法 为前提
- 是调用方法的技巧,不会影响到类的内部设计
多态 更容易编写出通用的代码,做出通用的编程,以适应需求的不断变化
2.多态实例
下面的Person和FireMan类具有相同的方法work,但是结果不同,体现出了多态
#定义人类
class Person():
def __init__(self, name):
self.name = name
def work(self):
print("{0}职员正在进行工作...".format(self.name))
#定义消防员类
class FireMan(Person):
def work(self):
print("消防员救火ing...")
#定义火灾类
class Fire():
def __init__(self, location, degree):
self.location = location
self.degree = degree
def take_place(self):
print("在{0}发生了一起{1}的火灾".format(self.location, self.degree))
def put_off(self, fireman):
fireman.work()
print("一起发生在{0}的{1}程度的火被消防员{2}扑灭了".format(self.location, self.degree, fireman.name))
#定义主函数
def main():
fire1 = Fire("A市B街道C号楼", "严重")
fireman1 = FireMan("dzzhyk")
common_worker = Person("小明")
common_worker.work()
fire1.take_place()
fire1.put_off(fireman1)
common_worker.work()
if __name__ == '__main__':
main()
#输出:
小明职员正在进行工作...
在A市B街道C号楼发生了一起严重的火灾
消防员救火ing...
一起发生在A市B街道C号楼的严重程度的火被消防员dzzhyk扑灭了
小明职员正在进行工作...
3.类属性和类方法
(1)类的结构
1.1 术语
- 使用面相对象开发,第 1 步 是设计 类
- 使用 类名() 创建对象,创建对象 的动作有两步:
- 1) 在内存中为对象 分配空间
- 2) 调用初始化方法
__init__
为 对象初始化
- 对象创建后,内存 中就有了一个对象的 实实在在 的存在 —— 实例
因此,通常也会把:
- 创建出来的 对象 叫做 类 的 实例
- 创建对象的 动作 叫做 实例化
- 对象的属性 叫做 实例属性
- 对象调用的方法 叫做 实例方法
在程序执行时:
- 对象各自拥有自己的 实例属性
- 调用对象方法,可以通过
self.
- 访问自己的属性
- 调用自己的方法
结论
- 每一个对象 都有自己 独立的内存空间,保存各自不同的属性
- 多个对象的方法,在内存中只有一份,在调用方法时,需要把对象的引用 传递到方法内部
1.2 类是一个特殊的对象
Python
中 一切皆对象:
class AAA:
定义的类属于 类对象obj1 = AAA()
属于 实例对象
- 在程序运行时,类 同样 会被加载到内存
- 在
Python
中,类 是一个特殊的对象 —— 类对象 - 在程序运行时,类对象 在内存中 只有一份,使用 一个类 可以创建出 很多个对象实例
- 除了封装 实例 的 属性 和 方法外,类对象 还可以拥有自己的 属性 和 方法
- 类属性
- 类方法
- 通过 类名. 的方式可以 访问类的属性 或者 调用类的方法
(2)类属性和实例属性
2.1 概念和使用
- 类属性 就是给 类对象 中定义的 属性
- 通常用来记录 与这个类相关 的特征
- 类属性 不会用于记录 具体对象的特征
示例:top_score是类属性
import random
class Game():
#类属性-直接在class下使用赋值语句定义
top_score = 0
#实例属性-使用__init__定义
def __init__(self, name):
self.player_name = name
#使用@staticmethod创建-类的静态方法
@staticmethod
def show_help():
print("游戏帮助信息")
#使用@classmethod创建-类方法
@classmethod
def show_top_score(cls):
print(Game.top_score)
#创建普通的实例方法
def start_game(self):
print("开始游戏")
score = random.random()*100
if score >= Game.top_score:
Game.top_score = score
#创建__del__方法
def __del__(self):
print("游戏结束!")
#主程序
time = int(input())
for i in range(time):
game1 = Game("dzzhyk")
print("游戏人:{0},第{1}轮游戏".format(game1.player_name, i+1))
game1.show_help()
game1.show_top_score()
game1.start_game()
print("结束后的最高分为:{0}".format(Game.top_score))
2.2 属性的获取机制
- 在
Python
中 属性的获取 存在一个 向上查找机制
- 因此,要访问类属性有两种方式:
- 类名.类属性
- 对象.类属性 (不推荐)
注意:如果使用 对象.类属性 = 值
赋值语句,只会 给对象添加一个属性,而不会影响到 类属性的值
(3)类方法和静态方法
3.1 类方法
-
类属性 就是针对 类对象 定义的属性
- 使用 赋值语句 在
class
关键字下方可以定义 类属性 - 类属性 用于记录 与这个类相关 的特征
- 使用 赋值语句 在
-
类方法 就是针对 类对象 定义的方法
- 在 类方法 内部可以直接访问 类属性 或者调用其他的 类方法
语法如下
@classmethod
def 类方法名(cls):
pass
- 类方法需要用 修饰器 @classmethod 来标识,告诉解释器这是一个类方法
- 类方法的 第一个参数 应该是
cls
- 由 哪一个类 调用的方法,方法内的
cls
就是 哪一个类的引用 - 这个参数和 实例方法 的第一个参数是
self
类似 -
提示:使用其他名称也可以,不过习惯使用
cls
- 由 哪一个类 调用的方法,方法内的
- 通过 类名. 调用 类方法,调用方法时,不需要传递
cls
参数
在方法内部:
- 可以通过
cls.
访问类的属性 - 也可以通过
cls.
调用其他的类方法
3.2 静态方法
-
在开发时,如果需要在 类 中封装一个方法,这个方法:
- 既 不需要 访问 实例属性 或者调用 实例方法
- 也 不需要 访问 类属性 或者调用 类方法
就可以把这个方法封装成一个 静态方法
@staticmethod
def 静态方法名():
pass
通过 类名. 调用 静态方法
class Dog(object):
# 狗对象计数
dog_count = 0
@staticmethod
def run():
# 不需要访问实例属性也不需要访问类属性的方法
print("狗在跑...")
def __init__(self, name):
self.name = name
(4)既需要访问 实例属性 又需要访问 类属性 的情况
如果方法内部 即需要访问 实例属性,又需要访问 类属性,应该定义成 实例方法
因为类只有一个,在 实例方法 内部可以使用 类名. 访问类属性