根据python中的属性值动态添加mixin到类中

问题描述 投票:0回答:1

我想在一个对象中动态添加一个 mixin 类,而不影响该类的任何其他对象。我有一个外部服务来确定哪个 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, some_value):
        self.mixin = external_function(some_value)


b1 = B('X')  # Let's say it should use MixinA
print(b1.name, b1.__class__.__base__)

b2 = B('Y') # Let's say it should use 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 的所有属性/方法。

编辑:更新了描述和代码片段以更加清晰。

python inheritance mixins
1个回答
0
投票

不要更改现有对象的基类,而是在实例化之前定义适当的子类

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), {})
仅创建一次。)

© www.soinside.com 2019 - 2024. All rights reserved.