Suche…


Einführung

Metaclasses können Sie das Verhalten von Python - Klassen zu tief ändern (in Bezug darauf, wie sie definiert sind, instanziiert, zugegriffen wird , und mehr) von dem Ersatz - type Metaklasse , die neuen Klassen standardmäßig verwenden.

Bemerkungen

Berücksichtigen Sie beim Entwerfen Ihrer Architektur, dass viele Dinge, die mit Metaklassen erreicht werden können, auch mit einfacheren Semantiken erreicht werden können:

  • Traditionelles Erbe ist oft mehr als genug.
  • Klassendekorateure können Funktionalität auf Ad-hoc-Weise in Klassen einmischen.
  • Python 3.6 führt __init_subclass__() , mit der eine Klasse an der Erstellung ihrer Unterklasse teilnehmen kann.

Grundlegende Metaklassen

Wenn type mit drei Argumenten aufgerufen wird, verhält es sich wie die (Meta-) Klasse und erstellt eine neue Instanz, d. H. es erzeugt eine neue Klasse / einen neuen Typ.

Dummy = type('OtherDummy', (), dict(x=1))
Dummy.__class__              # <type 'type'> 
Dummy().__class__.__class__  # <type 'type'> 

Es ist möglich, eine Unterklasse type eine benutzerdefinierte metaclass zu erstellen.

class mytype(type):
    def __init__(cls, name, bases, dict):
        # call the base initializer
        type.__init__(cls, name, bases, dict)

        # perform custom initialization...
        cls.__custom_attribute__ = 2

Jetzt haben wir eine neue benutzerdefinierte mytype Metaklasse, mit der Klassen auf dieselbe Weise wie type .

MyDummy = mytype('MyDummy', (), dict(x=2))
MyDummy.__class__              # <class '__main__.mytype'>
MyDummy().__class__.__class__  # <class '__main__.mytype'>
MyDummy.__custom_attribute__   # 2

Wenn wir mit dem Schlüsselwort class eine neue Klasse erstellen, wird die Metaklasse standardmäßig auf Basis der Basisklassen ausgewählt.

>>> class Foo(object):
...     pass

>>> type(Foo)
type

Im obigen Beispiel ist die einzige Basenklasse object also ist unsere Metaklasse der object , also type . Es ist möglich, den Standard zu überschreiben, es hängt jedoch davon ab, ob wir Python 2 oder Python 3 verwenden:

Python 2.x 2.7

Ein spezielles Klassenebenenattribut __metaclass__ kann verwendet werden, um die Metaklasse anzugeben.

class MyDummy(object):
    __metaclass__ = mytype
type(MyDummy)  # <class '__main__.mytype'>
Python 3.x 3.0

Ein spezielles Schlüsselwort für eine metaclass die Metaklasse an.

class MyDummy(metaclass=mytype):
    pass
type(MyDummy)  # <class '__main__.mytype'>

Alle Schlüsselwortargumente (außer metaclass ) in der Klassendeklaration werden an die Metaklasse übergeben. Daher gibt die class MyDummy(metaclass=mytype, x=2) x=2 als Schlüsselwortargument an den mytype Konstruktor weiter.

Lesen Sie diese ausführliche Beschreibung der Python-Metaklassen für weitere Details.

Singletons mit Metaklassen

Ein Singleton ist ein Muster, das die Instantiierung einer Klasse auf eine Instanz / ein Objekt beschränkt. Weitere Informationen zu Python-Singleton-Entwurfsmustern finden Sie hier .

class SingletonType(type):
    def __call__(cls, *args, **kwargs):
        try:
            return cls.__instance
        except AttributeError:
            cls.__instance = super(SingletonType, cls).__call__(*args, **kwargs)
            return cls.__instance
Python 2.x 2.7
class MySingleton(object):
    __metaclass__ = SingletonType
Python 3.x 3.0
class MySingleton(metaclass=SingletonType):
    pass
MySingleton() is MySingleton()  # True, only one instantiation occurs

Verwenden einer Metaklasse

Metaklassensyntax

Python 2.x 2.7
class MyClass(object):
    __metaclass__ = SomeMetaclass
Python 3.x 3.0
class MyClass(metaclass=SomeMetaclass):
    pass

Python 2 und 3 Kompatibilität mit six

import six

class MyClass(six.with_metaclass(SomeMetaclass)):
    pass

