2012-03-09 7 views
6

Trovo che molte classi che scrivo in Python contengano un piccolo insieme di variabili che in realtà mi piacerebbe vedere quando chiamo str() e che riscrivere __str__(self) per ciascuna è piuttosto ingombrante. Così, ho cucinato il seguente mixin,Python Mixin per __str__and Risoluzione dei metodi Ordine

class StrMixin(object): 
    ''' 
    Automatically generate __str__ and __repr__ 
    ''' 
    def __str__(self): 
    import types 
    name = self.__class__.__name__ + ': ' 
    attrs = [ '{}={}'.format(k,v) for (k,v) in self.__dict__.items() ] 
    return name + ', '.join(attrs) 

    def __repr__(self): 
    return str(self) 

Tuttavia, se scrivo una classe,

class C(object, StrMixin): 
    pass 

ottengo il seguente errore di un'istanza,

TypeError: Error when calling the metaclass bases 
    Cannot create a consistent method resolution 
order (MRO) for bases object, StrMixin 

scontato, tra cui object qui è ridondante, ma cosa sta succedendo davvero qui?

+1

Se si desidera solo per ovviare a questo, considerare la possibilità di un decoratore, invece di un mixin. –

risposta

1

Hai risposto tu stesso alla domanda: il secondo object è ridondante. La classe C ha due basi: oggetto e StrMixin. Tuttavia, la base di StrMixin è anche oggetto, quindi è confusa su quale oggetto dovrebbe risolvere prima. Il MRO lo calcola come (C, STRMixin, oggetto, oggetto), che ha oggetti duplicati. In questo caso particolare, sembra ovvio quale dovrebbe essere la soluzione, ma aggiungere alcune altre classi e l'MRO potrebbe diventare molto meno chiaro. Per esempio.

class A(object): 
    pass 
class B(object, A): 
    pass 
class C(object, A): 
    pass 
class D(object, B, C): 
    pass 
class E(object, A, D): 
    pass 

Qual è la MRO per E? Qualunque cosa sia, è davvero complicata, ha duplicati e probabilmente alcuni loop.

MRO è spiegato abbastanza bene here, e il vostro caso specifico viene affrontato circa due terzi in basso nella pagina, il primo esempio in "Bad Ordini metodo di risoluzione".

+0

Puoi chiarire "oggetto viene StrMixin viene dopo l'oggetto"? – duckworthd

+1

In realtà, i duplicati non sono un problema, poiché l'algoritmo MRO di Python rimuoverà quelli. IIRC, l'algoritmo MRO non è affatto cambiato in Python 3 e il codice di esempio dell'OP produce lo stesso errore in 3.2. –

+0

È un argomento piuttosto confuso, ma spero che ora sia più chiaro. – aquavitae

11

quando si definisce:

class StrMixin(object): 
    ... 

Il compilatore sa che StrMixin viene prima object nel MRO della classe.

Quando si esegue:

class C(object, StrMixin): 
    pass 

Hai detto al compilatore che object viene prima StrMixin nel MRO. Ma anche object deve venire dopo StrMixin quindi dovrebbe apparire due volte nell'MRO e ciò non è consentito.

Se dici:

class C(StrMixin, object): 
    pass 

poi la MRO è semplicemente C, StrMixin, object che soddisfa l'ordine imposto da entrambe le classi. Non c'è alcuna duplicazione perché sebbene object sia referenziato due volte non c'è conflitto tra le definizioni.

+1

+1. La tua risposta è molto più chiara della mia, quindi non mi sono neanche preoccupato di correggere i miei errori. –

0

L'ereditarietà multipla può essere curativa. Per mantenere l'ereditarietà semplice mentre si usano i mixin, è possibile definire la funzione al di fuori della classe e assegnarla alla classe quando la si definisce.

class StrMixin:  # class here used only as a namespace 

    @staticmethod # not needed with Python 3 
    def __str__(self): 
     name = self.__class__.__name__ + ': ' 
     attrs = [ '{}={}'.format(k,v) for (k,v) in self.__dict__.items() ] 
     return name + ', '.join(attrs) 
    __repr__ = __str__ 

class C(object): 
    __str__, __repr__ = StrMixin.__str__, StrMixin.__repr__ 

O se si memorizzano le funzioni mixin in un modulo, quindi è possibile utilizzarlo nella classe in questo modo:

class C(object): 
    from StrMixin import __str__, __repr__ 
Problemi correlati