1. 类的结构

1.1 术语 —— 实例

  • 1.使用面向对象开发,第一步是设计类。

  • 2.使用 类名() 创建对象,创建对象的动作有两步:

    • 在内存中为对象分配空间。

    • 调用初始化方法 __init__ 为对象初始化。

对象创建后,内存中就有了一个对象的实实在在的存在,我们称之为实例。

因此,我们通常会把以下内容进行转换:

  • 1.创建出来的 对象 称为 实例,就像是每个人都是某个明星的铁杆粉丝一样。

  • 2.创建对象的 动作 称为 实例化,就像是粉丝们追星一样,追求与偶像的亲密接触。

  • 3.对象的属性 称为 实例属性,就像是粉丝们的个人特点和喜好一样,每个人都有自己独特的品味。

  • 4.对象调用的方法 称为 实例方法,就像是粉丝们展示自己对偶像的支持和热爱一样,通过各种方式表达自己的情感。

在程序执行时:

  • 1.对象各自拥有自己的 实例属性,就像是每个粉丝都有自己独特的特点和喜好。

  • 2.调用对象方法,可以通过 self.,就像是粉丝们互相传递彼此的心意和信息。

    • 访问自己的属性,就像是粉丝们展示自己的个性和喜好。

    • 调用自己的方法,就像是粉丝们展示自己对偶像的支持和热爱。

结论

  • 每一个对象 都有自己 独立的内存空间保存各自不同的属性,就像是每个粉丝都有自己的个性和喜好。

  • 多个对象的方法,在内存中只有一份,在调用方法时,需要把对象的引用 传递到方法内部,就像是粉丝们互相传递彼此的心意和信息。

1.2 类是一个特殊的对象

在 Python 中,一切都是对象,就像是一群特殊的人:

  • class AAA:定义的类就像是一个类对象,可以看作是一个特殊的人类。

  • obj1 = AAA():创建的实例对象就像是一个具体的人,属于这个特殊的人类。

  • 在程序运行时,类也会被加载到内存中,就像是这个特殊的人类在我们的大脑中占据一席之地。

  • 在 Python 中,类是一种特殊的对象,我们称之为类对象。

  • 在内存中,类对象只有一份,就像是这个特殊的人类只有一个。

  • 通过一个类,我们可以创建出很多个对象实例,就像是这个特殊的人类可以有很多个具体的人。

  • 除了封装实例的属性和方法外,类对象还可以拥有自己的属性和方法,就像是这个特殊的人类可以有自己的特点和技能。

    • 类属性:就像是这个特殊的人类共有的特点,可以通过类名访问。

    • 类方法:就像是这个特殊的人类共有的技能,可以通过类名调用。

  • 通过 类名. 的方式,我们可以访问类的属性或者调用类的方法,就像是我们可以通过特殊的人类的名字找到他们的特点和技能。

2. 类属性和实例属性

2.1 概念和使用

  • 类属性 是指在 类对象 中定义的属性,用于记录与这个类相关的特征。

  • 类属性通常用来记录与类本身相关的信息,而不是具体对象的特征。

示例需求

  • 我们要定义一个工具类,每个工具都有自己的名称。

  • 现在的需求是,我们想知道使用这个类创建了多少个工具对象。

class Tool(object):

    # 使用赋值语句,定义类属性,记录创建工具对象的总数
    count = 0

    def __init__(self, name):
        self.name = name

        # 针对类属性做一个计数+1
        Tool.count += 1


# 创建工具对象
tool1 = Tool("斧头")
tool2 = Tool("榔头")
tool3 = Tool("铁锹")

# 知道使用 Tool 类到底创建了多少个对象?
print("现在创建了 %d 个工具" % Tool.count)

2.2属性的获取机制(科普)

在 Python 中,属性的获取存在一个有趣的向上查找机制。就像是在寻找宝藏一样,Python 会从下往上搜索属性的值。

属性的获取机制

因此,要访问类属性有两种方式:

  • 使用 类名.类属性 这种方式,就像是直接从宝藏地图上找到宝藏的位置一样简单明了。

  • 使用 对象.类属性 这种方式,虽然也能找到宝藏,但是不推荐使用。就像是要找到宝藏,却要先找到藏宝图,再根据藏宝图找到宝藏一样麻烦。

需要注意的是,如果使用 对象.类属性 = 值 这样的赋值语句,只会给对象添加一个属性,而不会影响到类属性的值。就像是在宝藏中添加了一个额外的宝物,但并没有改变宝藏本身的价值。

所以,记住这个属性的获取机制,就像是记住了寻找宝藏的秘诀一样,让你在 Python 的世界中游刃有余!

