Domanda

Ho due domande converning metaclassi e l'ereditarietà multipla. La prima è:? Perché ricevo un TypeError per la Derived classe, ma non per Derived2

class Metaclass(type): pass

class Klass(object):
    __metaclass__  = Metaclass

#class Derived(object, Klass): pass # if I uncomment this, I get a TypeError

class OtherClass(object): pass

class Derived2(OtherClass, Klass): pass # I do not get a TypeError for this

Il messaggio di errore esatto è:

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

La seconda domanda è: Perché super non funziona in questo caso (se uso __init__ invece di __new__, super funziona di nuovo):

class Metaclass(type):
    def __new__(self, name, bases, dict_):
        return super(Metaclass, self).__new__(name, bases, dict_)

class Klass(object):
    __metaclass__  = Metaclass

Non ottengo:

TypeError: Error when calling the metaclass bases type.__new__(X): X is not a type object (str)

Sto usando Python 2.6.

È stato utile?

Soluzione

La seconda questione è già stato ben risposto due volte, anche se __new__ è in realtà uno staticmethod, non un classmethod come erroneamente affermato in un commento ...:

>>> class sic(object):
...   def __new__(cls, *x): return object.__new__(cls, *x)
... 
>>> type(sic.__dict__['__new__'])
<type 'staticmethod'>

La prima domanda (come qualcuno ha notato) non ha nulla a che fare con metaclassi: semplicemente non è possibile moltiplicare ereditare da qualsiasi due classi A e B in questo ordine dove B è una sottoclasse di A. per esempio:.

>>> class cis(sic): pass
... 
>>> class oops(sic, cis): pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution
order (MRO) for bases sic, cis

Il MRO garantisce che le basi più a sinistra sono visitati prima di quelli più a destra - ma garantisce anche che tra gli antenati se x è una sottoclasse di y allora x è visitato prima y. E 'impossibile soddisfare entrambe queste garanzie in questo caso. C'è una buona ragione per queste garanzie, naturalmente: senza di loro (ad esempio, nelle classi di vecchio stile, che garantiscono solo l'ordine da sinistra a destra nella risoluzione metodo, non il vincolo sottoclasse) tutte le modifiche in x sarebbe stato ignorato a favore delle definizioni di y, e che non può avere molto senso. Pensateci: che cosa fa significa ereditare da object prima, e da qualche altra seconda classe? (Definizione ;-) essenzialmente inesistente Quel object dei suoi diversi metodi speciali deve avere la precedenza su l'altra classe di, provocando le sostituzioni di altra classe per essere ignorato?

Altri suggerimenti

Per la prima domanda, uno sguardo alla la descrizione di MRO in python - in particolare, la sezione "cattivo Metodo ordine Risoluzione". In sostanza, è a che fare con il fatto che Python non sa se utilizzare metodi di un oggetto o di Klass. (Non è niente a che fare con l'utilizzo di metaclassi.)

Per la seconda domanda, sembra che stai incomprensione come funziona la funzione __new__. Non ci vuole un riferimento a se stesso come il primo argomento - ci vuole un riferimento al tipo di classe che viene istanziata. Quindi, il codice dovrebbe essere simile a questo:

class Metaclass(type):
    def __new__(cls, name, bases, dictn):
        return type.__new__(cls, name, bases, dictn)

Per la seconda domanda, è necessario passare a sé __new__ in questo modo:

class Metaclass(type):
    def __new__(self, name, bases, dict_):
        return super(Metaclass, self).__new__(self, name, bases, dict_)

class Klass(object):
    __metaclass__  = Metaclass

Non riesco a ricordare la parte superiore della mia testa perché questo è, ma credo che sia perché type.__new__ non è un metodo vincolato e quindi non magicamente ottenere l'argomento sé.

Perché si dovrebbe fare?

class Derived(object, Klass):

Klass deriva già da oggetto.

class Derived(Klass):

è la cosa ragionevole qui.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top