Python中的动态继承

时间:2014-01-11 08:08:19

标签: python inheritance

假设我有两个不同的类

实现
class ParentA:
    def initialize(self):
        pass

    def some_event(self):
        pass

    def order(self, value):
        # handle order in some way for Parent A


class ParentB:
    def initialize(self):
        pass

    def some_event(self):
        pass

    def order(self, value):
        # handle order in another for Parent B

如何动态地让某些第3类继承ParentAParentB基于这样的内容?

class MyCode:
    def initialize(self):
        self.initial_value = 1

    def some_event(self):
        # handle event
        order(self.initial_value)


# let MyCode inherit from ParentA and run
run(my_code, ParentA)

4 个答案:

答案 0 :(得分:47)

只需将类对象存储在变量中(在下面的示例中,它名为base),并使用class语句的基类规范中的变量。

def get_my_code(base):

    class MyCode(base):
        def initialize(self):
          ...

    return MyCode

my_code = get_my_code(ParentA)

答案 1 :(得分:5)

此外,您可以使用type内置。作为可调用的,它需要参数:name, bases, dct(最简单的形式)。

def initialize(self):
    self.initial_value = 1

def some_event(self):
    # handle event
    order(self.initial_value)

subclass_body_dict = {
    "initialize": initialize,
    "some_event": some_event
}

base_class = ParentA # or ParentB, as you wish

MyCode = type("MyCode", (base_class, ), subclass_body_dict)

这比snx2解决方案更明确,但仍然 - 我更喜欢他的方式。

PS。当然,您不必存储base_class,也不必存储subclass_body_dict,您可以在type()调用中构建这些值,如:

MyCode = type("MyCode", (ParentA, ), {
        "initialize": initialize,
        "some_event": some_event
    })

答案 2 :(得分:1)

就像一个快速复制和粘贴准备好的片段一样,我添加了来自 shx2's answer 的注释来创建它(使用 created_classes dict 属性记忆,以便由连续创建的类相同类的相同调用将提供相同的类):

class ParentA:
    val = "ParentA"

class ParentB:
    val = "ParentB"

class DynamicClassCreator():
    def __init__(self):
        self.created_classes = {}
    def __call__(self, *bases):
        rep = ",".join([i.__name__ for i in bases])
        if rep in self.created_classes:
            return self.created_classes[rep]
        class MyCode(*bases):
            pass
        self.created_classes[rep] = MyCode
        return MyCode

creator = DynamicClassCreator()

instance1 = creator(ParentA, ParentB)()
print(instance1.val) #prints "ParentA"

instance2 = creator(ParentB, ParentA)()
print(instance2.val) #prints "ParentB"

如果你想变得有趣,你甚至可以让 DynamicClassCreator 成为单例:https://stackoverflow.com/a/7346105/5122790

答案 3 :(得分:0)

作为 Chris's answer 实现 shx2's answer 备忘建议的替代方法,我更喜欢使用 memoize decorator(最终结果仍然是一个类,但我更清楚的是function 是接口),并且还使用 setdefault 来简化添加到 memo dict 中,并且不将名称转换为字符串而是使用元组 bases 本身作为键,将代码简化为:< /p>

class Memoize:
    def __init__(self, f):
        self.f = f
        self.memo = {}

    def __call__(self, *args):
        return self.memo.setdefault(args, self.f(*args))

class ParentA:
    def initialize(self):
        pass


class ParentB:
    def initialize(self):
        pass


@Memoize
def get_my_code(base):

    class MyCode(base):
        def initialize(self):
          pass

    return MyCode

a1 = get_my_code(ParentA)
a2 = get_my_code(ParentA)
b1 = get_my_code(ParentB)

print(a1 is a2) # True
print(a1 is b1) # False

(不是一个很好的例子,因为提供的代码除了覆盖父类的 initialize 方法之外实际上没有做任何事情......)