如何为含__slots__的外部Python类实例添加额外数据?
解决带有__slots__的外部类实例添加额外数据的问题
你拥有一个不受控制的Python类A的实例a,对A的内部实现(包括__init__方法)完全不了解。由于A定义了__slots__,无法直接给a添加新属性,你希望找到办法让带有额外数据的对象能像A的实例一样正常工作,尝试通过子类化A实现包装类但不知道如何正确初始化父类。
以下是两种可行的解决思路:
方案一:组合+属性代理(推荐,无需依赖父类实现)
不用继承A,而是创建一个包装类持有原A实例的引用,通过__getattr__代理所有原实例的属性和方法。这样包装对象既能完全复用原实例的功能,又能自由添加额外属性。
class A: __slots__ = ["data"] def __init__(self, data): self.data = data # 外部创建的原实例 a = A([1, 2, 3]) class Wrapper: def __init__(self, original_instance, extra_data): self._original = original_instance self.extra_data = extra_data # 代理原实例的所有属性和方法(访问不存在的属性时触发) def __getattr__(self, name): return getattr(self._original, name) # 支持修改原实例的属性(区分包装类自身属性和原实例属性) def __setattr__(self, name, value): if name in ["_original", "extra_data"]: super().__setattr__(name, value) else: setattr(self._original, name, value) # 使用示例 w = Wrapper(a, [27]) print(w.data) # 输出 [1, 2, 3],复用原实例属性 print(w.extra_data) # 输出 [27],自定义额外属性 w.data.append(4) print(a.data) # 输出 [1, 2, 3, 4],原实例同步修改
如果原实例有__str__、__len__这类特殊方法,需要在包装类中手动代理,因为特殊方法会直接从类层面查找,不会触发__getattr__:
def __str__(self): return str(self._original) def __len__(self): return len(self._original)
方案二:子类化+复制原实例状态(适合必须继承A的场景)
如果你的场景要求对象必须是A的子类实例,可以跳过调用父类__init__,直接复制原A实例的所有属性到子类实例中。注意子类不要定义__slots__,这样子类实例会自带__dict__,可以自由添加额外属性。
class A: __slots__ = ["data"] def __init__(self, data): self.data = data a = A([1, 2, 3]) class Wrap(A): # 子类不定义__slots__,保留实例的__dict__用于添加自定义属性 def __init__(self, original_instance, extra_data): # 遍历原实例的__slots__,复制所有属性到子类实例 for slot in original_instance.__slots__: setattr(self, slot, getattr(original_instance, slot)) self.extra_data = extra_data # 使用示例 w = Wrap(a, [27]) print(w.data) # 输出 [1, 2, 3] print(w.extra_data) # 输出 [27] print(isinstance(w, A)) # 输出 True,确实是A的子类实例
如果原类A的__slots__包含继承来的属性,可以用dir(original_instance)过滤出实例属性后再复制。
内容的提问来源于stack exchange,提问作者Nico Schlömer
相关产品推荐
相关产品推荐

