一、类属性(Class Attribute)
1. 定义:
- 属于类本身的属性,所有实例共享。
- 直接在类内部声明(不在 init 中)。
2. 访问:
通过类名或实例均可访问(但修改时需谨慎)。
class Car:
wheels = 4 # 类属性:所有汽车有4个轮子
def __init__(self, brand):
self.brand = brand # 实例属性
# 访问类属性
print(Car.wheels) # 输出: 4
car = Car("Tesla")
print(car.wheels) # 输出: 4(通过实例访问)
3. 修改类属性
- 正确方式:通过类名修改,所有实例会继承新值。
- 错误方式:通过实例修改会创建同名实例属性,覆盖类属性。
# 正确修改类属性
Car.wheels = 6
print(Car.wheels) # 输出: 6
print(car.wheels) # 输出: 6(所有实例同步更新)
# 错误修改(实际创建实例属性)
car.wheels = 8
print(car.wheels) # 输出: 8(实例属性)
print(Car.wheels) # 输出: 6(类属性未变)
4. 作用:
- 共享数据:所有实例共用同一份数据,适合存储与类相关的全局信息。
class Dog:
species = "Canis familiaris" # 类属性:所有狗的物种相同
def __init__(self, name):
self.name = name # 实例属性:每只狗的名字不同
- 节省内存:类属性只存储一次,避免每个实例重复存储相同数据。
- 配置默认值:为实例提供默认值,实例可以覆盖这些值。
class User:
default_role = "guest" # 默认角色
def __init__(self, role=None):
self.role = role or User.default_role # 实例可覆盖默认值
- 统计类级信息:例如统计实例数量。
class Player:
count = 0 # 类属性统计实例数
def __init__(self):
Player.count += 1
二、实例属性(Instance Attribute)
1. 定义:
- 属于某个具体实例的属性,每个实例独立。
- 在 init 方法中通过 self.xxx 初始化。
2. 访问:
只能通过实例访问,每个实例独立。
class User:
def __init__(self, name, age):
self.name = name # 实例属性
self.age = age # 实例属性
user1 = User("Alice", 30)
user2 = User("Bob", 25)
print(user1.name) # 输出: Alice
print(user2.name) # 输出: Bob
3. 作用:
- 存储对象状态:保存对象的独特数据。
class Car:
def __init__(self, color, speed):
self.color = color # 实例属性:每辆车的颜色不同
self.speed = speed # 实例属性:每辆车的速度不同
- 动态属性管理:允许在运行时动态添加或修改属性。
car = Car("red", 100)
car.year = 2023 # 动态添加实例属性
- 隔离数据:不同实例的属性互不影响。
a = Car("red", 100)
b = Car("blue", 80)
a.speed = 120 # 仅修改 a 的 speed,不影响 b
三、类属性与实例属性的混合使用
1. 用类属性为实例提供默认值
class Settings:
theme = "light" # 类属性作为默认主题
def __init__(self):
self.theme = Settings.theme # 实例属性初始化为类属性值
settings = Settings()
settings.theme = "dark" # 修改实例属性,不影响类属性
print(settings.theme) # 输出: dark
print(Settings.theme) # 输出: light
2. 类属性与实例属性同名时的优先级
class MyClass:
attr = "类属性" # 类属性
def __init__(self):
self.attr = "实例属性" # 同名实例属性
obj = MyClass()
print(obj.attr) # 输出: 实例属性(实例属性优先级更高)
print(MyClass.attr) # 输出: 类属性
四、注意事项与常见错误
1. 避免通过实例修改类属性
class Animal:
category = "哺乳动物"
dog = Animal()
dog.category = "爬行动物" # 错误!实际创建了实例属性
print(dog.category) # 输出: 爬行动物
print(Animal.category) # 输出: 哺乳动物(类属性未变)
2. 可变类属性的副作用
若类属性是可变对象(如列表、字典),所有实例共享同一份数据:
class Student:
grades = [] # 类属性是列表
def add_grade(self, grade):
self.grades.append(grade)
s1 = Student()
s2 = Student()
s1.add_grade(90)
s2.add_grade(80)
print(s1.grades) # 输出: [90, 80](所有实例共享)
解决方案:在 init 中初始化可变对象:
class Student:
def __init__(self):
self.grades = [] # 实例属性,每个实例独立
def add_grade(self, grade):
self.grades.append(grade)
s1 = Student()
s2 = Student()
s1.add_grade(90)
s2.add_grade(80)
print(s1.grades) # 输出: [90]
print(s2.grades) # 输出: [80]
五、最佳实践
- 类属性用于:
- 全局配置、共享数据、统计信息。
- 避免存储可变状态(除非明确需要共享)。
- 实例属性用于:
- 对象特有的状态、动态数据。
- 优先在 __init__ 中初始化。
- 命名规范:
- 类属性用全大写表示常量(如 MAX_SPEED = 200)。
- 实例属性用蛇形命名法(如 user_name)。
总结
场景 | 类属性 | 实例属性 |
---|---|---|
归属 | 属于类 | 属于实例 |
定义位置 | 类内部直接声明 | __init__ 中通过 self.xxx 初始化 |
数据共享性 | 所有实例共享 | 实例独立 |
修改影响范围 | 修改后所有实例可见 | 仅影响当前实例 |
修改方式 | 通过类名修改(ClassName.attr) | 通过实例修改(self.attr) |
典型用途 | 全局配置、统计计数、默认值 | 对象状态、临时数据 |