'__new__ method giving error object.__new__() takes exactly one argument (the type to instantiate)
why the following code is giving error?
class Foo:
def __new__(cls, *args, **kwargs):
print("Creating Instance")
instance = super(Foo, cls).__new__(cls,*args, **kwargs)
return instance
def __init__(self, a, b):
self.a = a
self.b = b
z= Foo(2,3)
it is giving the following error
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
Solution 1:[1]
object.__new__() signature is (*args, **kwargs), you may check this by using inspect.signature function.
But why then you have this error? TLDR: because you defined custom __new__ method.
Small research
All tests were done on Python 3.9.1.
Consider next class.
class MyClass:
def __init__(self): pass
Let's call object.__new__() on it:
>>> object.__new__(MyClass, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.MyClass object at 0x000001E7B15B3550>
No problems at all.
This class has only custom __init__ and no custom __new__.
Now try to do the same call for your Foo:
>>> object.__new__(Foo, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
An exception about object.__new__().
This class has both custom __init__ and __new__.
You will see the same error when only custom __new__ is defined:
>>> class OnlyNew:
... def __new__(cls, *args, **kwargs): return super().__new__(cls)
>>> object.__new__(OnlyNew, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
Let's check a class with no custom __init__ and __new__.
>>> class A: pass
>>> object.__new__(A, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: A() takes no arguments
Absolutely different error.
Let's check how it works with inheritance.
Derive from A and define __init__.
>>> class B(A):
... def __init__(self): pass
>>> object.__new__(B, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.B object at 0x000001E7B15D23A0>
Derive from MyClass and define nothing.
>>> class MC(MyClass): pass
>>> object.__new__(MC, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.MC object at 0x000001E7B15D2CA0>
Derive from MyClass and define __new__.
>>> class Sub(MyClass):
def __new__(cls, *args, **kwargs): return super().__new__(cls)
>>> object.__new__(Sub, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
Derive from Foo and define nothing.
>>> class F(Foo): pass
>>> object.__new__(F, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
And now let's look on an absolutely exotic case:
class Base:
def __init__(self): pass
def __new__(cls, *args, **kwargs): return super().__new__(cls)
class Sub(Base):
def __init__(self): pass
__new__ = object.__new__
class Free:
def __init__(self): pass
__new__ = object.__new__
>>> object.__new__(Free, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.Free object at 0x000001E7B15C5A90>
>>> object.__new__(Sub, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
Both Sub and Free do not have a custom __new__ method - in both classes __new__ is object.__new__().
But creating Sub raises an error while creating Free does not.
Seems like object.__new__() checks not getattr(A_Class, '__new__', object.__new__) is object.__new__ but all(getattr(cls, '__new__', object.__new__) is object.__new__ for cls in A_Class.mro()).
Conclusion
- If a class has custom
__new__in its MRO, callingobject.__new__()with >1 arguments raises TypeError. - If a class has only custom
__init__and does not have custom__new__in its MRO, callingobject.__new__()with >1 arguments creates a proper instance. - If a class does not have both custom
__init__and__new__in its MRO, callingobject.__new__()with >1 arguments raises TypeError.
Solution 2:[2]
This should work:
class Foo:
def __new__(cls, a, b):
print("Creating Instance")
instance = super(Foo, cls).__new__(cls)
return instance
def __init__(self, a, b):
self.a = a
self.b = b
foo_1 = Foo(a=1, b=2)
foo_2 = Foo(a=1, b=3)
if you want to use Singleton design pattern, and create instance of class with params in constructor, this should work:
class FooSingleton:
_instances = {}
def __new__(cls, a, b):
if cls not in cls._instances:
print('creating new FooSingleton instance')
cls._instances[cls] = super(FooSingleton, cls).__new__(cls)
else:
print('using FooSingleton instance')
return cls._instances[cls]
def __init__(self, a, b):
self.a = a
self.b = b
foo_s1 = FooSingleton(a=1, b=2)
foo_s2 = FooSingleton(a=1, b=3)
Solution 3:[3]
In addition to this and this answer, It's good to have this response from Guido van Rossum here.
This addresses the behavior of object.__new__ when overriding or not overriding __new__ in subclasses and what happens to the extra arguments which passed that method.
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.
from inspect import signature
print(signature(object.__new__))
print('------------------------------')
print(signature(object.__init__))
print('------------------------------')
object(42)
output:
(*args, **kwargs)
------------------------------
(self, /, *args, **kwargs)
------------------------------
Traceback (most recent call last):
File "<>", line 7, in <module>
object(42)
TypeError: object() takes no arguments
Solution 4:[4]
object.__new__(cls), param is cls, not (cls, *args, **kwargs)
Solution 5:[5]
You don't need to worry about passing the arguments up to the superclass. The arguments will also be passed into the __init__ call.
class User(object):
def __new__(cls, *args, **kwargs):
# do some logic with the initial parameters
return super().__new__(cls)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Peter Trcka |
| Solution 3 | |
| Solution 4 | wjandrea |
| Solution 5 | Tomisin Abiodun |
