I think I have not undertood how to define a class subclassed from a namedtuple :
from collections import namedtuple
PD = namedtuple('PD', 'x y z')
p1 = PD(0, 'u', 1)
print p1.x #<== this works
class PDsub(PD):
__slots__ = ()
def __new__(cls, x, y, z):
self = super(PDsub, cls).__new__(cls, x, y, z)
return self
def __init__(self, a):
self.x, self.y, self.z = a, a, a
def __str__(self):
return 'Foo'
p2 = PDsub(5) #<== this does not work
This code raises TypeError : __new__() takes exactly 4 arguments (2 given)
.
Any ideas why?
Both the instance constructor (__new__
) and your instance initializer (__init__
) need to accept the same number of arguments.
Your __new__
needs 4 arguments, but your __init__
method only accepts 2. Adjust one or the other to accept the same number, or use a *args
catch-all argument in your __init__
method.
For example, using the following __new__
method would make things work:
def __new__(cls, a):
self = super(PDsub, cls).__new__(cls, a, a, a)
return self
in which case you no longer need your __init__
initializer at all.
Demo:
>>> from collections import namedtuple
>>> PD = namedtuple('PD', 'x y z')
>>> class PDsub(PD):
... __slots__ = ()
... def __new__(cls, a):
... self = super(PDsub, cls).__new__(cls, a, a, a)
... return self
... def __str__(self):
... return 'Foo'
...
>>> p2 = PDsub(5)
>>> p2.x, p2.y, p2.z
(5, 5, 5)
>>> str(p2)
'Foo'
An immutable type like a tuple often uses a __new__
constructor instead of a __init__
initializer; all the built-in immutables (frozenset
, str
, tuple
) do so.
def __new__(cls, x, y, z):
p2 = PDsub(5)
Whenever you create an object for your class, __new__
method (constructor) is called to create it.. So, here your __new__
method requires 4 parameters, but you have only passed 2 (*Note: - parameter cls
is implicit)
So, either you change your __new__
to take 2 parameters, or you can change your __init__
to take 4 parameters, and accordingly create your instance
by passing 3 parameters (1st one is implicit..)