【问题标题】:Inherit dynamic object in python在python中继承动态对象
【发布时间】:2017-07-28 11:14:26
【问题描述】:

我想创建一个子类“sub()”,它可以继承对象“A(object)”或对象“B(object)”。

以下适用于此:

class A(object):
    def __init__(self):
        print "Class A was inherited"


class B(object):
    def __init__(self):
        print "Class B was inherited"


class sub(A if inh==A else B):
    def __init__(self,inh):
        if inh==A:
            A.__init__(self)
        else:
            B.__init__(self)

但是,当我构造“sub()”时,“inh”不是定义的参数。我希望能够使用初始化“A(object)”或“B(object)”的参数“inh”构造我的“sub()”。

这样:

my_object = sub(inh = A)

会给我:

Class A was inherited

还有:

my_object = sub(inh = B)

会给我

Class B was inherited

我的问题是,如何将“inh”传递给构造函数“sub()”,以便它可以选择正确的对象来继承?

【问题讨论】:

  • 你不能。继承是在创建类型时完成的,而不是在实例化它时完成的。但是,您可以动态创建一个新类。
  • 为什么要这样做?闻起来像 XY problem
  • 认为 metaclass__new__ 应该是可能的,但我真的没有看到任何情况下这是最好的选择。
  • 为什么需要继承?你能代替作曲吗?
  • 之所以要动态继承,是因为 A(object) 和 B(object) 有相同的功能(同名但返回结果不同的函数)。我没有为我的超类中的所有函数执行“if inh = A:...”,而是简单地覆盖了我的“sub()”调用的函数。对此更优雅的解决方案表示赞赏。

标签: python python-3.x class oop inheritance


【解决方案1】:

Immortal 的解决方案虽然基本正确,但有一个缺点:每次调用 Sub() 都会产生一个新类,因此像 isinstance() 或类标识测试之类的东西会中断。对此的解决方案是保留已创建类的映射:

_CLSMAP = {}

def Sub(base, *args, **kw):
    if base not in _CLSMAP:
        class Sub(base):
            def __init__(self, *args, **kw):
                super(sub, self).__init__(*args, **kw)
    _CLSMAP[base] = Sub
    return _CLSMAP[base](*args, **kw)

【讨论】:

    【解决方案2】:

    在我看来,您想要的是一个生成器/工厂函数,它将按照您的意愿构造并返回一个类实例。 为此,您可以使用python在函数中定义类和函数的能力,这样您对class sub的定义将在工厂函数的范围内完成,如下所示:

    def Sub(inh=object):
        class sub(inh):
           def __init__(self):
               super(sub, self).__init__()
        return sub()
    

    您现在可以将所需的子类传递给您的生成器函数并获得所需类型的实例化实例。

    运行输出:

    >>> def Sub(inh=object):
    ...     class sub(inh):
    ...        def __init__(self):
    ...            super(sub, self).__init__()
    ...     return sub()
    ...
    >>> class A(object):
    ...     def __init__(self):
    ...         print "Class A was inherited"
    ...
    >>>
    >>> class B(object):
    ...     def __init__(self):
    ...         print "Class B was inherited"
    ...
    >>>
    >>> Sub(A)
    Class A was inherited
    <__main__.sub object at 0x014E4970>
    >>> Sub(B)
    Class B was inherited
    <__main__.sub object at 0x014E49F0>
    >>>
    

    如你所愿。

    【讨论】:

    • 为什么是type(inh)?如果您将一个类作为参数传递,它将使用它的元类作为基类,这肯定不是 OP 所要求的。
    • 此外,这将在每次调用时创建一个新的 sub 类,这将在该类上进行 isinstance() 测试或身份测试。
    猜你喜欢
    • 2014-01-30
    • 2015-01-20
    • 1970-01-01
    • 1970-01-01
    • 2018-03-10
    • 2017-02-14
    • 1970-01-01
    相关资源
    最近更新 更多