
本文介绍一种兼顾兼容性与功能扩展的 Python 类设计策略:通过自定义代理列表类,在保持原有 main 列表可直接操作(如 .append()、.remove())的同时,实时、透明地更新经过转换的 dependent 列表,避免手动同步遗漏或性能浪费。
本文介绍一种兼顾兼容性与功能扩展的 python 类设计策略:通过自定义代理列表类,在保持原有 `main` 列表可直接操作(如 `.append()`、`.remove()`)的同时,实时、透明地更新经过转换的 `dependent` 列表,避免手动同步遗漏或性能浪费。
在遗留系统中,常面临“不能改接口,但需新增逻辑”的典型约束。如题所示:self.main 已被多处代码直接读写(包括第三方调用),无法轻易替换为 property;而新需求要求 self.dependent 始终是 self.main 中每个元素经 inflect.number_to_words() 转换后的结果,并需支持动态增删——此时仅靠 @property setter 完全失效,因为 t.main.append(1) 并未触发 setter,而是直接调用了底层列表对象的方法。
根本解法:用代理列表(Proxy List)接管所有变更行为
我们创建一个 SyncedList 类,它继承自 list(或更安全地采用组合 + collections.abc.MutableSequence),重载所有可能修改内容的方法(append, extend, remove, pop, __setitem__, __delitem__, clear, insert 等),并在每次调用后自动同步更新 dependent 列表:
import inflect
from collections.abc import MutableSequence
p = inflect.engine()
class SyncedList(MutableSequence):
def __init__(self, transform_func, target_list=None):
self._data = [] if target_list is None else target_list
self._transform = transform_func
# 读取操作(委托给底层 list)
def __getitem__(self, index): return self._data[index]
def __len__(self): return len(self._data)
def __iter__(self): return iter(self._data)
# 写入操作(拦截并同步)
def append(self, value):
self._data.append(value)
self._sync_dependent()
def extend(self, values):
self._data.extend(values)
self._sync_dependent()
def remove(self, value):
self._data.remove(value)
self._sync_dependent()
def pop(self, index=-1):
result = self._data.pop(index)
self._sync_dependent()
return result
def __setitem__(self, index, value):
self._data[index] = value
self._sync_dependent()
def __delitem__(self, index):
del self._data[index]
self._sync_dependent()
def insert(self, index, value):
self._data.insert(index, value)
self._sync_dependent()
def clear(self):
self._data.clear()
self._sync_dependent()
def _sync_dependent(self):
# 注意:此处假设 dependent 是实例属性名,实际使用时需传入引用或绑定
pass # 具体同步逻辑由外部控制,见下文 T 类实现
# 必须实现的抽象方法(MutableSequence 要求)
def __eq__(self, other): return self._data == list(other)
接下来,在主类 T 中使用该代理,并将 dependent 设为只读属性(或保留为普通属性,由代理内部维护):
class T:
def __init__(self):
self._main = []
self._dependent = [] # 真实存储转换后数据的私有列表
# 将 main 设为代理列表,绑定转换函数和同步逻辑
self.main = SyncedList(
transform_func=lambda x: p.number_to_words(x),
target_list=self._main
)
# 重写 SyncedList 的 _sync_dependent 方法,使其更新 _dependent
self.main._sync_dependent = self._update_dependent
def _update_dependent(self):
self._dependent = [p.number_to_words(x) for x in self._main]
@property
def dependent(self):
return self._dependent.copy() # 返回副本,防止外部误改
# 可选:提供便捷的 dict 序列化支持(解决 __dict__ 问题)
def to_dict(self):
return {
'main': self._main,
'dependent': self._dependent,
# 其他需要导出的字段...
}
现在验证行为:
t = T() t.main.append(1) print(t.main) # [1] print(t.dependent) # ['one'] t.main.extend([2, 3]) print(t.main) # [1, 2, 3] print(t.dependent) # ['one', 'two', 'three'] t.main[0] = 10 print(t.main) # [10, 2, 3] print(t.dependent) # ['ten', 'two', 'three']
✅ 优势总结:
- ✅ 零侵入遗留代码:
t.main.append()等所有原生操作完全可用,无需修改任何调用方; - ✅ 强一致性:所有变更路径均被拦截,
dependent始终与main严格同步; - ✅ 支持
__dict__导出:_main和_dependent均为真实实例属性,可被序列化工具识别; - ✅ 可扩展性强:如需缓存、惰性计算或异步更新,均可在
_sync_dependent中增强。
⚠️ 注意事项:
- 若
main需支持切片赋值(如t.main[1:3] = [4,5]),需额外实现__setslice__(Python __setitem__ 对slice类型的支持; - 对于超大列表,频繁全量重建
dependent可能有性能压力,此时可改为增量更新(如记录变更索引); -
dependent属性返回.copy()是防御性设计,若确定外部不会修改,可直接返回self._dependent提升效率。
这种代理模式在 ORM、响应式编程、数据管道等场景中广泛应用,本质是将“状态同步”从分散的手动调用,收束到单一可控的变更入口,是平衡演进与稳定性的工程典范。










