面向对象|面向对象 -- 类属性和类方法
实例对象
当使用类名()
创建对象时,系统进行了两步操作:
- 在内存中为
对象
分配存储空间- 调用初始化方法
__init__
为对象进行初始化
当对象创建后,内存中就有了一个对象的实实在在
的存在 —— 实例
- 创建出来的
对象
叫做类的实例
- 创建对象的动作叫做
实例化
- 对象的
属性
叫做实例属性
- 对象调用的
方法
叫做实例方法
文章图片
在程序执行时:实例演示:工具箱
- 每一个对象都有自己
独立的内存空间
,保存各自不同的属性
- 可以通过
self.
访问自己的属性
,调用自己的方法
- 多个对象的方法,在内存中
只有一份
,调用方法时将当前对象的引用
传递到方法内部
- 定义一个
工具类
,每件工具都有自己的name
属性- 定义一个
类属性
记录该类创建了多少个工具对象?
- 设计类
文章图片
- 实现类
class Tool(object):
count = 0
def __init__(self, name):
self.name = name
Tool.count += 1tool1 = Tool("锤子")
tool2 = Tool("螺丝刀")
tool3 = Tool("钳子")print("现在创建了 %d 个工具" % Tool.count)
类对象
- 在程序运行时,类同样会被加载到内存中
- 在Python中,类是一个特殊的对象 ——
类对象
- 在程序运行时,
类对象
在内存中只有一份
类对象
拥有自己的属性
和自己的方法
,分别称为类属性
和类方法
- 通过
类名.
的方式访问类属性,
调用类方法
文章图片
类属性
类属性
是针对类
定义的属性
,用于记录与这个类相关的特征- 使用
类名.类属性名
的方式访问
class 类名:
类变量名 = 值
【面向对象|面向对象 -- 类属性和类方法】注意:使用类方法对象.类属性 = 值
,只会添加一个对象属性
,而不会改变
类属性的值
类方法
是针对类
定义的方法
- 在
类方法
内部可以直接访问类属性
或者调用其他类方法
@classmethod
def 类方法名(cls):
pass
实例演示:工具箱
类方法
需要用修饰器@classmethod
来标识类方法
的第一个参数是cls
,这只是习惯用法,也可以换成其他名字cls
用来指出类方法
的调用者
,与self
类似,不需要传递cls
参数- 使用
类名.类方法名()
的形式调用类方法
类方法
内部,使用cls.属性名
访问类属性
、cls.方法名
调用其他类方法
为工具类
添加show_tool_count
类方法,输出创建对象的个数
@classmethod
def show_tool_count(cls):
print("工具对象的总数 %d" % cls.count)
静态方法
- 在
类方法
中只能访问类属性
,调用其他的类方法
- 在
实例方法
中可以访问实例属性
,也可访问类属性
- 在
实例方法
中可以调用其他的实例方法
,也可调用其他的类方法
在开发时,如果需要在类中封装一个方法,这个方法:
- 既
不访问
实例属性、实例方法,也不访问
类属性、类方法- 这时可以把这个方法封装成一个
静态方法
@staticmethod
def 静态方法名():
pass
通过类名.静态方法名
来调用静态方法
class Dog:
@staticmethod
def run():
print("狗在跑...")
实例演示:小霸王游戏机
需求:设计一个 Game 类
- 属性:
- 定义一个类属性
top_score
记录游戏的历史最高分- 定义一个实例属性
player_name
记录当前游戏的玩家姓名- 方法:
- 定义静态方法
show_help
显示游戏帮助信息- 定义类方法
show_top_score
显示历史最高分- 定义实例方法
start_game
开始当前玩家的游戏
- 设计类
文章图片
- 实现类
class Game(object):
top_score = 0# 游戏最高分,类属性@staticmethod
def show_help():
print("帮助信息:让僵尸走进房间")@classmethod
def show_top_score(cls):
print("游戏最高分是 %d" % cls.top_score)def __init__(self, player_name):
self.player_name = player_namedef start_game(self):
print("[%s] 开始游戏..." % self.player_name)
Game.top_score = 999# 使用类名.修改历史最高分Game.show_help()# 1. 查看游戏帮助
Game.show_top_score()# 2. 查看游戏最高分
game = Game("小明")# 3. 创建游戏对象,开始游戏
game.start_game()
Game.show_top_score()# 4. 游戏结束,查看游戏最高分
帮助信息:让僵尸走进房间
游戏最高分是 0
[小明] 开始游戏...
游戏最高分是 999
单例设计模式
- 实例方法内,可以访问
实例属性
、实例方法
、类属性
、类方法
- 类方法内,可以访问
类属性
、类方法
- 静态方法内,
不能
访问实例属性
、实例方法
、类属性
、类方法
- 设计模式:是前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对某一特定问题的成熟解决方案。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性
- 单例设计模式:在程序中只创建一个
唯一的
对象实例,每次执行类名()
创建对象时,返回的都是同一个对象,内存地址是相同的
-
__new__
方法
- 使用
类名()
创建对象时,Python解释器首先调用__new__
方法为对象分配存储空间__new__
方法是object类
提供的内置静态方法,作用有两个,分配内存空间,返回对象引用- Python解释器获得对象的引用后,将引用作为第一个参数,传递给
__init__
方法
文章图片
- 单例模式的实现
- 定义一个
类属性
,初始值设为None
,用于记录单例对象的引用- 重写
__new__
方法
如果类属性 is None
,调用父类方法分配空间,并在类属性中记录结果
否则返回类属性中记录的对象引用
文章图片
class MusicPlayer(object):
instance = None# 定义类属性记录单例对象引用def __new__(cls, *args, **kwargs):
if cls.instance is None:# 判断类属性是否已经被赋值
cls.instance = super().__new__(cls)return cls.instance# 返回类属性的单例引用
- 只执行一次初始化工作
重写__new__
方法后,每次都得到唯一的
对象引用,但是,初始化方法还是会被再次调用
解决方法:
- 定义
init_flag
类属性,标记是否执行过初始化动作,初始值设为False
- 在
__init__
方法中,判断init_flag
,如果为False
就执行初始化动作,并将init_flag
设置为True
- 这样,再次调用
__init__
方法时,初始化动作就不再执行了
class MusicPlayer(object):
instance = None# 记录第一个被创建对象的引用
init_flag = False# 记录是否执行过初始化动作def __new__(cls, *args, **kwargs):
if cls.instance is None:# 判断类属性是否为空
cls.instance = super().__new__(cls)# 调用__new__方法创建新对象
return cls.instance# 返回类属性保存的对象引用def __init__(self):
if not MusicPlayer.init_flag:
print("初始化音乐播放器")
MusicPlayer.init_flag = Trueplayer1 = MusicPlayer()
print(player1)player2 = MusicPlayer()
print(player2)
初始化音乐播放器
<__main__.MusicPlayer object at 0x00000000029CA160>
<__main__.MusicPlayer object at 0x00000000029CA160>
- end -
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 为什么你的路演总会超时()
- 标签、语法规范、内联框架、超链接、CSS的编写位置、CSS语法、开发工具、块和内联、常用选择器、后代元素选择器、伪类、伪元素。
- thinkphp|thinkphp 3.2 如何调用第三方类库
- 使用composer自动加载类文件
- 一个健康的APP和健全的人格大体类似
- 数组常用方法一
- 种树郭橐驼传(文言句式+古今异义+词类活用+通假字)
- 归乡-序章(世界伊始,人类无所依靠,我的故事就从这里开始...)
- jQuery插件