python - 如何从 __new__ 参数返回子类

标签 python python-2.7

我有一个父类和两个子类 child1(parent) 和 child2(parent),有点像下面的 near 代码。 (经过编辑以更恰本地表明父类正在做某事)

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'] 的值是。

最佳答案

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

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


如果您在所有子类中都定义了 __new__,它就不会落入 parent.__new__。您可以通过在 parentchildN 之间插入一个 intermediate 类一步完成此操作,因此您只需要 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.

在 Python 中,你甚至可以让 parent 成为一个 ABC,并用它register 每个 childN 这样你就可以使用 isinstance 和它的 friend 。


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

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

关于python - 如何从 __new__ 参数返回子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18218876/

相关文章:

python-2.7 - 如何通过 Selenium Python 点击​​某个元素

python - SocketServer Python

python - 使用 Tkinter 插入文本框

python - Spark 在本地运行但不在 YARN 中运行

python - 如何在Python中标记整数列表?

python - Selenium 点击错误

python - 如果识别出特定元素,则乘以 DataFrame 中的值

python - 将 Aiohttp 与代理一起使用

python - 提示输入,直到给出 2 个空行

python - 在 Sqlite 中对多索引大型数据库表进行排序