4

我想我还没有理解如何定义一个从 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

此代码引发TypeError : __new__() takes exactly 4 arguments (2 given).

任何想法为什么?

4

2 回答 2

6

实例构造函数 ( __new__) 和实例初始化器 ( __init__) 都需要接受相同数量的参数。

__new__需要 4 个参数,但您的__init__方法只接受 2 个。调整一个或另一个以接受相同的数字,或在您的方法中使用*args包罗万象的参数。__init__

例如,使用以下__new__方法可以使事情正常进行:

def __new__(cls, a):
    self = super(PDsub, cls).__new__(cls, a, a, a)
    return self

在这种情况下,您根本不再需要您的__init__初始化程序。

演示:

>>> 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'

像元组这样的不可变类型通常使用__new__构造函数而不是初始值设定项__init__;所有内置的不可变对象 ( frozenset, str, tuple) 都这样做。

于 2012-10-05T11:55:16.817 回答
2
def __new__(cls, x, y, z):

p2 = PDsub(5)

每当您为您的类创建一个对象时,__new__都会调用方法(构造函数)来创建它。所以,这里您的__new__方法需要 4 个参数,但您只传递了 2 个(*注意:- 参数cls是隐式的)

所以,要么你改变你__new__采取2 个参数,或者你可以改变你__init__采取4 个参数,并相应地your instance通过传递3 个参数来创建(第一个是隐式的..)

于 2012-10-05T11:58:00.307 回答