3. 类方法和静态方法

3.1 类方法

  • 类属性 就是针对 类对象 定义的属性。

    • 使用 赋值语句class 关键字下方可以定义 类属性

    • 类属性 用于记录 与这个类相关的特征。

  • 类方法 就是针对 类对象 定义的方法。

    • 类方法 内部可以直接访问 类属性 或者调用其他的 类方法

语法如下

@classmethod
def 类方法名(cls):
    pass
  • 嘿,小伙伴们!今天我们要来聊一聊类方法的使用。你知道吗,类方法是一种特殊的方法,需要用修饰器@classmethod来标识,这样解释器才能知道它是一个类方法哦。

  • 类方法的第一个参数通常是cls,这个cls其实就是调用这个方法的那个类的引用。就像实例方法的第一个参数是self一样,cls也是个约定俗成的名字,当然你也可以用其他的名字,但是习惯上我们都叫它cls

  • 调用类方法的时候,你只需要通过类名加一个点来调用就可以了,不需要传递cls参数。真是方便呢!

  • 在类方法的内部,你可以通过cls.来访问类的属性,也可以通过cls.来调用其他的类方法。这样一来,我们就可以在类方法中做一些与类相关的操作了。

现在,让我们来看一个示例需求吧!

假设我们要定义一个工具类,每个工具都有自己的名字。我们还有一个需求,就是要在类中封装一个show_tool_count的类方法,用来输出使用当前这个类创建的对象个数。那么,我们该怎么做呢?

class Tool:
    count = 0  # 类属性,用来记录对象个数

    def __init__(self, name):
        self.name = name
        Tool.count += 1  # 每次创建对象时,对象个数加1

    @classmethod
    def show_tool_count(cls):
        print(f"当前共有{cls.count}个工具对象")  # 通过cls访问类属性

# 创建工具对象
tool1 = Tool("锤子")
tool2 = Tool("扳手")
tool3 = Tool("螺丝刀")

# 调用类方法
Tool.show_tool_count()

运行上面的代码,你会发现输出了当前共有3个工具对象。是不是很简单呢?类方法真是太好用了!记得要多多尝试,掌握这个技巧,让你的代码更加优雅!加油!

@classmethod
def show_tool_count(cls):
    """显示工具对象的总数"""
    print("工具对象的总数 %d" % cls.count)

在类方法内部,可以直接使用 cls 访问 类属性 或者 调用类方法

3.2 静态方法

在开发时,有时候我们需要在类中封装一个方法,这个方法既不需要访问实例属性或调用实例方法,也不需要访问类属性或调用类方法。这种情况下,我们可以将这个方法封装成一个静态方法。

静态方法的语法如下:

@staticmethod
def 静态方法名():
    pass

静态方法需要使用修饰器@staticmethod来标识,告诉解释器这是一个静态方法。我们可以通过类名来调用静态方法。

举个例子,我们定义了一个Dog类,其中有一个静态方法run

class Dog(object):
    
    # 狗对象计数
    dog_count = 0
    
    @staticmethod
    def run():
        
        # 不需要访问实例属性也不需要访问类属性的方法
        print("狗在跑...")

    def __init__(self, name):
        self.name = name

3.3 方法综合案例

现在我们来看一个方法综合案例的需求:

  1. 设计一个Game类。

  2. 属性:

    • 定义一个类属性top_score,用于记录游戏的历史最高分。

    • 定义一个实例属性player_name,用于记录当前游戏的玩家姓名。

  3. 方法:

    • 静态方法show_help,用于显示游戏帮助信息。

    • 类方法show_top_score,用于显示历史最高分。

    • 实例方法start_game,用于开始当前玩家的游戏。

  4. 主程序步骤:

    • 查看帮助信息。

    • 查看历史最高分。

    • 创建游戏对象,开始游戏。

案例小结:

  1. 实例方法是需要访问实例属性的方法,实例方法内部可以使用类名.来访问类属性。

  2. 类方法是只需要访问类属性的方法。

  3. 静态方法是不需要访问实例属性和类属性的方法。

如果方法内部既需要访问实例属性,又需要访问类属性,那么应该定义成实例方法。因为类只有一个,实例方法内部可以使用类名.来访问类属性。

举个例子,我们定义了一个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

# 1. 查看游戏帮助
Game.show_help()

# 2. 查看游戏最高分
Game.show_top_score()

# 3. 创建游戏对象,开始游戏
game = Game("小明")

game.start_game()

# 4. 游戏结束,查看游戏最高分
Game.show_top_score()