2012-09-29 24 views
8

Possible Duplicate:
Subclassing Python tuple with multiple __init__ argumentsCome inizializzare un'istanza di una sottoclasse di tupla in Python?

voglio definire una classe che eredita da tuple, e voglio essere in grado di istanziare utilizzando una sintassi non supportato da tuple. Per un semplice esempio, supponiamo di voler definire una classe MyTuple che eredita da tuple e che posso creare un'istanza passando due valori, x e , per creare la (mia) tupla (x, y). Ho provato il seguente codice:

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

ma quando ho provato, per esempio, MyTuple(2, 3) ho ottenuto un errore: TypeError: tuple() takes at most 1 argument (2 given). Sembra che la mia funzione __init__ non sia stata nemmeno chiamata (in base all'errore che ho ricevuto e sul fatto che il mio "messaggio di debug" non è stato stampato).

Quindi qual è il modo giusto per farlo?

Sto usando Python 3.2.

+3

Si potrebbe dare un'occhiata a ['' collections.namedtuple() ''] (http://docs.python.org/dev/library/collections.html#collections.namedtuple). –

+2

Si prega di controllare [questa domanda SO originale] (http://stackoverflow.com/questions/1565374/subclassing-python-tuple-with-multiple-init-arguments) per una risposta approfondita su (1) perché è necessario utilizzare ' __new__' invece di '__init__' (2) quali altri passi devi seguire. –

risposta

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

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

Una delle difficoltà di utilizzo super è che non si controlla quale metodo con lo stesso nome delle classi sta per essere chiamato dopo. Quindi tutti i metodi delle classi devono condividere la stessa firma di chiamata, almeno lo stesso numero di elementi. Poiché si modifica il numero di argomenti inviati a __new__, non è possibile utilizzare super.


O come suggerisce Lattyware, si potrebbe definire 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

Potresti usare '* tuple' (o' * args') piuttosto che 'x, y', quindi generalizzerebbe a dimensioni arbitrarie. –

1

un altro approccio sarebbe quello di incapsulare una tupla invece di ereditare da essa:

>>> 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 

Come pratico questo è dipende dal numero di funzionalità e modifiche necessarie e dal momento che è necessario avere isinstance(MyTuple(2, 3), tuple).

+0

Interessante. Mi ci è voluto un po 'di tempo per capire cosa assomiglia ai compiti sul campo e ai lambda. Qualche ragione particolare per cui non hai usato la normale costruzione 'def'? Inoltre, come si "inoltrano tutte le ricerche dei metodi sconosciuti a' _tuple' "? – Tom

+0

nessun motivo particolare per i lambda, mi piace solo "legare" funzioni del genere. 'count = lambda: ... 'mi dice" count IS ASSIGNED TO BE il conteggio di _tuple ". – ch3ka

+2

È possibile inoltrare ricerche metodo sconosciute con 'def __getattr __ (self, attr): \t \t return self._tuple .__ getattribute __ (attr)' – ch3ka

Problemi correlati