正确覆盖 python3 中的 __new__

correctly override __new__ in python3

所以我试图覆盖 __new__ 并让它作为工厂存在以创建 派生实例。在阅读了一些关于 SO 的内容之后,我的印象是我也应该在派生实例上调用 __new__

BaseThing

class BaseThing:
    def __init(self, name, **kwargs):
        self.name = name

    # methods to be derived

事物工厂

class Thing(BaseThing):
    def __new__(cls, name, **kwargs):
        if name == 'A':
           return A.__new__(name, **kwargs)
        if name == 'B':
           return B.__new__(name, **kwargs)        

    def __init__(self, *args, **kwargs):
        super().__init__(name, **kwargs)

   # methods to be implemented by concrete class (same as those in base)

一个

class A(BaseThing):
    def __init__(self, name, **kwargs):
       super().__init__(name, **kwargs)

B

class B(BaseThing):
    def __init__(self, name, **kwargs):
       super().__init__(name, **kwargs)

我期待的是它会正常工作。

>>> a = Thing('A')

给我 TypeError: object.__new__(X): X is not a type object (str)

我对此有点困惑;当我只是 return 派生 类 的具体实例时,它就起作用了。即

def __new__(cls, name, **kwargs):
        if name == 'A':
           return A(name)
        if name == 'B':
           return B(name)

但是我不认为这是在 __new__ 中 returning 的正确方法;它可能会重复对 __init__.

的调用

当我在 object 中检查 __new__ 的签名时,似乎是这个:

@staticmethod # known case of __new__
def __new__(cls, *more): # known special case of object.__new__
    """ Create and return a new object.  See help(type) for accurate signature. """
    pass

没想到是这个;我希望它也带有 args 和 kwargs。我一定是在这里做错了什么。

在我看来,我需要直接在我的基础中继承对象,但谁能解释一下正确的做法?

你叫 __new__ 错了。如果你想让你的 __new__ 创建一个子类的实例,你不调用子类的 __new__;您像往常一样调用超类的 __new__,但是 将子类 作为第一个参数传递给它:

instance = super().__new__(A)

我不能保证这足以解决您的问题,因为您发布的代码不会重现您声称的错误;它还有其他问题会首先导致不同的错误(无限递归)。特别是,如果 AB 不是真正从 Thing 继承而来,则需要不同的处理方式。