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.batchesappend 一个空 list,返回这个新 list
创建两个 BatchPool 实例,每个实例各调用 new_batch() 两次,确认两个实例的 batches 互不影响。
💡 思路提示
点开看提示
- 空 list
[]不要放在__init__签名里,要放在方法体里 - 实例方法总是第一个参数是
self 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 兜底,在方法体里初始化可变结构。