【问题标题】:How to dynamically inherit at initialization time?初始化时如何动态继承?
【发布时间】:2018-10-07 05:28:23
【问题描述】:

我有以下类结构:

class Base:
  def z(self):
    raise NotImplementedError()

class A(Base):
  def z(self):
    self._x()
    return self._z()

  def _x(self):
    # do stuff

  def _a(self):
    raise NotImplementedError()

class B(Base)
  def z(self):
    self._x()
    return self._z()

  def _x(self):
    # do stuff

  def _z(self):
    raise NotImplementedError()


class C(A):
  def _z(self):
    print(5)

class D(B):
  def _z(self):
    print(5)

C(A)D(B) 的实现完全一样,并不关心它继承自哪个类。概念上的区别仅在于AB(并且这些需要作为单独的类保存)。我不想为CD 编写单独的定义,而是希望能够根据在创建@ 实例 时提供的参数从AB 动态继承@ 987654331@/D(最终CD必须同名)。

似乎元类可能有效,但我不确定如何将 __init__ 参数传递给元类 __new__(以及这是否真的有效)。我真的更喜欢能解决课堂内部问题的解决方案。

【问题讨论】:

  • 这个问题看起来接近this other one,如果不是真正的重复...
  • 你为什么需要它?我觉得可能有更好的方法。
  • 简而言之,我有类(CD 以上)应该并行运行线程(A)或顺序运行(B)。总体结果行为与AB 相同,性能和准确性略有不同。所有ABCDBase 的行为都极其相似,需要给定的继承结构,所以组合并不是很合适。你还有什么建议?

标签: python python-3.x inheritance metaclass


【解决方案1】:

您是否考虑过使用组合而不是继承?似乎它更适合这个用例。详情见答案底部。

不管怎样,

  • class C(A): ......... class C(B): ..... 甚至无效,只会导致定义 class C(B)

  • 我不确定元类能否在这方面为您提供帮助。我相信最好的方法是使用type,但我很想得到纠正。

使用type 的解决方案(并且可能滥用locals(),但这不是重点)

class A:
    def __init__(self):
        print('Inherited from A')

class B:
    def __init__(self):
        print('Inherited from B')

class_to_inherit = input()  # 'A' or 'B"

C = type('C', (locals()[class_to_inherit],), {})

C()

'A' or 'B'
>> A
Inherited from A

'A' or 'B'
>> B
Inherited from B


作曲

回到我回答开头的问题,您声明自己“C(A)”和“C(B)”的实现是相同的,它们实际上并不关心A 或@987654330 @。对我来说使用组合似乎更正确。然后你可以按照以下方式做一些事情:

class A: pass

class B: pass

class C:
    def __init__(self, obj):  # obj is either A or B instance, or A or B themselves
        self.obj = obj  # or self.obj = obj() if obj is A or B themselves

c = C(A())  #  or c = C(A) 

如果C 应该公开与AB 相同的API,C 可以覆盖__getattr__

class A:
    def foo(self):
        print('foo')

class C:
    def __init__(self, obj):
        self.obj = obj

    def __getattr__(self, item):
        return getattr(self.obj, item)

C(A()).foo()
# foo

【讨论】:

  • 感谢您的回答。不幸的是,对于我的特定用例来说,组合不是一个好的解决方案,因为C 应该提供与 A 相同的 API。也许使用type 的解决方案结合了一个确定正确类的函数就可以了。我会再开放一段时间,看看是否有其他想法出现。
  • @niko " C 应该提供与A 相同的API" 这可以通过使用组合来实现,也可以通过覆盖C 中的__getattr__ 来实现,例如def __getattr__(self, item): return getattr(self.obj, item) 它有效,但这是一个好方法吗?不确定。查看更新的答案。
  • 当然,但是跟踪哪些成员属于A 以及哪些成员属于C 就会变得一团糟。当然这是可行的,但我觉得type 的解决方案更清晰。同样在我的例子中,A 和 C 在概念上应该是相同的,A 为 C 的抽象方法提供了一个实现
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-18
  • 2012-11-08
  • 2019-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多