实例属性和类属性

Python 类属性与实例属性详解

1. 属性基本概念

在 Python 中,类和实例都可以拥有属性,但它们的绑定方式和作用范围有所不同:

  • 实例属性:属于特定实例的属性,通过 self 或实例变量绑定
  • 类属性:属于类本身的属性,直接在类中定义

2. 实例属性

实例属性是最常见的属性类型,每个实例都有自己独立的属性副本:

class Student:
    def __init__(self, name):
        self.name = name  # 实例属性

s1 = Student('Alice')
s2 = Student('Bob')

print(s1.name)  # 输出: Alice
print(s2.name)  # 输出: Bob

实例属性也可以在创建后动态添加:

s1.score = 90  # 动态添加实例属性

3. 类属性

类属性属于类本身,所有实例共享:

class Student:
    school = 'XYZ School'  # 类属性
    
    def __init__(self, name):
        self.name = name

s1 = Student('Alice')
s2 = Student('Bob')

print(s1.school)  # 输出: XYZ School
print(s2.school)  # 输出: XYZ School
print(Student.school)  # 输出: XYZ School

4. 属性访问优先级

当实例属性和类属性同名时,实例属性会优先被访问:

class Student:
    name = 'Student'  # 类属性

s = Student()
print(s.name)  # 输出: Student (访问类属性)

s.name = 'Michael'  # 添加实例属性
print(s.name)  # 输出: Michael (访问实例属性)
print(Student.name)  # 输出: Student (类属性不变)

del s.name  # 删除实例属性
print(s.name)  # 输出: Student (再次访问类属性)

5. 最佳实践

  1. 避免同名:不要为实例属性和类属性使用相同的名字
  2. 类属性用于共享数据:适合存储类级别的常量或统计信息
  3. 实例属性用于实例特有数据:每个实例需要独立维护的数据

6. 实用示例:统计实例数量

class Student:
    count = 0  # 类属性,用于统计实例数量

    def __init__(self, name):
        self.name = name
        Student.count += 1  # 每次创建实例时增加计数

# 测试代码
if __name__ == '__main__':
    print(f'初始学生数: {Student.count}')  # 0
    
    s1 = Student('Alice')
    s2 = Student('Bob')
    
    print(f'当前学生数: {Student.count}')  # 2
    print(f'通过类访问: {Student.count}')  # 2
    print(f'通过实例访问: {s1.count}')  # 2

7. 现代 Python 中的属性管理

在 Python 3.7+ 中,可以使用 @dataclass 更清晰地管理属性:

from dataclasses import dataclass

@dataclass
class Student:
    name: str  # 实例属性
    school: str = 'XYZ School'  # 带默认值的实例属性
    
    # 类属性仍然可以单独定义
    count: int = 0
    
    def __post_init__(self):
        Student.count += 1

8. 总结

特性实例属性类属性
定义位置__init__ 方法或实例上类定义中
访问方式instance.attrClass.attrinstance.attr
存储位置每个实例独立存储类对象存储
修改影响只影响当前实例影响所有实例
典型用途实例特有数据共享数据、常量

遵循这些原则可以避免属性访问中的常见错误,并编写更清晰、更易维护的代码。