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

实例对象

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

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

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

  • 创建出来的对象叫做类的实例
  • 创建对象的动作叫做实例化
  • 对象的属性叫做实例属性
  • 对象调用的方法叫做实例方法

在程序执行时:

  • 每一个对象都有自己独立的内存空间,保存各自不同的属性
  • 可以通过self.访问自己的属性,调用自己的方法
  • 多个对象的方法,在内存中只有一份,调用方法时将当前对象的引用传递到方法内部
实例演示:工具箱
  • 定义一个工具类,每件工具都有自己的name属性
  • 定义一个类属性记录该类创建了多少个工具对象?
  • 设计类
  • 实现类
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中,类是一个特殊的对象 —— 类对象
  • 在程序运行时,类对象在内存中只有一份
  • 类对象拥有自己的属性自己的方法,分别称为类属性类方法
  • 通过类名.的方式访问类属性,调用类方法
类属性
  • 类属性是针对定义的属性,用于记录与这个类相关的特征
  • 使用类名.类属性名的方式访问
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_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__方法
  • 单例模式的实现
  • 定义一个类属性,初始值设为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 = True

player1 = MusicPlayer()
print(player1)

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




- end -

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容