Einführung
In diesem Lab werden Sie sich mit Metaklassen in Python vertraut machen. In Python ist alles, einschließlich Klassen, ein Objekt. Eine Metaklasse ist eine Klasse, die andere Klassen erstellt und bietet eine leistungsstarke Möglichkeit, die Klassen-Erstellung anzupassen.
Die Ziele dieses Labs sind es, zu verstehen, was eine Metaklasse ist, Ihre erste Metaklasse zu erstellen, sie zur Erstellung neuer Klassen zu verwenden und zu beobachten, wie Metaklassen die Klassenvererbung beeinflussen. Die Datei mymeta.py wird während des Labs erstellt.
Das Verständnis von Metaklassen
Metaklassen sind ein fortgeschrittenes, aber leistungsstarkes Feature in Python. Als Anfänger fragen Sie sich vielleicht, was Metaklassen sind und warum sie wichtig sind. Bevor wir mit der Erstellung unserer ersten Metaklasse beginnen, nehmen wir einen Moment Zeit, um diese Konzepte zu verstehen.
Was ist eine Metaklasse?
In Python ist alles ein Objekt, und das umfasst auch Klassen. Genauso wie eine normale Klasse zur Erstellung von Instanzen verwendet wird, wird eine Metaklasse zur Erstellung von Klassen verwendet. Standardmäßig verwendet Python die eingebaute Metaklasse type, um alle Klassen zu erstellen.
Lassen Sie uns den Klassen-Erstellungsprozess Schritt für Schritt analysieren:
- Zuerst liest Python die Klassen-Definition, die Sie in Ihrem Code geschrieben haben. Hier definieren Sie den Namen der Klasse, ihre Attribute und Methoden.
- Dann sammelt Python wichtige Informationen über die Klasse, wie den Klassennamen, alle Basisklassen, von denen sie erbt, und alle ihre Attribute.
- Danach übergibt Python diese gesammelten Informationen an die Metaklasse. Die Metaklasse ist dafür verantwortlich, diese Informationen zu nehmen und das eigentliche Klassen-Objekt zu erstellen.
- Schließlich erstellt und gibt die Metaklasse die neue Klasse zurück.
Eine Metaklasse gibt Ihnen die Möglichkeit, diesen Klassen-Erstellungsprozess anzupassen. Sie können Klassen modifizieren oder untersuchen, während sie erstellt werden, was in bestimmten Szenarien sehr nützlich sein kann.
Lassen Sie uns diese Beziehung visualisieren, um es einfacher zu verstehen:
Metaclass → creates → Class → creates → Instance
In diesem Lab werden wir unsere eigene Metaklasse erstellen. Auf diese Weise können Sie diesen Klassen-Erstellungsprozess in Aktion sehen und ein besseres Verständnis dafür entwickeln, wie Metaklassen funktionieren.
Die Erstellung Ihrer ersten Metaklasse
Jetzt werden wir unsere erste Metaklasse erstellen. Bevor wir mit dem Codieren beginnen, verstehen wir zunächst, was eine Metaklasse ist. In Python ist eine Metaklasse eine Klasse, die andere Klassen erstellt. Sie ist wie ein Bauplan für Klassen. Wenn Sie in Python eine Klasse definieren, verwendet Python eine Metaklasse, um diese Klasse zu erstellen. Standardmäßig verwendet Python die Metaklasse type. In diesem Schritt werden wir eine benutzerdefinierte Metaklasse definieren, die Informationen über die Klasse ausgibt, die sie erstellt. Dies wird uns helfen, zu verstehen, wie Metaklassen hinter den Kulissen funktionieren.
Öffnen Sie VSCode im WebIDE und erstellen Sie eine neue Datei namens
mymeta.pyim Verzeichnis/home/labex/project. Hier werden wir unseren Code für die Metaklasse schreiben.Fügen Sie der Datei folgenden Code hinzu:
## mymeta.py
class mytype(type):
@staticmethod
def __new__(meta, name, bases, __dict__):
print("Creating class :", name)
print("Base classes :", bases)
print("Attributes :", list(__dict__))
return super().__new__(meta, name, bases, __dict__)
class myobject(metaclass=mytype):
pass
Lassen Sie uns analysieren, was dieser Code tut:
- Zunächst definieren wir eine neue Klasse namens
mytype, die vontypeerbt. Datypedie Standard-Metaklasse in Python ist, erstellen wir durch die Vererbung von ihr unsere eigene benutzerdefinierte Metaklasse. - Als Nächstes überschreiben wir die Methode
__new__. In Python ist die Methode__new__eine spezielle Methode, die aufgerufen wird, wenn ein neues Objekt erstellt wird. Im Kontext einer Metaklasse wird sie aufgerufen, wenn eine neue Klasse erstellt wird. - Innerhalb unserer
__new__-Methode geben wir einige Informationen über die zu erstellende Klasse aus. Wir geben den Namen der Klasse, ihre Basisklassen und ihre Attribute aus. Danach rufen wir die__new__-Methode der Elternklasse mitsuper().__new__(meta, name, bases, __dict__)auf. Dies ist wichtig, da es tatsächlich die Klasse erstellt. - Schließlich erstellen wir eine Basisklasse namens
myobjectund geben an, dass sie unsere benutzerdefinierte Metaklassemytypeverwenden soll.
Die __new__-Methode nimmt die folgenden Parameter:
meta: Dies bezieht sich auf die Metaklasse selbst. In unserem Fall ist esmytype.name: Dies ist der Name der zu erstellenden Klasse.bases: Dies ist ein Tupel, das die Basisklassen enthält, von denen die neue Klasse erbt.__dict__: Dies ist ein Wörterbuch, das die Attribute der Klasse enthält.
- Speichern Sie die Datei, indem Sie Strg+S drücken oder auf Datei > Speichern klicken. Das Speichern der Datei stellt sicher, dass Ihr Code aufbewahrt wird und später ausgeführt werden kann.
Die Verwendung Ihrer Metaklasse
Jetzt werden wir eine Klasse erstellen, die unsere Metaklasse über Vererbung nutzt. Dies wird uns helfen zu verstehen, wie die Metaklasse aufgerufen wird, wenn die Klasse definiert wird.
Eine Metaklasse in Python ist eine Klasse, die andere Klassen erstellt. Wenn Sie eine Klasse definieren, verwendet Python eine Metaklasse, um das Klassenobjekt zu konstruieren. Durch die Verwendung von Vererbung können wir angeben, welche Metaklasse eine Klasse verwenden soll.
- Öffnen Sie
mymeta.pyund fügen Sie am Ende der Datei folgenden Code hinzu:
class Stock(myobject):
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
def cost(self):
return self.shares * self.price
def sell(self, nshares):
self.shares -= nshares
Hier definieren wir eine Stock-Klasse, die von myobject erbt. Die __init__-Methode ist eine spezielle Methode in Python-Klassen. Sie wird aufgerufen, wenn ein Objekt der Klasse erstellt wird und dient zur Initialisierung der Attribute des Objekts. Die cost-Methode berechnet die Gesamtkosten der Aktie, und die sell-Methode verringert die Anzahl der Aktien.
Speichern Sie die Datei, indem Sie Strg+S drücken. Das Speichern der Datei stellt sicher, dass die von Ihnen vorgenommenen Änderungen gespeichert werden und später ausgeführt werden können.
Jetzt lassen Sie uns die Datei ausführen, um zu sehen, was passiert. Öffnen Sie ein Terminal im WebIDE und führen Sie aus:
cd /home/labex/project
python3 mymeta.py
Der cd-Befehl wechselt das aktuelle Arbeitsverzeichnis zu /home/labex/project, und python3 mymeta.py führt das Python-Skript mymeta.py aus.
Sie sollten eine Ausgabe ähnlich der folgenden sehen:
Creating class : myobject
Base classes : ()
Attributes : ['__module__', '__qualname__', '__doc__']
Creating class : Stock
Base classes : (<class '__main__.myobject'>,)
Attributes : ['__module__', '__qualname__', '__init__', 'cost', 'sell', '__doc__']
Diese Ausgabe zeigt, dass unsere Metaklasse aufgerufen wird, wenn sowohl die myobject- als auch die Stock-Klasse erstellt werden. Beachten Sie, wie:
- Für
Stockdie Basisklassenmyobjectenthalten, daStockvonmyobjecterbt. - Die Attributliste alle von uns definierten Methoden (
__init__,cost,sell) sowie einige Standardattribute enthält.
- Lassen Sie uns mit unserer
Stock-Klasse interagieren. Erstellen Sie eine neue Datei namenstest_stock.pymit folgendem Inhalt:
## test_stock.py
from mymeta import Stock
## Create a new Stock instance
apple = Stock("AAPL", 100, 154.50)
## Use the methods
print(f"Stock: {apple.name}, Shares: {apple.shares}, Price: ${apple.price}")
print(f"Total cost: ${apple.cost()}")
## Sell some shares
apple.sell(10)
print(f"After selling 10 shares: {apple.shares} shares remaining")
print(f"Updated cost: ${apple.cost()}")
In diesem Code importieren wir die Stock-Klasse aus dem mymeta-Modul. Dann erstellen wir eine Instanz der Stock-Klasse namens apple. Wir verwenden die Methoden der Stock-Klasse, um Informationen über die Aktie auszugeben, die Gesamtkosten zu berechnen, einige Aktien zu verkaufen und dann die aktualisierten Informationen auszugeben.
- Führen Sie diese Datei aus, um unsere
Stock-Klasse zu testen:
python3 test_stock.py
Sie sollten eine Ausgabe wie die folgende sehen:
Creating class : myobject
Base classes : ()
Attributes : ['__module__', '__qualname__', '__doc__']
Creating class : Stock
Base classes : (<class 'mymeta.myobject'>,)
Attributes : ['__module__', '__qualname__', '__init__', 'cost', 'sell', '__doc__']
Stock: AAPL, Shares: 100, Price: $154.5
Total cost: $15450.0
After selling 10 shares: 90 shares remaining
Updated cost: $13905.0
Beachten Sie, dass zuerst die Informationen unserer Metaklasse ausgegeben werden, gefolgt von der Ausgabe unseres Testskripts. Dies liegt daran, dass die Metaklasse aufgerufen wird, wenn die Klasse definiert wird, was vor der Ausführung des Codes im Testskript geschieht.
Die Erkundung der Metaklassenvererbung
Metaklassen haben eine faszinierende Eigenschaft: Sie sind "haftend". Das bedeutet, dass wenn eine Klasse eine Metaklasse verwendet, alle ihre Subklassen in der Vererbungshierarchie ebenfalls dieselbe Metaklasse verwenden werden. Mit anderen Worten, die Metaklasseigenschaft breitet sich entlang der Vererbungskette aus.
Lassen Sie uns dies in Aktion sehen:
- Öffnen Sie zunächst die Datei
mymeta.py. Am Ende dieser Datei werden wir eine neue Klasse hinzufügen. Diese Klasse, namensMyStock, wird von derStock-Klasse erben. Die__init__-Methode wird verwendet, um die Attribute des Objekts zu initialisieren, und wir rufen die__init__-Methode der Elternklasse mitsuper().__init__auf, um die gemeinsamen Attribute zu initialisieren. Dieinfo-Methode wird verwendet, um einen formatierten String mit Informationen über die Aktie zurückzugeben. Fügen Sie folgenden Code hinzu:
class MyStock(Stock):
def __init__(self, name, shares, price, category):
super().__init__(name, shares, price)
self.category = category
def info(self):
return f"{self.name} ({self.category}): {self.shares} shares at ${self.price}"
Nachdem Sie den Code hinzugefügt haben, speichern Sie die Datei
mymeta.py. Das Speichern der Datei stellt sicher, dass die von uns vorgenommenen Änderungen gespeichert werden und später verwendet werden können.Jetzt werden wir eine neue Datei namens
test_inheritance.pyerstellen, um das Vererbungsverhalten der Metaklasse zu testen. In dieser Datei werden wir dieMyStock-Klasse aus der Dateimymeta.pyimportieren. Dann werden wir eine Instanz derMyStock-Klasse erstellen, ihre Methoden aufrufen und die Ergebnisse ausgeben, um zu sehen, wie die Metaklasse über Vererbung funktioniert. Fügen Sie folgenden Code intest_inheritance.pyhinzu:
## test_inheritance.py
from mymeta import MyStock
## Create a MyStock instance
tech_stock = MyStock("MSFT", 50, 305.75, "Technology")
## Test the methods
print(tech_stock.info())
print(f"Total cost: ${tech_stock.cost()}")
## Sell some shares
tech_stock.sell(5)
print(f"After selling: {tech_stock.shares} shares remaining")
print(f"Updated cost: ${tech_stock.cost()}")
- Schließlich führen Sie die Datei
test_inheritance.pyaus, um die Metaklasse in Aktion über Vererbung zu sehen. Öffnen Sie Ihr Terminal, navigieren Sie zum Verzeichnis, in dem sich die Dateitest_inheritance.pybefindet, und führen Sie den folgenden Befehl aus:
python3 test_inheritance.py
Sie sollten eine Ausgabe ähnlich der folgenden sehen:
Creating class : myobject
Base classes : ()
Attributes : ['__module__', '__qualname__', '__doc__']
Creating class : Stock
Base classes : (<class 'mymeta.myobject'>,)
Attributes : ['__module__', '__qualname__', '__init__', 'cost', 'sell', '__doc__']
Creating class : MyStock
Base classes : (<class 'mymeta.Stock'>,)
Attributes : ['__module__', '__qualname__', '__init__', 'info', '__doc__']
MSFT (Technology): 50 shares at $305.75
Total cost: $15287.5
After selling: 45 shares remaining
Updated cost: $13758.75
Beachten Sie, dass obwohl wir für die MyStock-Klasse keine Metaklasse explizit angegeben haben, die Metaklasse dennoch angewendet wird. Dies zeigt deutlich, wie Metaklassen über Vererbung propagieren.
Praktische Anwendungen von Metaklassen
In unserem Beispiel gibt die Metaklasse einfach Informationen über Klassen aus. Metaklassen haben jedoch viele praktische Anwendungen in der realen Programmierung:
- Validierung: Sie können Metaklassen verwenden, um zu prüfen, ob eine Klasse die erforderlichen Methoden oder Attribute hat. Dies hilft sicherzustellen, dass Klassen bestimmte Kriterien erfüllen, bevor sie verwendet werden.
- Registrierung: Metaklassen können Klassen automatisch in einem Register eintragen. Dies ist nützlich, wenn Sie alle Klassen eines bestimmten Typs verfolgen müssen.
- Schnittstellenimplementierung: Sie können verwendet werden, um sicherzustellen, dass Klassen erforderliche Schnittstellen implementieren. Dies hilft, eine konsistente Struktur in Ihrem Code aufrechtzuerhalten.
- Aspektorientierte Programmierung: Metaklassen können Verhaltensweisen zu Methoden hinzufügen. Beispielsweise können Sie Protokollierung oder Leistungsüberwachung zu Methoden hinzufügen, ohne den Methodencode direkt zu ändern.
- ORM-Systeme: In Objekt-Relationalen Mapping (ORM)-Systemen wie Django oder SQLAlchemy werden Metaklassen verwendet, um Klassen auf Datenbanktabellen abzubilden. Dies vereinfacht die Datenbankoperationen in Ihrer Anwendung.
Metaklassen sind sehr leistungsstark, sollten jedoch sparsam verwendet werden. Wie Tim Peters (berühmt für die "Zen of Python") einmal sagte: "Metaklassen sind eine tiefere Magie als 99 % der Benutzer jemals befürchten müssen."
Zusammenfassung
In diesem Lab haben Sie gelernt, was Metaklassen sind und wie sie in Python funktionieren. Sie haben erfolgreich Ihre erste benutzerdefinierte Metaklasse erstellt, um die Klassenerstellung zu überwachen, und sie verwendet, um neue Klassen zu generieren. Darüber hinaus haben Sie beobachtet, wie Metaklassen durch Vererbungshierarchien propagieren.
Metaklassen sind ein fortgeschrittenes Python-Feature, das die Kontrolle über die Klassenerstellung bietet. Obwohl Sie möglicherweise nicht täglich Metaklassen erstellen, bietet das Verständnis von ihnen tiefere Einblicke in das Objektsystem von Python und eröffnet mächtige Möglichkeiten für die Entwicklung von Frameworks und Bibliotheken. Um mehr zu erfahren, erkunden Sie die offizielle Python-Dokumentation und fortgeschrittene Python-Bücher über Metaprogrammierung.