如何从__new__参数返回子类

时间:2013-08-13 20:44:17

标签: python python-2.7

我有一个类父类和两个子类child1(父类)和child2(父类)类似于以下代码。 (编辑为更准确地表明父类正在做某事)

class parent(object):
  name = None

  def __init__(self,e):
    # process the common attributes
    name = e.attrib['name']

  def __new__(cls,e):
    if e.attrib['type'] == 'c1':
      return child1(e)
    elif e.attrib['type'] == 'c2':
      return child2(e)
    else:
      raise 

class child1(parent):
  extra1 = None
  def __init__(self,e):
    super(e)
    # set attributes from e that are specific to type c1

class child2(parent):
  extra2 = None
  def __init__(self,e):
    super(e)
    # set attributes from e that are specific to type c2

目标是能够根据参数的值获得“正确”的类。因此,如果我可以说obj = parent(element)obj将是child1child2,具体取决于element.attrib['type']的值。

2 个答案:

答案 0 :(得分:3)

问题是在parent.__new__内部,您正在调用child1(e),同时调用child1.__new__,它会在parent.__new__中找到实现并使用相同的{{e调用它1}},它调用child1(e),这......你得到无限递归。

有更好的方法来设计它,但如果您只想修改设计,有三种选择:


如果您在所有子类中定义__new__,则不会通过parent.__new__。您可以在intermediateparent之间插入childN课程,只需一步即可完成此操作,因此您只需要intermediate.__new__。或者使用他们都继承的mixin,或者......


摆脱继承。是否真的有任何理由child1parent吗?

你似乎在寻找Smalltalk / ObjC中被称为“类集群”的东西,并且你不需要集群的“可见面”作为Python中的基类比你做的更多那些语言。

例如:

class base(object):
    pass

class parent(base):
    def __new__(cls, e):
        # same as before

class child1(base):
    # etc.

在Python中,您甚至可以将parent设为ABC,并register使用childN,这样您就可以使用isinstance和朋友。


最后,您只需处理__new__上的parent而不是其子类来捕获递归:

def __new__(cls, e):
    if cls is not parent:
        return super(parent, cls).__new__(cls)

答案 1 :(得分:3)

如果你没有parent成为一个类,只是一个正常的函数,这会容易得多。

使用基类是一种语言模式,这是实现这一目标的唯一方法。它在Python中没有必要或没有帮助。