Frage

Ich war ein Metaklasse zu schreiben und habe es versehentlich, wie folgt aus:

class MetaCls(type):
    def __new__(cls, name, bases, dict):
        return type(name, bases, dict)

... statt wie folgt:

class MetaCls(type):
    def __new__(cls, name, bases, dict):
        return type.__new__(cls, name, bases, dict)

Was genau ist der Unterschied zwischen diesen beiden metaclasses? Und genauer gesagt, was die Ursache der erste, der nicht richtig funktionieren (einige Klassen nicht in der Metaklasse genannt wurden)?

War es hilfreich?

Lösung

Im ersten Beispiel sind Sie eine ganz neue Klasse zu erstellen:

>>> class MetaA(type):
...     def __new__(cls, name, bases, dct):
...         print 'MetaA.__new__'
...         return type(name, bases, dct)
...     def __init__(cls, name, bases, dct):
...         print 'MetaA.__init__'
... 
>>> class A(object):
...     __metaclass__ = MetaA
... 
MetaA.__new__
>>> 

, während im zweiten Fall die Sie anrufen Eltern __new__:

>>> class MetaA(type):
...     def __new__(cls, name, bases, dct):
...         print 'MetaA.__new__'
...         return type.__new__(cls, name, bases, dct)
...     def __init__(cls, name, bases, dct):
...         print 'MetaA.__init__'
... 
>>> class A(object):
...     __metaclass__ = MetaA
... 
MetaA.__new__
MetaA.__init__
>>> 

Andere Tipps

Das erste, was Sie brauchen, um herauszufinden, ist, wie object.__new__() funktioniert.

Hier ist es von der Dokumentation :

  

object.__new__(cls[, ...])

     

aufgerufen, um eine neue Instanz der Klasse cls zu erstellen. __new__() ist eine statische   Verfahren (spezielle Gefasste, so dass Sie es nicht als solche deklarieren muss), der nimmt   die Klasse, von denen eine Instanz als erstes Argument angefordert wurde.   Die übrigen Argumente sind diejenigen, auf das Objekt Konstruktor übergeben   Ausdruck (der Aufruf der Klasse). Der Rückgabewert von __new__()   sollte die neue Objektinstanz (in der Regel eine Instanz von cls).

     

Typische Implementierungen erstellen Sie eine neue Instanz der Klasse durch den Aufruf   die __new__() Methode super(currentclass, cls).__new__(cls[, ...]) der Superklasse mit entsprechenden Argumenten und dann Modifizieren   die neu erstellte Instanz als notwendig, bevor es zurück.

     

Wenn __new__() eine Instanz von cls zurückgibt, die __init__() Methode der neue Instanz wird wie __init__(self[, ...]) aufgerufen werden, wo self ist die neue Instanz und die übrigen Argumente sind die gleichen wie   wurden __new__() übergeben.

     

Wenn __new__() keine Instanz cls zurückkehrt, dann ist die __init__() Methode der neuen Instanz wird nicht aufgerufen werden.

     

__new__() soll hauptsächlich Subklassen von erlauben unveränderlich Typen (wie int, str oder tuple) Instanzerstellung anpassen. Es ist auch   häufig in benutzerdefinierter metaclasses um überschrieben Klasse anpassen   Schöpfung.

So in mg. Antwort , wird die ehemalige nicht Funktion __init__ nennen, während die letztere Anrufe funktionieren __init__ nach Aufruf __new__.

return type(name, bases, dict)

Was Sie wieder aus ist dies eine neue type, und keine MetaCls Instanz überhaupt. Folglich definiert Ihre Methoden in MetaCls (einschließlich __init__) kann nicht immer genannt werden.

type.__new__ wird im Rahmen genannt werden, dass neue Art zu schaffen, ja, aber der Wert von cls in diese Funktion gehen wird type und nicht MetaCls sein.

Wir verweisen auf die Anmerkung unten, hoffen, dass diese Informationen hilfreich.

class MetaCls(type):
    def __new__(cls, name, bases, dict):
        # return a new type named "name",this type has nothing
        # to do with MetaCls,and MetaCl.__init__ won't be invoked
        return type(name, bases, dict)

class MetaCls(type):
    def __new__(cls, name, bases, dict):
        # return a new type named "name",the returned type 
        # is an instance of cls,and cls here is "MetaCls", so 
        # the next step can invoke MetaCls.__init__ 
        return type.__new__(cls, name, bases, dict)
class MyMeta(type):
    def __new__(meta, cls, bases, attributes):
        print 'MyMeta.__new__'
        return type.__new__(meta, cls, bases, attributes)
    def __init__(clsobj, cls, bases, attributes):
        print 'MyMeta.__init__'

class MyClass(object):
  __metaclass__ = MyMeta
  foo = 'bar'

Eine andere Möglichkeit, um das gleiche Ergebnis zu erreichen:

cls = "MyClass"
bases = ()
attributes = {'foo': 'bar'}
MyClass = MyMeta(cls, bases, attributes)

MyMeta ist eine aufrufbare so Python wird die spezielle Methode __call__ verwenden.

Python wird für __call__ aussieht in dem Typ des MyMeta (die type in unserem Fall)

  

"Für neuen Stil Klassen, implizite Anrufungen spezieller Methoden sind   nur Arbeit garantiert richtig definiert, wenn sie auf den Typ eines Objekts, nicht   in der Instanz Wörterbuch des Objekts "

MyClass = MyMeta(...) wird interpretiert als:

my_meta_type = type(MyMeta)
MyClass = my_meta_type.__call__(MyMeta, cls, bases, attributes)

Im Inneren des type.__call__() ich so etwas wie dies vorstellen:

MyClass = MyMeta.__new__(MyMeta, cls, bases, attributes)
meta_class = MyClass.__metaclass__
meta_class.__init__(MyClass, cls, bases, attributes)
return MyClass

MyMeta.__new__() wird entscheiden, wie der MyClass gebaut wird:

type.__new__(meta, cls, bases, attributes) die korrekte metaclass gesetzt (die MyMeta ist) für MyClass

type(cls, bases, attributes) wird das Standard metaclass (welcher Typ ist) für MyClass

Es ist alles ziemlich gut beschrieben hier .

Wenn Sie die richtige Art von Objekt nicht zurück, es hat keinen Sinn zu definieren, eine benutzerdefinierte metaclass.

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