2012-09-29 10 views
8

Possible Duplicate:
Subclassing Python tuple with multiple __init__ arguments¿Cómo inicializar una instancia de una subclase de tupla en Python?

quiero definir una clase que hereda de tuple, y quiero ser capaz de crear una instancia utilizando una sintaxis no es compatible con tuple. Para un ejemplo simple, supongamos que quiero definir una clase MyTuple que hereda de tuple, y que puedo instanciar pasando dos valores, x y y, para crear la (mi) tupla (x, y). He intentado el siguiente código:

class MyTuple(tuple): 
    def __init__(self, x, y): 
     print("debug message") 
     super().__init__((x, y)) 

Pero cuando lo probé, por ejemplo, MyTuple(2, 3) me dio un error: TypeError: tuple() takes at most 1 argument (2 given). Parece que mi función __init__ ni siquiera se llamó (en función del error que obtuve y del hecho de que mi "mensaje de depuración" no se imprimió).

Entonces, ¿cuál es la forma correcta de hacerlo?

Estoy usando Python 3.2.

+3

Es posible que desee echar un vistazo a ['' collections.namedtuple() ''] (http://docs.python.org/dev/library/collections.html#collections.namedtuple). –

+2

Verifique [esta pregunta original de SO] (http://stackoverflow.com/questions/1565374/subclassing-python-tuple-with-multiple-init-arguments) para obtener una respuesta completa sobre (1) por qué necesita usar ' __new__' en lugar de '__init__' (2) qué otros pasos debes seguir. –

Respuesta

12
class MyTuple(tuple): 
    def __new__(cls, x, y): 
     return tuple.__new__(cls, (x, y)) 

x = MyTuple(2,3) 
print(x) 
# (2, 3) 

Una de las dificultades de usar super es que usted no controla el cual va a ser llamado método siguiente del mismo nombre de las clases. Por lo tanto, todos los métodos de las clases tienen que compartir la misma firma de llamada, al menos el mismo número de elementos. Dado que está cambiando el número de argumentos enviados a __new__, no puede usar super.


O como sugiere Lattyware, se podría definir un namedtuple,

import collections 
MyTuple = collections.namedtuple('MyTuple', 'x y') 

p = MyTuple(2,3) 
print(p) 
# MyTuple(x=2, y=3) 
print(p.x) 
# 2 
+5

Podría usar '* tuple' (o' * args') en lugar de 'x, y', luego se generalizaría a un tamaño arbitrario. –

1

otro enfoque sería para encapsular una tupla en lugar de heredar de ella:

>>> class MyTuple(object): 
    count = lambda self, *args: self._tuple.count(*args) 
    index = lambda self, *args: self._tuple.index(*args) 
    __repr__ = lambda self: self._tuple.__repr__() 
    # wrap other methods you need, or define them yourself, 
    # or simply forward all unknown method lookups to _tuple 
    def __init__(self, x, y): 
     self._tuple = x,y 


>>> x = MyTuple(2,3) 
>>> x 
(2, 3) 
>>> x.index(3) 
1 

Cómo práctico, esto es , depende de la cantidad de capacidades y modificaciones que necesite, y si necesita tener isinstance(MyTuple(2, 3), tuple).

+0

Interesante. Me llevó algo de tiempo entender qué aspecto tienen las asignaciones de campo y las lambdas. ¿Alguna razón en particular por la que no usaste la construcción 'def' normal? Además, ¿cómo "reenvía todas las búsquedas de métodos desconocidos a' _tuple' "? – Tom

+0

no hay una razón en particular para las lambdas, solo me gusta "enlazar" funciones como esa. 'count = lambda: ...' me dice "la cuenta ES ASIGNADA PARA SER el conteo de _tuple". – ch3ka

+2

Puede reenviar búsquedas de métodos desconocidos con 'def __getattr __ (self, attr): \t \t return self._tuple .__ getattribute __ (attr)' – ch3ka

Cuestiones relacionadas