如何从基于条件返回其他类的类中正确继承?

时间:2013-12-23 15:19:16

标签: python class inheritance metaclass

我将首先编写代码,而不是我想要实现的完整解释,因为这样更容易:

global child_selector

class Base(object): 
  def __init__(self):
    self.extended_name = self.name + '_Base'


class Child1(Base): 
  def __init__(self):
    super(Child1, self).__init__()

  def print_my_name(self):
    print 'I am ChildOne'

class Child2(Base):

  def __init__(self):
    super(Child2, self).__init__()

  def print_my_name(self):
    print 'I am ChildTwo'

class ChildAsBaseSelector(object):
  def __new__(cls):
    if child_selector == 1:
      return Child1()
    elif child_selector == 2:
      return Child2()
    else:
      print 'No child selected'

现在,如果我创建一个继承自Child1或Child2的类并将self.name作为实例变量,那么一切都按预期工作:

class Testing1(Child1):

  def __init__(self):
    self.name = 'Testing1'
    super(Testing1, self).__init__()

a = Testing1()
a.print_my_name() # 'I am ChlidOne'
print a.extended_name # 'Testing1_Base'

但是,如果我创建另一个将直接从ChildAsBaseSelector()继承的类,那么事情就变得可疑:

class Testing2(ChildAsBaseSelector):

  def __init__(self):
    self.name = 'Testing2'
    super(Testing2, self).__init__()

child_selector = 1
a = Testing2() 
# Will raise AttributeError: 'Child1' object has no attribute 'name'

在阅读'__new __()'的python文档后,我认为问题是因为:'如果__new __()没有返回cls的实例,那么将不会调用新实例的__init __()方法。这并没有真正帮助,因为我不知道如何“修复它”。

我也知道我可以这样做:

if child_selector == 1:
  ChildAsBaseSelector = Child1
if child_selector == 2:
  ChildAsBaseSelector = Child2

而不是直接从ChildAsBaseSelector继承。但我发现这不是优雅的,并且将python灵活性推向极限。 我真正想做的是有一个类,它将根据条件返回另一个类,然后我可以使用它来继承。任何提示?我想metaclasses(我痛苦地试图理解的一个概念)现在会派上用场。

任何提示赞赏。谢谢!

1 个答案:

答案 0 :(得分:0)

为什么不让ChildAsBaseSelector继承Base?在您的示例中,super(Testing2, self).__init__()将解析为object.__init__()(因此它不会按预期执行),但是 - 正如您所提到的 - 它无论如何都不会被调用,因为它不在{{1并非__mro__Child1

无论如何:让你的Child2取决于在调用Base.__init__()之前设置属性的子类是不好的设计 - 如果super().__init__()需要它,那么它应该作为参数传递或在Base本身具有可用的默认值。

此外,如果Base的唯一存在理由是根据全局/设置/其他内容创建ChildAsBaseSelectorChild1的实例,只需使用工厂函数即可。没有“新”关键字真的是一种祝福。