我想在一个对象中动态添加一个 mixin 类,而不影响该类的任何其他对象。我目前正在使用元类来动态地将基类添加到对象中。但问题是,如果我更改任何对象的基类,它也会影响所有其他对象。这是示例代码片段:
class M(type):
def __call__(cls, *args, **kwargs):
obj = type.__call__(cls, *args, **kwargs)
if hasattr(obj, "mixin"):
obj.__class__.__bases__ = (obj.mixin,) + obj.__class__.__bases__
return obj
class MixinA:
name = "A"
attr1 = 100
class MixinB:
name = "B"
attr2 = 200
class A(metaclass=M):
pass
class B(A):
def __init__(self, mixin_cls):
self.mixin = mixin_cls
b1 = B(MixinA)
print(b1.name, b1.__class__.__base__)
b2 = B(MixinB)
print(b2.name, b2.__class__.__base__)
print(b1.name, b1.__class__.__base__)
这将输出:
A <class '__main__.MixinA'>
B <class '__main__.MixinB'>
B <class '__main__.MixinB'>
我该怎么做才能更改
b2
的基类不会影响 b1
。所以输出应该是:
A <class '__main__.MixinA'>
B <class '__main__.MixinB'>
A <class '__main__.MixinA'>
或者是否有其他方法可以访问/执行动态应用于该对象的适当 mixin 的所有属性/方法。
不要更改现有对象的基类,而是在实例化之前定义适当的子类
B
。这根本不需要元类,只需要一个工厂函数。类似的东西
class A:
pass
class B(A):
pass
class MixinA:
pass
class MixinB:
pass
_cache = {}
def compose_classes(base, *mixins):
t = (base, ) + mixins
if t not in _cache:
name = f'{base.__name__}With{''.join(x.__name__ for x in mixins)}'
_cache[t] = type(name, t, {})
return _cache[t]
b1 = compose_classes(B, MixinA)()
b2 = compose_classes(B, MixinB)()
b3 = compose_classes(B, MixinA)()
b1
、b2
和b3
都是B
的实例,b1
和b3
是B
同一子类的实例。 (即,type(..., (B, MixinA), {})
仅创建一次。)