7371 Stimmen

Was sind Metaklassen in Python?

Was sind Metaklassen in Python und wofür werden sie verwendet?

22voto

Lars Punkte 1600

Beachten Sie, dass in Python 3.6 eine neue Dunder-Methode __init_subclass__(cls, **kwargs) wurde eingeführt, um viele gängige Anwendungsfälle für Metaklassen zu ersetzen. Is wird aufgerufen, wenn eine Unterklasse der definierenden Klasse erstellt wird. Siehe Python-Dokumente .

20voto

Carson Punkte 3411

Hier ist ein weiteres Beispiel dafür, wofür es verwendet werden kann:

  • Sie können die metaclass um die Funktion ihrer Instanz (der Klasse) zu ändern.

    class MetaMemberControl(type): slots = ()

    @classmethod
    def __prepare__(mcs, f_cls_name, f_cls_parents,  # f_cls means: future class
                    meta_args=None, meta_options=None):  # meta_args and meta_options is not necessarily needed, just so you know.
        f_cls_attr = dict()
        if not "do something or if you want to define your cool stuff of dict...":
            return dict(make_your_special_dict=None)
        else:
            return f_cls_attr
    
    def __new__(mcs, f_cls_name, f_cls_parents, f_cls_attr,
                meta_args=None, meta_options=None):
    
        original_getattr = f_cls_attr.get('__getattribute__')
        original_setattr = f_cls_attr.get('__setattr__')
    
        def init_getattr(self, item):
            if not item.startswith('_'):  # you can set break points at here
                alias_name = '_' + item
                if alias_name in f_cls_attr['__slots__']:
                    item = alias_name
            if original_getattr is not None:
                return original_getattr(self, item)
            else:
                return super(eval(f_cls_name), self).__getattribute__(item)
    
        def init_setattr(self, key, value):
            if not key.startswith('_') and ('_' + key) in f_cls_attr['__slots__']:
                raise AttributeError(f"you can't modify private members:_{key}")
            if original_setattr is not None:
                original_setattr(self, key, value)
            else:
                super(eval(f_cls_name), self).__setattr__(key, value)
    
        f_cls_attr['__getattribute__'] = init_getattr
        f_cls_attr['__setattr__'] = init_setattr
    
        cls = super().__new__(mcs, f_cls_name, f_cls_parents, f_cls_attr)
        return cls

    class Human(metaclass=MetaMemberControl): slots = ('_age', '_name')

    def __init__(self, name, age):
        self._name = name
        self._age = age
    
    def __getattribute__(self, item):
        """
        is just for IDE recognize.
        """
        return super().__getattribute__(item)
    
    """ with MetaMemberControl then you don't have to write as following
    @property
    def name(self):
        return self._name
    
    @property
    def age(self):
        return self._age
    """

    def test_demo(): human = Human('Carson', 27)

    human.age = 18 # you can't modify private members:_age <-- this is defined by yourself.

    # human.k = 18  # 'Human' object has no attribute 'k'  <-- system error.
    age1 = human._age  # It's OK, although the IDE will show some warnings. (Access to a protected member _age of a class)
    
    age2 = human.age  # It's OK! see below:
    """
    if you do not define `__getattribute__` at the class of Human,
    the IDE will show you: Unresolved attribute reference 'age' for class 'Human'
    but it's ok on running since the MetaMemberControl will help you.
    """

    if name == 'main': test_demo()

Le site metaclass mächtig ist, kannst du viele Dinge damit tun (z. B. Affenmagie), aber sei vorsichtig, das ist vielleicht nur dir bekannt.

19voto

Manukumar Punkte 185

Die oberste Antwort ist richtig .

Aber vielleicht kommen die Leser hierher, weil sie Antworten auf ähnlich benannte innere Klassen suchen. Sie sind in populären Bibliotheken vorhanden, wie z.B. Django y WTForms .

Wie DavidW in den Kommentaren unter dieser Antwort anmerkt, diese sind bibliotheksspezifische Funktionen und sind nicht zu verwechseln mit den erweiterten, nicht verwandten Python-Sprache Merkmal mit ähnlichem Namen .

Vielmehr handelt es sich um Namensräume innerhalb der Dicts von Klassen. Aus Gründen der Lesbarkeit werden sie mit inneren Klassen konstruiert.

In diesem Beispiel ein spezielles Feld, abstract ist sichtbar von den Feldern des Autorenmodells getrennt.

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()

    class Meta:
        abstract = True

Ein weiteres Beispiel findet sich in der Dokumentation zu WTForms :

from wtforms.form import Form
from wtforms.csrf.session import SessionCSRF
from wtforms.fields import StringField

