如何从 __new__ 参数返回子类

ctj*_*tj2 4 python python-2.7

我有一个父类和两个子类 child1(parent) 和 child2(parent) 有点像下面的代码。(编辑以更正确地显示父类正在做某事)

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
Run Code Online (Sandbox Code Playgroud)

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

aba*_*ert 5

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

有更好的设计方法,但如果您只想修复您的设计,有以下三种选择:


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


摆脱继承。是否有任何真正的原因child1是,一个parent在这里?

您似乎正在寻找在 Smalltalk/ObjC 术语中称为“类集群”的东西,并且您不需要集群的“可见面”作为 Python 中的基类,就像在这些语言中所做的那样。

例如:

class base(object):
    pass

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

class child1(base):
    # etc.
Run Code Online (Sandbox Code Playgroud)

在 Python 中,你甚至可以制作parent一个 ABC,register每个都childN用它,这样你就可以使用isinstance它并与它成为朋友。


最后,您可以仅通过处理__new__onparent而不是其子类来捕获递归:

def __new__(cls, e):
    if cls is not parent:
        return super(parent, cls).__new__(cls)
Run Code Online (Sandbox Code Playgroud)