使用多个__init__参数对元组进行子类化

Rei*_*ica 49 python inheritance tuples subclass

以下代码有效:

class Foo(tuple):

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

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

$ python play.py 
Run Code Online (Sandbox Code Playgroud)

结果:

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

但不是以下内容:

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 
Run Code Online (Sandbox Code Playgroud)

结果:

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)
Run Code Online (Sandbox Code Playgroud)

为什么?

Joh*_*ooy 67

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

python docs

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

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

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

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

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

__new__()主要是用来允许不可改变的类型(如类的子类 int,strtuple)来定制实例创建.它也通常在自定义元类中重写,以自定义类创建.


Jon*_*ati 49

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

class Foo(tuple):

    def __new__ (cls, a, b):
        return super(Foo, cls).__new__(cls, tuple(b))
Run Code Online (Sandbox Code Playgroud)

这些参数似乎被__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
Run Code Online (Sandbox Code Playgroud)