在 Python 中,类变量和实例变量是面向对象编程的核心概念,它们的访问方式和作用域存在显著差异。以下从定义、访问场景、优先级等方面全面详解两者的访问步骤:

一、核心概念

  • 类变量:定义在类中、方法外的变量,属于类本身,被所有实例共享。
  • 实例变量:定义在实例方法(通常是 __init__)中,通过 self.变量名 声明,属于单个实例,不共享。

二、类变量的访问步骤

类变量可通过 类名 或 实例对象 访问,具体步骤如下:

1. 通过类名访问(推荐)

直接使用 类名.类变量名 访问,步骤:

  • 解析类名,找到对应的类对象。
  • 在类对象的命名空间中查找目标变量。
  • 若存在,返回变量值;若不存在,抛出 AttributeError

示例

python

运行

class Student:
    school = "北京大学"  # 类变量

# 访问步骤:Student → 查找 school → 返回 "北京大学"
print(Student.school)  # 输出:北京大学
2. 通过实例对象访问

使用 实例名.类变量名 访问,步骤:

  • 先在实例对象的命名空间中查找目标变量。
  • 若未找到,向上查找实例所属的类的命名空间。
  • 若类中存在,返回类变量值;否则抛出 AttributeError

示例

python

运行

stu1 = Student()
# 访问步骤:stu1 的命名空间(无 school)→ 查找 Student 类 → 找到 school → 返回 "北京大学"
print(stu1.school)  # 输出:北京大学

三、实例变量的访问步骤

实例变量只能通过 实例对象 访问,步骤:

  • 解析实例名,找到对应的实例对象。
  • 在实例对象的命名空间(__dict__)中查找目标变量。
  • 若存在,返回变量值;若不存在,抛出 AttributeError不会去类中查找)。

示例

python

运行

class Student:
    def __init__(self, name):
        self.name = name  # 实例变量

stu1 = Student("张三")
# 访问步骤:stu1 → 查找 name → 返回 "张三"
print(stu1.name)  # 输出:张三

# 错误:实例变量不能通过类名访问
print(Student.name)  # 报错:AttributeError: type object 'Student' has no attribute 'name'

四、访问优先级与覆盖问题

当实例变量与类变量同名时,实例变量会覆盖类变量(仅对当前实例有效),访问步骤如下:

  1. 通过实例访问时,优先返回实例变量(实例命名空间存在该变量)。
  2. 通过类名访问时,仍返回类变量(类命名空间的变量未被修改)。

示例

python

运行

class Student:
    school = "北京大学"  # 类变量

stu1 = Student()
stu1.school = "清华大学"  # 给 stu1 绑定实例变量(与类变量同名)

# 实例访问:优先实例变量
print(stu1.school)  # 输出:清华大学(实例变量)
# 类访问:仍为类变量
print(Student.school)  # 输出:北京大学(类变量)

五、修改变量的注意事项

  1. 修改类变量

    • 必须通过 类名.类变量名 = 新值,否则会变成给实例绑定新的实例变量。

    python

    运行

    Student.school = "浙江大学"  # 正确修改类变量,所有实例共享新值
    stu1.school = "南京大学"  # 错误:仅给 stu1 新增实例变量,不影响类和其他实例
    
  2. 修改实例变量

    • 只能通过 实例名.实例变量名 = 新值,直接修改实例的命名空间。

六、总结访问步骤对比

变量类型 访问方式 查找顺序(优先级) 是否共享
类变量 类名 / 实例名 实例命名空间 → 类命名空间
实例变量 仅实例名 仅实例命名空间(不查类)

通过理解以上步骤,可以清晰区分类变量和实例变量的访问逻辑,避免因作用域混淆导致的错误。

Logo

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

更多推荐