在 Python 中,类变量和实例变量的访问规则是面向对象编程的基础,理解两者的访问步骤和区别至关重要。以下从定义、访问方式、查找顺序三个维度详解关键步骤:

一、核心定义与存储位置

  1. 类变量

    • 定义在类中、方法外,属于类本身,被所有实例共享。
    • 存储在类的命名空间(类名.__dict__)中。

    python

    运行

    class MyClass:
        class_var = "我是类变量"  # 类变量定义
    
  2. 实例变量

    • 定义在实例方法中(通常是 __init__ 方法),通过 self.变量名 赋值,属于单个实例。
    • 存储在实例的命名空间(实例名.__dict__)中。

    python

    运行

    class MyClass:
        def __init__(self):
            self.instance_var = "我是实例变量"  # 实例变量定义
    

二、访问关键步骤与规则

1. 访问类变量的步骤

类变量可通过 类名 或 实例名 访问,核心规则:

  • 优先从类的命名空间中查找。

步骤拆解

  • 当使用 类名.类变量 访问时:直接在类的命名空间(MyClass.__dict__)中查找目标变量,找到则返回,否则报错。

  • 当使用 实例名.类变量 访问时:

    1. 先检查实例自身的命名空间(obj.__dict__),若存在同名变量(实例覆盖了类变量),则返回实例变量;
    2. 若实例中无同名变量,再去实例所属的类的命名空间(MyClass.__dict__)中查找,找到则返回类变量;
    3. 若类中也无,则继续向上查找父类的命名空间(继承链),直至找到或报错。
2. 访问实例变量的步骤

实例变量只能通过 实例名 访问,核心规则:

  • 必须从实例自身的命名空间中查找,类无法直接访问实例变量。

步骤拆解

  • 当使用 实例名.实例变量 访问时:

    1. 直接在实例的命名空间(obj.__dict__)中查找目标变量;
    2. 若存在则返回,否则报错(即使类中存在同名变量,也不会被访问,因为实例变量与类变量是独立的)。
  • 注意:类名无法访问实例变量,若尝试 类名.实例变量,会直接去类的命名空间查找,若类中无此变量则报错。

三、关键区别与示例验证

python

运行

class MyClass:
    class_var = "类变量初始值"  # 类变量

    def __init__(self):
        self.instance_var = "实例变量初始值"  # 实例变量


# 1. 访问类变量
print(MyClass.class_var)  # 类名访问:直接查类命名空间 → "类变量初始值"
obj = MyClass()
print(obj.class_var)      # 实例访问:实例无同名变量,查类命名空间 → "类变量初始值"

# 2. 实例覆盖类变量(仅影响当前实例)
obj.class_var = "实例覆盖的类变量"  # 给实例新增同名变量(实例变量)
print(obj.class_var)      # 查实例命名空间 → "实例覆盖的类变量"
print(MyClass.class_var)  # 类命名空间未变 → "类变量初始值"

# 3. 访问实例变量
print(obj.instance_var)   # 实例访问 → "实例变量初始值"
# print(MyClass.instance_var)  # 类名访问 → 报错(类中无此变量)

# 4. 修改类变量(影响所有未覆盖该变量的实例)
MyClass.class_var = "修改后的类变量"
obj2 = MyClass()
print(obj2.class_var)     # 实例未覆盖,查类命名空间 → "修改后的类变量"
print(obj.class_var)      # 实例已覆盖,仍查实例命名空间 → "实例覆盖的类变量"

四、总结关键原则

  1. 类变量:类和实例均可访问,实例访问时遵循 “实例优先于类” 的查找顺序;修改类变量会影响所有未覆盖它的实例。
  2. 实例变量:仅实例可访问,类无法直接访问;每个实例的实例变量独立存储,互不影响。
  3. 命名空间优先级:访问变量时,实例命名空间 > 类命名空间 > 父类命名空间(MRO 顺序)。

掌握这些步骤和规则,可避免因变量访问错误导致的逻辑问题,尤其在处理继承和多实例共享数据时更为重要。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