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

时间:2009-10-14 10:10:41

标签: python inheritance subclass tuples

以下代码有效:

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)

为什么?

2 个答案:

答案 0 :(得分:64)

因为元组是不可变的,所以你必须改为覆盖__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__()主要用于允许不可变类型的子类(如   intstrtuple)进行自定义   实例创建。它也是常见的   在自定义元类中重写   为了自定义类创建。

答案 1 :(得分:48)

要分配您需要覆盖__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