推理基础设施 · Python5.2 __init__ 与属性默认值
05
基础面向对象 · 2 / 5

5.2 __init__ 与属性默认值

💡 推理引擎的 device、dtype、batch_size 几乎都有默认值

5.2 init 与属性默认值

init 里给属性默认值有两种方式

1. 可变默认值不要直接放签名里(经典坑)

def __init__(self, history=[]):   # 不要这样
    self.history = history

所有实例共享同一个 list。

2. 正确做法:在方法体里赋值

def __init__(self):
    self.history = []              # 每次新建实例都是新 list

不可变默认值(int、str、bool、tuple)可以直接放签名

def __init__(self, max_tokens=512, device="cuda"):
    ...

示范

class Batch:
    def __init__(self, max_size=8):
        self.max_size = max_size
        self.requests = []          # 每次新建都是新 list

    def add(self, req):
        if len(self.requests) < self.max_size:
            self.requests.append(req)

b1 = Batch()
b2 = Batch()
b1.add("r1")
print(b1.requests, b2.requests)   # ['r1'] []

✍️ 练习

定义类 BatchPool

  • __init__(self, max_size=4):存 self.max_size,并把 self.batches 初始化为空 list
  • 方法 new_batch(self):向 self.batches append 一个空 list,返回这个新 list

创建两个 BatchPool 实例,每个实例各调用 new_batch() 两次,确认两个实例的 batches 互不影响。

💡 思路提示

点开看提示
  1. 空 list [] 不要放在 __init__ 签名里,要放在方法体里
  2. 实例方法总是第一个参数是 self
  3. append 返回 None,所以方法最后可以 return 那个新 list

✅ 参考解法

写不出来再打开
class BatchPool:
    def __init__(self, max_size=4):
        self.max_size = max_size
        self.batches = []

    def new_batch(self):
        batch = []
        self.batches.append(batch)
        return batch

p1 = BatchPool()
p2 = BatchPool()
p1.new_batch()
p1.new_batch()
p2.new_batch()
print(p1.batches)   # [[], []]
print(p2.batches)   # [[]]

🔍 进阶思考

如果把 __init__(self, max_size=4, batches=[]),两次创建 BatchPool 会共享同一个 list——这就是 mutable default argument 坑。

更隐蔽的写法:

def add(req, store=[]):   # ❌
    store.append(req)
    return store

add("a")
add("c")   # 输出 ['a', 'c'],不是你以为的 ['c']

永远用 None 兜底,在方法体里初始化可变结构。