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.