如何在实际开发中选择使用类变量和实例变量?

一、核心选择准则(一句话判断)

只要是所有实例共用、不会随单个对象变化的数据 → 用类变量; 只要是每个对象独有的、彼此不一样的数据 → 必须用实例变量。

二、什么时候优先用【类变量】

1. 全局固定常量、配置类数据

所有实例取值完全相同,不会单独修改某个实例的该字段。 示例:接口地址、超时时间、默认分页条数、统一状态码、地区常量、类描述。

python

运行

复制代码
class OrderService:
    # 类变量:全局统一配置
    DEFAULT_TIMEOUT = 30
    PAY_GATEWAY_URL = "https://pay.xxx.com"

    def __init__(self, order_no):
        self.order_no = order_no

优势:只存一份内存,大量实例节省内存,初始化更快。

2. 统计类、全局计数器

统计当前类一共创建了多少个实例、全局请求次数。

python

运行

复制代码
class User:
    total_count = 0

    def __init__(self):
        User.total_count += 1

3. 类级别的缓存、全局共享容器(慎用)

所有实例需要共用一份缓存字典、连接池对象。 ⚠️ 注意:多线程场景要手动加锁防止并发错乱。

4. 枚举、类型标记

比如订单类型、用户角色枚举,全项目统一不变。

类变量使用避坑

不要通过 实例.变量 = xxx 赋值,会生成实例变量,破坏共享设计; 修改类变量统一用 类名.变量 = xxx

三、什么时候必须用【实例变量】

1. 每个对象独有属性

姓名、手机号、订单号、价格、创建时间、用户 ID 等,每个实例值都不一样。

python

运行

复制代码
class User:
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone

2. 会被单个实例单独修改的数据

某个对象要独立修改属性,不能影响其他实例。 比如用户余额、商品库存、临时状态标记。

3. 可变对象(list/dict)且需要数据隔离

如果用类变量存列表,A 实例 append 会影响所有实例,大概率产生 Bug,这种场景一定要用实例变量:

python

运行

复制代码
# 错误写法
class Order:
    goods_list = []

# 正确写法
class Order:
    def __init__(self):
        self.goods_list = []

4. 业务上需要对象销毁时自动释放的数据

实例被回收,实例变量自动释放,减少全局常驻内存占用。

四、特殊场景怎么选

场景 1:默认值,大部分实例相同,少量实例自定义

类变量当默认值,需要自定义时在实例覆盖:

python

运行

复制代码
class Goods:
    default_status = 1

    def __init__(self):
        # 大部分商品用默认状态,不用赋值
        pass

g1 = Goods()
g2 = Goods()
g2.default_status = 2  # 仅当前商品修改

场景 2:需要序列化、ORM 映射(数据库字段)

ORM 模型(Django/Flask-SQLAlchemy)中:

  • 表字段声明写在类上(类变量),用来做表结构映射;
  • 每行记录的数据存在实例变量中。

场景 3:工具类、工具方法封装

工具类没有实例属性,全部配置、常量使用类变量,甚至可以直接用类方法调用,不用实例化。

五、选择决策流程图

  1. 这个数据是不是所有实例完全一样?
    • 是 → 类变量
  2. 是否允许一个实例修改后,其他实例同步看到变化?
    • 是 → 类变量;否 → 实例变量
  3. 是不是列表、字典这类可变容器?
    • 大部分情况用实例变量;全局缓存 / 连接池才用类变量 + 加锁
  4. 对象销毁后该数据是否需要释放?
    • 需要释放 → 实例变量;需要全局常驻 → 类变量

六、开发最佳实践

  1. 常量全大写命名,统一放在类顶部作为类变量,便于统一维护;
  2. 实例变量统一在 __init__ 中初始化,不要随意在业务方法中动态新增;
  3. 海量实例场景,公共配置放类变量,减少内存占用;
  4. 可变容器优先实例变量,避免无意修改全局数据;
  5. 类变量尽量通过类名访问,减少属性向上查找的微小性能损耗;
  6. 实例特别多且属性固定,使用 __slots__ 优化实例变量内存。

七、常见错误案例

错误 1:可变对象当类变量存默认值

python

运行

复制代码
class Student:
    tags = []
    def __init__(self, name):
        self.name = name

s1 = Student("张三")
s1.tags.append("优秀")
s2 = Student("李四")
print(s2.tags)  # ['优秀'] 被污染

✅ 正确:在__init__里初始化列表为实例变量。

错误 2:把独有业务字段定义成类变量

会导致所有实例数据互相覆盖。

需要我整理一份面试高频场景选型速记表吗?