Metaklassen werden selten verwendet, es sei denn, sie sind Bibliotheken, aber sie werden in SQLAlchemy verwendet, daher werde ich sie nur als Referenz zusammenfassen.
Eine Metaklasse ist ein Klassentyp. Im Fall von Python ist der Typ der benutzerdefinierten Klasse im Grunde Typ.
>>> class A(object):
>>> pass
>>>
>>> type(A)
type
Andere Metaklassen als der Typ können für spezielle Zwecke verwendet werden.
Eine vertraute Verwendung von Metaklassen findet sich in der SQL Alchemy-Deklaration.
>>> from sqlalchemy.ext.declarative import declarative_base
>>> Base = declarative_base()
>>> type(Base)
<class 'sqlalchemy.ext.declarative.api.DeclarativeMeta'>
Bei deklarativ wird die Klassendefinition automatisch der Tabellendefinition zugeordnet.
class User(Base):
__tablename__ = 'user_account'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(Varchar(100))
Intern verwendet es eine eigene Meta-Klasse namens sqlalchemy.ext.declarative.api.DeclarativeMeta und bindet die Verarbeitung zum Zeitpunkt der Klassendefinition ein, um die Zuordnungsverarbeitung durchzuführen.
Die Definition von sqlalchemy.ext.declarative.api.DeclarativeMeta lautet wie folgt. init wird aufgerufen, wenn eine Klasse erstellt wird, die Base erbt, und die Klasse und die Tabelle darin verknüpft sind.
sqlalchemy/ext/declarative/api.py
class DeclarativeMeta(type):
def __init__(cls, classname, bases, dict_):
if '_decl_class_registry' not in cls.__dict__:
_as_declarative(cls, classname, cls.__dict__)
type.__init__(cls, classname, bases, dict_)
def __setattr__(cls, key, value):
_add_attribute(cls, key, value)
In Python scheint die Verwendung von Metaklasse eine relativ häufige Methode zu sein, wenn Sie automatisch etwas aus der Klassendefinition heraus tun möchten. Zum Beispiel macht die Form-Klasse von wtforms fast dasselbe.
Je nach Anwendungsfall möchten Sie diesen Vorgang möglicherweise stoppen. Betrachten wir einen Anwendungsfall wie das Zuordnen eines Tabellenobjekts, das durch Reflektion aus der Datenbank erstellt wurde, zu einer Klasse, die durch deklarative_Base erstellt wurde. In solchen Fällen kann der folgende Code verwendet werden.
from sqlalchemy import MetaData, Table
from sqlalchemy.ext.declarative import api, declarative_base
from sqlalchemy.ext.declarative.api import DeclarativeMeta
class_registry = {}
metadata = MetaData()
Base = declarative_base(class_registry=class_registry,
metadata=MetaData())
class MyMetaClass(DeclarativeMeta):
def __init__(cls, classname, bases, dict_):
#Nicht mit der Tabelle verknüpfen
type.__init__(cls, classname, bases, dict_)
@classmethod
def create_class(cls, table_name, class_name, dbsession):
tableobj = Table(table_name, metadata, autoload=True,
autoload_with=dbsession.bind)
class_ = MyMetaClass(class_name, (Base), {})
#Verknüpfen Sie explizit mit der folgenden Tabelle.
class_.__tablename__ = tablename
class_.__table__ = tableobj
for c in tableobj.columns:
setattr(class_, c.name, c)
api.instrument_declarative(class_, class_registry, metadata)
return class_
Recommended Posts