Heim > Backend-Entwicklung > Python-Tutorial > Tiefer Einblick in Python-Klassen und Metaklassen II

Tiefer Einblick in Python-Klassen und Metaklassen II

高洛峰
Freigeben: 2016-11-22 17:06:19
Original
1257 Leute haben es durchsucht

Gehen wir eine Ebene zurück und sehen uns an, wie das Klassenobjekt selbst generiert wird.

Wir wissen, dass die Methode type() den Typ eines Objekts überprüfen oder bestimmen kann, aus welcher Klasse das Objekt generiert wird:

print(type(12))
print(type('python'))
Nach dem Login kopieren
<class &#39;int&#39;>
<class &#39;str&#39;>
Nach dem Login kopieren
class A:
    passprint(type(A))
Nach dem Login kopieren
<class &#39;type&#39;>
Nach dem Login kopieren

Pass Wie aus diesem Code ersichtlich ist, wird Klassenobjekt A von type() generiert, was bedeutet, dass dieser Typ auch zum Generieren neuer Objekte verwendet werden kann und was generiert wird, ein Klassenobjekt, also die Klasse aller Klassenobjekte ist :

print(type.__doc__)
Nach dem Login kopieren
type(object_or_name, bases, dict)
type(object) -> the object&#39;s type
type(name, bases, dict) -> a new type
Nach dem Login kopieren

class Die Syntax zum Definieren einer Klasse wird tatsächlich in type(name, bases, dict) konvertiert, wobei der Name-Parameter der Name der Klasse und bases ein erbendes Tupel ist die übergeordnete Klasse, und dict ist das Attribut und die Methode:

class A:
    pass# 实际上等于B = type(&#39;A&#39;, (), {})

print(A.__name__ == B.__name__)
Nach dem Login kopieren
True
Nach dem Login kopieren

Theoretisch ist dies die Bedeutung der Metaklasse, aber aus praktischer Sicht ist die Verwendung offensichtlich bequemer und sinnvoller Klassensyntax, und die eigentliche Bedeutung von Metaklasse besteht darin, den Klassentyp zu erben, um eine neue Metaklasse zu erstellen und bestimmte Operationen auszuführen, um Klassenobjekte mit bestimmtem Verhalten zu erzeugen. Unter diesem Gesichtspunkt unterscheidet sich sein Wesen nicht von gewöhnlichen Klassenobjekten, außer dass es den Typ Klasse erbt.

Beim Generieren einer Instanz wird diese durch Aufrufen der Methode __init__ initialisiert. Tatsächlich wird zuvor die Methode __new__ aufgerufen, um die Instanz zu erstellen, und dann durch __init__ initialisiert, als ob __new__ für die Deklaration von Variablen verantwortlich wäre und __init__ ist für die Initialisierung deklarierter Variablen verantwortlich. Hier gilt die Regel, dass der Rückgabewert von __new__(cls,) eine Instanz des cls-Parameters sein muss, andernfalls wird __init__ nicht ausgelöst. Beispielsweise in der Definition von enum.Enum, da der Aufzählungstyp ein Singleton-Modus ist , also in der Definition von __new__ Wenn seine Instanz nicht zurückgegeben wird, wird sie nicht initialisiert:

class Enum:
    def __new__(cls, value):
        print(cls, value)
        return value
    def __init__(self):
        print("Will not be called!")
e = Enum(1)
Nach dem Login kopieren
<class &#39;__main__.Enum&#39;> 1
Nach dem Login kopieren

Wenn Sie __new__ selbst definieren, müssen Sie normalerweise eine Instanz von cls erstellen, indem Sie aufrufen __new__-Methode der übergeordneten Klasse und auch beim Definieren der Metaklasse Beim Aufrufen der oben erwähnten Verwendung des Typs (da die Metaklasse vom Typ erbt):

class MetaEnum(type):
    def __new__(metaclass, name, base, attrs):
        print("Metaclass: {}\nName: {}\nParents: {}\nAttributes: {}".format(metaclass, name, base, attrs))
        return super().__new__(metaclass, name, base, attrs)
Nach dem Login kopieren
class Enum(metaclass=MetaEnum):
    # Python 2.7 中定义元类的方法是使用 __metaclass__ 变量
    # [PEP 3115](https://www.python.org/dev/peps/pep-3115/)
    # 将 Python 3.0 以后语法改为 class Cls(metaclass=Meta)
    test = 0
Nach dem Login kopieren
Metaclass: <class &#39;__main__.MetaEnum&#39;>
Name: Enum
Parents: ()
Attributes: {&#39;__qualname__&#39;: &#39;Enum&#39;, &#39;__module__&#39;: &#39;__main__&#39;, &#39;test&#39;: 0}
Nach dem Login kopieren

Zu diesem Zeitpunkt schauen wir bei der Enum-Klasse, die nicht mehr Typ ist, sondern deren Metaklasse MetaEnum:

type(Enum)
__main__.MetaEnum

Zusätzlich zur __new__-Methode, PEP 3115 Definiert auch das Attribut __prepare__ zum Festlegen des initialisierten Namespace (d. h. des dritten Parameters des Typs). Am Beispiel von enum.Enum müssen wir die Wiederverwendung der Attributnamen im Aufzählungstyp einschränken und dann das Verhalten einschränken der Klasse durch Metaklassen

# 定义新的字典类,在赋值新的 dict[k] = v 时
# 检查 k 是否重复
class _EnumDict(dict):
    def __init__(self):
        super().__init__()
        self.members = []
    def __setitem__(self, k, v):
        if k in self.members:
            raise TypeError("Attempted to reuse key: &#39;{}&#39;".format(k))
        else:
            self.members.append(k)
            super().__setitem__(k, v)

class MetaEnum(type):
    @classmethod
    def __prepare__(metaclass, cls, bases):
        return _EnumDict()
    def __new__(metaclass, name, base, attrs):
        return super().__new__(metaclass, name, base, attrs)
class Enum(metaclass=MetaEnum):
    pass

class Color(Enum):
    try:
        red = 1
        red = 2
    except TypeError:# 这里没有使用 as err: 的原因是?
        print("TypeError catched")
Nach dem Login kopieren
TypeError catched
Nach dem Login kopieren

Alle Objekte sind Instanzen einer bestimmten Klasse oder eine Instanz eines bestimmten Metaklassentyps ist eine eigene Metaklasse und eine eigene Instanz.

Tiefer Einblick in Python-Klassen und Metaklassen II

Zusammenfassung

Metaklassen sind in Python relativ tiefschwarze Magie und werden in allgemeinen Alltagsanwendungen möglicherweise nicht häufig verwendet, aber das Verständnis der dahinter stehenden Prinzipien ist dafür unerlässlich Das Verständnis der objektorientierten Programmierung in Python ist hilfreich. Wenn Sie tiefgreifende Änderungen an einer Klasse vornehmen müssen, wissen Sie zumindest, wo Sie anfangen müssen.


Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage