无法创建namedtuple子类的实例:TypeError:__ new __()需要4个参数(给定3个)

时间:2018-01-30 19:44:03

标签: python python-2.7 namedtuple

我似乎无法实例化namedtuple子类:

from collections import namedtuple

foo = namedtuple("foo",["a","b","c"])
class Foo(foo):
    def __init__(self, a, b):
        super(Foo, self).__init__(a=a,b=b,c=a+b)

当我尝试创建一个实例时,我得到:

>>> Foo(1,2)
TypeError: __new__() takes exactly 4 arguments (3 given)

我期待Foo(1,2,3)

似乎有一种解决方法:使用类方法而不是__init__

class Foo(foo):
    @classmethod
    def get(cls, a, b):
        return cls(a=a, b=b, c=a+b)

现在Foo.get(1,2)确实会返回foo(a=1, b=2, c=3)

然而,这看起来很难看。

这是唯一的方法吗?

1 个答案:

答案 0 :(得分:7)

命名元组是不可变的,您需要使用__new__ method代替:

class Foo(foo):
    def __new__(cls, a, b):
        return super(Foo, cls).__new__(cls, a=a, b=b, c=a+b)

(注意:__new__隐式地成为静态方法,因此您需要显式传递cls参数;该方法返回新创建的实例。)

无法使用

__init__,因为在实例创建后调用它,因此无法再改变元组。

请注意,您应该在子类中添加__slots__ = ()行;一个命名的元组没有__dict__字典使你的记忆混乱,但你的子类,除非你添加__slots__行:

class Foo(foo):
    __slots__ = ()
    def __new__(cls, a, b):
        return super(Foo, cls).__new__(cls, a=a, b=b, c=a+b)

这样你就可以保持命名元组的内存占用率低。请参阅__slots__文档:

  

__slots__ 声明的操作仅限于定义它的类。因此,子类将具有 __dict__ ,除非它们还定义 __slots__ (其中只能包含任何附加的名称 slot)。