class MyBaseForm(Form):
    class Meta:
        csrf = True
        csrf_class = SessionCSRF

    name = StringField("name")

Diese Syntax wird in der Programmiersprache Python nicht besonders behandelt. Meta ist hier kein Schlüsselwort und löst auch kein Metaklassenverhalten aus. Vielmehr wird der Code von Bibliotheken Dritter in Paketen wie Django y WTForms liest diese Eigenschaft unter anderem in den Konstruktoren bestimmter Klassen.

Das Vorhandensein dieser Deklarationen ändert das Verhalten der Klassen, die diese Deklarationen haben. Zum Beispiel, WTForms liest self.Meta.csrf um festzustellen, ob das Formular eine csrf Feld.

2 Stimmen

Dies ist eine Django-spezifische Funktion, bei der eine verschachtelte Klasse namens Meta hat eine besondere Bedeutung. Die Frage bezieht sich auf eine nicht verwandte Python-Sprachfunktion mit einem ähnlichen Namen.

0 Stimmen

@DavidW - hamilyon hat eine heldenhafte Bearbeitung dieses Beitrags vorgenommen. Meiner Meinung nach ist es jetzt eine recht nützliche Antwort.

1 Stimmen

@AlexWaygood Ich hätte die Änderung wahrscheinlich abgelehnt (zu große Änderung...), aber ich sehe, dass sie etwas klärt, das für Verwirrung gesorgt hat, also ist sie wahrscheinlich nützlich. In diesem Sinne habe ich mein Downvote entfernt.

17voto

Venu Gopal Tewari Punkte 5068

In der objektorientierten Programmierung ist eine Metaklasse eine Klasse, deren Instanzen Klassen sind. So wie eine gewöhnliche Klasse das Verhalten bestimmter Objekte definiert, definiert eine Metaklasse das Verhalten bestimmter Klassen und ihrer Instanzen Der Begriff Metaklasse bedeutet einfach etwas, das zur Erstellung von Klassen verwendet wird. Mit anderen Worten, sie ist die Klasse einer Klasse. Die Metaklasse wird verwendet, um die Klasse zu erstellen. So wie ein Objekt eine Instanz einer Klasse ist, ist eine Klasse eine Instanz einer Metaklasse. In Python werden Klassen auch als Objekte betrachtet.

6 Stimmen

Anstatt Definitionen aus Büchern zu geben, wäre es besser gewesen, wenn Sie einige Beispiele hinzugefügt hätten. Die erste Zeile Ihrer Antwort scheint aus dem Wikipedia-Eintrag über Metaklassen kopiert worden zu sein.

3 Stimmen

@verisimilitude Ich bin auch am Lernen, können Sie mir helfen, diese Antwort zu verbessern, indem Sie einige praktische Beispiele aus Ihrer Erfahrung liefern?

17voto

Swati Srivastava Punkte 982

Eine Klasse ist in Python ein Objekt, und wie jedes andere Objekt ist sie eine Instanz von "etwas". Dieses "Etwas" ist eine so genannte Metaklasse. Diese Metaklasse ist eine besondere Art von Klasse, die Objekte anderer Klassen erzeugt. Daher ist die Metaklasse für die Erstellung neuer Klassen verantwortlich. Dadurch kann der Programmierer die Art und Weise, wie Klassen erzeugt werden, individuell anpassen.

Um eine Metaklasse zu erstellen, muss das Overriding von neu () und init ()-Methoden wird in der Regel durchgeführt. neu () kann überschrieben werden, um die Art und Weise zu ändern, wie Objekte erstellt werden, während init () kann überschrieben werden, um die Art der Initialisierung des Objekts zu ändern. Eine Metaklasse kann auf verschiedene Weise erstellt werden. Eine der Möglichkeiten ist die Verwendung der Funktion type(). Die Funktion type(), die mit 3 Parametern aufgerufen wird, erstellt eine Metaklasse. Die Parameter sind :-

  1. Name der Klasse
  2. Tupel mit von der Klasse geerbten Basisklassen
  3. Ein Wörterbuch mit allen Klassenmethoden und Klassenvariablen

Eine andere Möglichkeit, eine Metaklasse zu erstellen, besteht im Schlüsselwort "metaclass". Definieren Sie die Metaklasse als eine einfache Klasse. In den Parametern der geerbten Klasse übergeben Sie metaclass=metaclass_name

Die Metaklasse kann insbesondere in folgenden Situationen verwendet werden :-

  1. wenn ein bestimmter Effekt auf alle Unterklassen angewandt werden muss
  2. Automatischer Wechsel der Klasse (bei der Erstellung) ist erforderlich
  3. Von API-Entwicklern

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X