Home > Net >  How to pass different arguments to __new__ vs __init__ without a metaclass
How to pass different arguments to __new__ vs __init__ without a metaclass

Time:12-26

I have a simple base class that instantiates to one of two 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')

This currently raises an error because the child __init__ method takes no argument while the parent __new__ does:

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

I can solve this by overriding type.__call__ in a new metaclass, but I want to keep type as my metaclass.

I can also add select or *args as a parameter to the child __init__ methods. Is there a more elegant way of accomplishing the same of allowing a child __init__ to run with different parameters than the parent __new__ accepts?

CodePudding user response:

I am afraid it's not possible, at least with more 'elegant' way than metaclasses. In older python there were possibility to pass arguments to super().__new__ but they were never used actually, so that behaviour was deprecated and removed at all later.

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.

  • Related