在 Python 中,类变量和实例变量是面向对象编程的基础概念,理解它们的访问方式和区别对编写清晰的代码至关重要。以下是详细的步骤演示与问题排查指南:

一、类变量与实例变量的定义

  • 类变量:定义在类中,所有实例共享的变量(属于类本身)。
  • 实例变量:定义在 __init__ 方法中,通过 self 绑定,每个实例独立拥有的变量。

二、访问步骤演示

1. 定义类并声明变量

python

运行

class Person:
    # 类变量:所有实例共享
    species = "人类"  # 类变量
    
    def __init__(self, name):
        # 实例变量:每个实例独立
        self.name = name  # 实例变量
2. 访问类变量

类变量可通过 类名 或 实例对象 访问(推荐用类名,避免歧义)。

python

运行

# 1. 通过类名访问(推荐)
print(Person.species)  # 输出:人类

# 2. 通过实例对象访问
p1 = Person("Alice")
print(p1.species)      # 输出:人类(实例会先查找自身,找不到则找类变量)
3. 访问实例变量

实例变量只能通过实例对象访问(需先创建实例)。

python

运行

p1 = Person("Alice")
print(p1.name)  # 输出:Alice(正确:通过实例访问)

# 错误:实例变量不能通过类名访问
print(Person.name)  # 报错:AttributeError: type object 'Person' has no attribute 'name'
4. 修改变量的注意事项
  • 修改类变量:需通过类名修改,否则会变成实例变量。

    python

    运行

    # 正确:通过类名修改,所有实例共享变化
    Person.species = "智人"
    p2 = Person("Bob")
    print(p2.species)  # 输出:智人(所有实例都会受影响)
    
    # 错误:通过实例修改类变量(实际是给实例新增了同名实例变量)
    p1.species = "机器人"  # 仅 p1 有此实例变量,类变量不受影响
    print(Person.species)  # 输出:智人(类变量不变)
    print(p1.species)      # 输出:机器人(实例变量覆盖)
    
  • 修改实例变量:只能通过实例对象修改,不影响其他实例。

    python

    运行

    p1.name = "Alicia"
    print(p1.name)  # 输出:Alicia
    p2 = Person("Bob")
    print(p2.name)  # 输出:Bob(不受 p1 修改影响)
    

三、常见问题排查

1. 报错:AttributeError: 'XXX' object has no attribute 'YYY'
  • 原因 1:访问了未定义的实例变量(如拼写错误或未在 __init__ 中初始化)。

    python

    运行

    p1 = Person("Alice")
    print(p1.age)  # 报错:未定义 age 实例变量
    

    解决:在 __init__ 中添加 self.age = age 并初始化。

  • 原因 2:通过类名访问实例变量。

    python

    运行

    print(Person.name)  # 报错:类不能直接访问实例变量
    

    解决:创建实例后通过实例访问。

2. 类变量修改后不生效
  • 原因:误通过实例修改类变量,导致实例新增了同名变量,掩盖了类变量。

    python

    运行

    Person.species = "人类"
    p1 = Person("Alice")
    p1.species = "机器人"  # 实际是实例变量
    print(Person.species)  # 仍为 "人类"(类变量未变)
    
    解决:修改类变量必须用 类名.变量名
3. 实例变量共享问题
  • 原因:错误地将实例变量定义为类变量(导致所有实例共享同一变量)。

    python

    运行

    class Person:
        names = []  # 错误:类变量(所有实例共享列表)
        
        def __init__(self, name):
            self.names.append(name)  # 所有实例都会添加到同一个列表
    
    p1 = Person("Alice")
    p2 = Person("Bob")
    print(p1.names)  # 输出:['Alice', 'Bob'](非预期的共享)
    
    解决:将共享变量改为实例变量(在 __init__ 中初始化):

    python

    运行

    def __init__(self, name):
        self.names = [name]  # 每个实例独立的列表
    

四、总结

  • 类变量:属于类,所有实例共享,通过 类名.变量 访问 / 修改。
  • 实例变量:属于实例,独立存在,通过 实例.变量 访问 / 修改。
  • 避免通过实例修改类变量,避免将需要独立的变量定义为类变量。

掌握这些规则可以有效减少变量访问错误,写出更清晰的面向对象代码。

Logo

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

更多推荐