2012-03-09 19 views
6

Python'da yazdığım birçok sınıfın, aslında str()'u aradığımda görmek istediğim küçük bir değişken kümesi içerdiğini ve her biri için __str__(self)'u yeniden yazmanın oldukça hantal olduğunu buldum. Böylece ben, Ancak şu mixin,__str__and için Python Mixin Metodu Çözünürlük Sırası

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) 

kadar pişirilir Ben bir sınıf yazarsanız,

class C(object, StrMixin): 
    pass 

Ben object dahil

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

Verilen, örnekleme üzerinde aşağıdaki hatayı alıyorum burada gereksiz, ama gerçekten burada neler oluyor?

+1

sadece bu geçici bir çözüm istiyorsanız, bir dekoratör yerine yapmayı düşünün bir karışım. –

cevap

1

Soruyu kendiniz yanıtladı - ikinci object gereksizdir. C Sınıfı iki tabana sahiptir: nesne ve StrMixin. Bununla birlikte, StrMixin'in temeli de nesnedir, bu yüzden ilk önce hangi nesnenin çözülmesi gerektiği konusunda kafasını karıştırır. MRO, çift nesneleri olan (C, STRMixin, object, object) olarak hesaplar. Bu özel durumda çözümün ne olması gerektiği belli görünüyor, ancak birkaç tane daha sınıf ekliyor ve MRO daha az açıklığa kavuşabilir. Örneğin.

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 

E için MRO nedir? Her ne olursa olsun, gerçekten karmaşık, çiftleri ve muhtemelen birkaç döngüleri vardır.

MRO, oldukça iyi bir şekilde here açıklanır ve özel durumunuza, sayfanın yaklaşık üçte ikisi, "Hatalı Yöntem Çözüm Emirleri" altındaki ilk örnek verilir.

+0

"Nesne Strmixin nesneden sonra geliyor" diye açıklar mısınız? – duckworthd

+1

Aslında, Python'un MRO algoritması bunları kaldıracağından, kopyalar sorun değil. IIRC, MRO algoritması Python 3'te hiç değişmedi ve OP'nin örnek kodu 3.2'de aynı hatayı üretiyor. –

+0

Onun oldukça kafa karıştırıcı bir konu, ama umarım bu daha nettir. – aquavitae

11

tanımladığınızda:

class StrMixin(object): 
    ... 

derleyici StrMixin sınıfının MRO içinde object önce geldiğini bilir.

Bunu yaptığınızda: Sen object MRO içinde StrMixin önce gelir derleyici söylediler

class C(object, StrMixin): 
    pass 

. Ancak object da StrMixin'dan sonra gelmelidir, bu yüzden MRO'da iki kez görünmesi ve buna izin verilmemesi gerekir.

dersen:

class C(StrMixin, object): 
    pass 

sonra MRO basitçe her iki sınıflar dayattığı sipariş karşılayan C, StrMixin, object olduğunu. Çoğaltma yoktur, çünkü object iki kez başvurulan olmasına rağmen, tanımlar arasında çakışma yoktur.

+1

+1. Cevabınız benimkinden çok temizlendi, bu yüzden hatalarımı düzelttim bile. –

0

Çoklu kalıtım akıl-bükülme olabilir. Miksleri kullanırken basit kalmayı sürdürmek için, işlevi sınıfın dışında tanımlayabilir ve tanımladığınızda sınıfa atayabilirsiniz.

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__ 

Yoksa bir modül içinde mixin fonksiyonları depolamak, o zaman şöyle Sınıfındaki kullanabilirsiniz:

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