Benutzerdefinierte Funktionalität mit Metaklassen

Die Funktionalität in Metaklassen kann so geändert werden, dass beim Erstellen einer Klasse eine Zeichenfolge in die Standardausgabe gedruckt wird oder eine Ausnahme ausgelöst wird. Diese Metaklasse gibt den Namen der zu erstellenden Klasse aus.

class VerboseMetaclass(type):

    def __new__(cls, class_name, class_parents, class_dict):
        print("Creating class ", class_name)
        new_class = super().__new__(cls, class_name, class_parents, class_dict)
        return new_class

Sie können die Metaklasse wie folgt verwenden:

class Spam(metaclass=VerboseMetaclass):
    def eggs(self):
        print("[insert example string here]")
s = Spam()
s.eggs()

Die Standardausgabe wird sein:

Creating class Spam
[insert example string here]

Einführung in Metaklassen

Was ist eine Metaklasse?

In Python ist alles ein Objekt: Ganzzahlen, Strings, Listen, sogar Funktionen und Klassen selbst sind Objekte. Und jedes Objekt ist eine Instanz einer Klasse.

Um die Klasse eines Objekts x zu überprüfen, kann type(x) aufgerufen werden.

>>> type(5)
<type 'int'>
>>> type(str)
<type 'type'>
>>> type([1, 2, 3])
<type 'list'>

>>> class C(object):
...     pass
...
>>> type(C)
<type 'type'>    

Die meisten Klassen in Python sind Instanzen des type . type selbst ist auch eine Klasse. Solche Klassen, deren Instanzen auch Klassen sind, werden Metaklassen genannt.

Die einfachste Metaclass

OK, also gibt es in Python bereits eine Metaklasse: type . Können wir noch einen schaffen?

class SimplestMetaclass(type):
    pass

class MyClass(object):
    __metaclass__ = SimplestMetaclass

Das fügt keine Funktionalität hinzu, aber es ist eine neue Metaklasse. Sehen Sie, dass MyClass jetzt eine Instanz von SimplestMetaclass ist:

>>> type(MyClass)
<class '__main__.SimplestMetaclass'>

Eine Metaklasse, die etwas tut

Eine Metaklasse, die etwas tut, überschreibt normalerweise __new__ type , um einige Eigenschaften der zu erstellenden Klasse zu ändern, bevor das ursprüngliche __new__ , das die Klasse erstellt:

class AnotherMetaclass(type):
    def __new__(cls, name, parents, dct):
        # cls is this class
        # name is the name of the class to be created
        # parents is the list of the class's parent classes
        # dct is the list of class's attributes (methods, static variables)

        # here all of the attributes can be modified before creating the class, e.g.

        dct['x'] = 8  # now the class will have a static variable x = 8

        # return value is the new class. super will take care of that
        return super(AnotherMetaclass, cls).__new__(cls, name, parents, dct)

Die Standard-Metaklasse

Sie haben vielleicht gehört, dass alles in Python ein Objekt ist. Es stimmt, und alle Objekte haben eine Klasse:

>>> type(1)
int

Das Literal 1 ist eine Instanz von int . Lass uns eine Klasse deklarieren:

>>> class Foo(object):
...    pass
...

Jetzt können wir es instanziieren:

>>> bar = Foo()

Was ist die Klasse der bar ?

>>> type(bar)
Foo

Schön, bar ist ein Beispiel für Foo . Aber was ist die Klasse von Foo selbst?

>>> type(Foo)
type

Ok, Foo selbst ist eine Instanz des type . Wie wäre es mit dem type selbst?

>>> type(type)
type

Was ist also eine Metaklasse? Lassen Sie uns jetzt so tun, als wäre es nur ein schicker Name für die Klasse einer Klasse. Zum Mitnehmen:

  • Alles ist ein Objekt in Python, also hat alles eine Klasse
  • Die Klasse einer Klasse wird als Metaklasse bezeichnet
  • Die Standard-Metaklasse ist type und bei weitem die häufigste Metaklasse

Aber warum sollten Sie sich mit Metaklassen auskennen? Nun, Python selbst ist ziemlich "hackbar", und das Konzept der Metaklasse ist wichtig, wenn Sie fortgeschrittene Dinge wie Meta-Programmierung machen oder die Initialisierung Ihrer Klassen kontrollieren möchten.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow