面向对象 -- 类属性和类方法

实例对象

当使用类名()创建对象时,系统进行了两步操作:

  • 在内存中为对象分配存储空间
  • 调用初始化方法 __init__ 为对象进行初始化

当对象创建后,内存中就有了一个对象的实实在在的存在 —— 实例

  • 创建出来的对象叫做类的实例
  • 创建对象的动作叫做实例化
  • 对象的属性叫做实例属性
  • 对象调用的方法叫做实例方法
面向对象 -- 类属性和类方法_第1张图片

在程序执行时:

  • 每一个对象都有自己独立的内存空间,保存各自不同的属性
  • 可以通过self.访问自己的属性,调用自己的方法
  • 多个对象的方法,在内存中只有一份,调用方法时将当前对象的引用传递到方法内部
实例演示:工具箱
  • 定义一个工具类,每件工具都有自己的name属性
  • 定义一个类属性记录该类创建了多少个工具对象?
  • 设计类
面向对象 -- 类属性和类方法_第2张图片
  • 实现类
class Tool(object):
    count = 0
    def __init__(self, name):
        self.name = name
        Tool.count += 1

tool1 = Tool("锤子")
tool2 = Tool("螺丝刀")
tool3 = Tool("钳子")

print("现在创建了 %d 个工具" % Tool.count)
类对象
  • 在程序运行时,类同样会被加载到内存中
  • 在Python中,类是一个特殊的对象 —— 类对象
  • 在程序运行时,类对象在内存中只有一份
  • 类对象拥有自己的属性自己的方法,分别称为类属性类方法
  • 通过类名.的方式访问类属性,调用类方法
面向对象 -- 类属性和类方法_第3张图片
类属性
  • 类属性是针对定义的属性,用于记录与这个类相关的特征
  • 使用类名.类属性名的方式访问
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开始当前玩家的游戏
  • 设计类
面向对象 -- 类属性和类方法_第4张图片
  • 实现类
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_name

    def 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__方法
面向对象 -- 类属性和类方法_第5张图片
  • 单例模式的实现
  • 定义一个类属性,初始值设为None,用于记录单例对象的引用
  • 重写__new__方法
    如果类属性 is None,调用父类方法分配空间,并在类属性中记录结果
    否则返回类属性中记录的对象引用
面向对象 -- 类属性和类方法_第6张图片
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 = True

player1 = MusicPlayer()
print(player1)

player2 = MusicPlayer()
print(player2)
初始化音乐播放器
<__main__.MusicPlayer object at 0x00000000029CA160>
<__main__.MusicPlayer object at 0x00000000029CA160>




- end -

你可能感兴趣的:(面向对象 -- 类属性和类方法)