56

以下代码有效:

class Foo(tuple):

    def __init__(self, b):
        super(Foo, self).__init__(tuple(b))

if __name__ == '__main__':
    print Foo([3, 4])

$ python play.py 

结果:

play.py:4: DeprecationWarning: object.__init__() takes no parameters
  super(Foo, self).__init__(tuple(b))
(3, 4)

但不是以下内容:

class Foo(tuple):

    def __init__(self, a, b):
        super(Foo, self).__init__(tuple(b))

if __name__ == '__main__':
    print Foo(None, [3, 4])

$ python play.py 

结果:

Traceback (most recent call last):
  File "play.py", line 7, in <module>
    print Foo(None, [3, 4])
TypeError: tuple() takes at most 1 argument (2 given)

为什么?

4

2 回答 2

72

因为元组是不可变的,所以你必须重写__new__

蟒蛇文档

object.__new__(cls[, ...])

调用以创建 class 的新实例cls__new__()是一个静态方法(特殊情况,因此您不需要这样声明),它将请求实例的类作为其第一个参数。其余参数是传递给对象构造函数表达式(对类的调用)的参数。的返回值__new__()应该是新的对象实例(通常是 的实例cls)。

典型的实现通过使用适当的参数调用超类的__new__()方法来 创建类的新实例super(currentclass, cls).__new__(cls[, ...]),然后在返回之前根据需要修改新创建的实例。

如果__new__()返回 的实例 cls,则将调用新实例的 __init__()方法__init__(self[, ...]),其中 self 是新实例,其余参数与传递给 的参数相同__new__()

如果__new__()不返回 的实例,则不会调用cls新实例的方法。__init__()

__new__()主要是为了允许不可变类型的子类(如 intstrtuple)自定义实例创建。它也通常在自定义元类中被覆盖,以自定义类创建。

于 2009-10-14T10:24:33.400 回答
56

要分配元组值,您需要覆盖该__new__方法:

class Foo(tuple):

    def __new__ (cls, a, b):
        return super(Foo, cls).__new__(cls, tuple(b))

元组类的实现似乎忽略了参数__init__,但是如果您需要做一些初始化的事情,您可以按如下方式进行:

class Foo(tuple):

    def __new__ (cls, a, b):
        return super(Foo, cls).__new__(cls, tuple(b))

    def __init__(self, a, b):
        self.a=a
        self.b=b

if __name__ == '__main__':
    foo = Foo(None, [3, 4])
    print foo
    print foo.a
    print foo.b
于 2012-10-26T21:38:33.613 回答