Frage

Ich habe versucht zu verstehen, python-metaclasses, und so wurden durch einige Beispiel-code.Soweit ich es verstehe, ein Python-Metaklasse kann eine beliebige aufrufbare.Also, ich meine metaclass wie

def metacls(clsName, bases, atts):
    ....
    return type(clsName, bases, atts)

Aber ich habe gesehen, eine Menge Menschen schreiben Ihre Metaklassen in der folgenden Weise:

class Metacls(type):
    def __new__(meta, clsName, bases, atts):
        ....
        return type.__new__(meta, clsName, bases, atts)

Soweit ich sehen kann, sind diese würden beide das gleiche tun.Gibt es einen Grund, die Verwendung der Basisklasse statt?Ist es üblich?

War es hilfreich?

Lösung

Es gibt feine Unterschiede, die meist im Zusammenhang mit Vererbung.Bei Verwendung eines Funktion als Metaklasse, die resultierende Klasse ist wirklich ein Fall von type, und kann vererbt werden, ohne Einschränkung;jedoch, die Metaklasse Funktion wird nie aufgerufen, solche Unterklassen.Bei Verwendung einer Unterklasse von type als Metaklasse, die resultierende Klasse ist eine Instanz der Metaklasse, wie einer Ihrer Unterklassen;jedoch mehrfache Vererbung beschränkt.

Zur Veranschaulichung der Unterschiede:

>>> def m1(name, bases, atts):
>>>     print "m1 called for " + name
>>>     return type(name, bases, atts)
>>>

>>> def m2(name, bases, atts):
>>>     print "m2 called for " + name
>>>     return type(name, bases, atts)
>>>

>>> class c1(object):
>>>     __metaclass__ = m1
m1 called for c1

>>> type(c1)
<type 'type'>

>>> class sub1(c1):
>>>     pass

>>> type(sub1)
<type 'type'>

>>> class c2(object):
>>>     __metaclass__ = m2
m2 called for c2

>>> class sub2(c1, c2):
>>>     pass

>>> type(sub2)
<type 'type'>

Beachten Sie, dass bei der Definition von sub1 und sub2 keine Metaklasse Funktionen aufgerufen wurden.Sie erstellt werden, genau so, wie wenn c1 und c2 hatte keine Metaklassen, sondern manipuliert wurde nach der Erstellung.

>>> class M1(type):
>>>     def __new__(meta, name, bases, atts):
>>>         print "M1 called for " + name
>>>         return super(M1, meta).__new__(meta, name, bases, atts)

>>> class C1(object):
>>>     __metaclass__ = M1
M1 called for C1

>>> type(C1)
<class '__main__.M1'>

>>> class Sub1(C1):
>>>     pass
M1 called for Sub1

>>> type(Sub1)
<class '__main__.M1'>

Beachten Sie die Unterschiede bereits:M1 genannt wurde beim erstellen Sub1, und beide Klassen sind Instanzen von M1.Ich bin mit super() für die eigentliche Gestaltung hier aus Gründen, die später klar werden.

>>> class M2(type):
>>>     def __new__(meta, name, bases, atts):
>>>         print "M2 called for " + name
>>>         return super(M2, meta).__new__(meta, name, bases, atts)

>>> class C2(object):
>>>     __metaclass__ = M2
M2 called for C2

>>> type(C2)
<class '__main__.M2'>

>>> class Sub2(C1, C2):
>>>     pass
M1 called for Sub2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 23, in __new__
TypeError: Error when calling the metaclass bases
    metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

Dies ist die große Einschränkung auf mehrfache Vererbung mit Metaklassen.Python weiß nicht, ob M1 und M2 sind kompatibel Metaklassen, also es zwingt Sie, um eine neue zu erstellen, um zu garantieren, dass es stimmt, was Sie brauchen.

>>> class M3(M1, M2):
>>>     def __new__(meta, name, bases, atts):
>>>         print "M3 called for " + name
>>>         return super(M3, meta).__new__(meta, name, bases, atts)

>>> class C3(C1, C2):
>>>     __metaclass__ = M3
M3 called for C3
M1 called for C3
M2 called for C3

>>> type(C3)
<class '__main__.M3'>

Dies ist der Grund, warum ich verwendet super() in der Metaklasse __new__ Funktionen:also jeder können, rufen Sie den nächsten in der Instandhaltung.

Bestimmte Fälle müssen möglicherweise Ihren Klassen zu sein, der Typ type, oder vielleicht möchten um zu vermeiden, die Vererbung Probleme, in dem Fall eine Metaklasse ist die Funktion wahrscheinlich der Weg zu gehen.In anderen Fällen ist der Typ der Klasse sein könnte wirklich wichtig, oder möchten Sie vielleicht arbeiten auf allen Unterklassen, in dem Fall Erben type wäre eine bessere Idee.Fühlen Sie sich frei zu verwenden, der Stil, die am besten in in einer bestimmten situation.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top