如何在没有元类的情况下将不同的参数传递给 __new__ vs __init__

How to pass different arguments to __new__ vs __init__ without a metaclass

我有一个简单的基础 class 实例化为两个 child classes:

之一
class Base:
    def __new__(cls, select):
        return super().__new__(Child1 if select == 1 else Child2)

    def __init__(self, select):
        self.select = select

    def __repr__(self):
        return f'{type(self).__name__}({self.select})'

class Child1(Base):
    def __init__(self):
        super().__init__('One')

class Child2(Base):
    def __init__(self):
        super().__init__('Two')

这目前引发了一个错误,因为 child __init__ 方法没有参数,而 parent __new__ 有:

>>> Base(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() takes 1 positional argument but 2 were given

我可以通过在新元 class 中覆盖 type.__call__ 来解决这个问题,但我想保留 type 作为我的元 class。

我还可以将 select*args 作为参数添加到 child __init__ 方法中。是否有更优雅的方法来实现允许 child __init__ 到 运行 与 parent __new__ 接受的不同参数?

恐怕这是不可能的,至少比元类多 'elegant' 方式。在较旧的 python 中,可以将参数传递给 super().__new__,但实际上从未使用过,因此该行为 was deprecated 并在以后完全删除。

The message means just what it says. :-) There's no point in calling object.new() with more than a class parameter, and any code that did so was just dumping those args into a black hole.

The only time when it makes sense for object.new() to ignore extra arguments is when it's not being overridden, but init is being overridden -- then you have a completely default new and the checking of constructor arguments is relegated to init.

The purpose of all this is to catch the error in a call like object(42) which (again) passes an argument that is not used. This is often a symptom of a bug in your program.