Subclase tupla con múltiples argumentos __init__

El siguiente código funciona:

class Foo(tuple): def __init__(self, b): super(Foo, self).__init__(tuple(b)) if __name__ == '__main__': print Foo([3, 4]) $ python play.py 

Resultado:

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

Pero no lo siguiente:

 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 

Resultado:

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

¿Por qué?

    Debido a que las tuplas son inmutables, debe reemplazar __new__ en __new__ lugar:

    documentos de python

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

    Llamado para crear una nueva instancia de clase cls . __new__() es un método estático (con __new__() especial, por lo que no necesita declararlo como tal) que toma la clase de la cual se solicitó una instancia como primer argumento. Los argumentos restantes son los que se pasan a la expresión del constructor de objetos (la llamada a la clase). El valor de retorno de __new__() debe ser la nueva instancia de objeto (generalmente una instancia de cls ).

    Las implementaciones típicas crean una nueva instancia de la clase invocando el método __new__() la superclase usando super(currentclass, cls).__new__(cls[, ...]) con los argumentos apropiados y luego modificando la instancia recién creada según sea necesario antes de regresar eso.

    Si __new__() devuelve una instancia de cls , entonces el método __init__() la nueva instancia se invocará como __init__(self[, ...]) , donde self es la nueva instancia y los argumentos restantes son los mismos que se pasaron a __new__() .

    Si __new__() no devuelve una instancia de cls , no se invocará el método __init__() la nueva instancia.

    __new__() está destinado principalmente a permitir que las subclases de tipos inmutables (como int , str o tuple ) personalicen la creación de instancias. También se reemplaza comúnmente en metaclases personalizadas para personalizar la creación de clases.

    Para asignar el valor de la tupla, debe reemplazar el método __new__ :

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

    Los argumentos parecen ser ignorados por la implementación __init__ de la clase de tupla, pero si necesitas hacer algunas cosas de inicio, puedes hacerlo de la siguiente manera:

     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