Üblich Zu Erben Metaklassen Aus geben?
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?
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.