我有一个class X
,它派生自一个拥有自己的元类Meta
的类。我还希望从SQL Alchemy中的声明性基础派生X.但我不能做那么简单的
def class MyBase(metaclass = Meta):
#...
def class X(declarative_base(), MyBase):
#...
因为我会得到元类冲突错误:'派生类的元类必须是其所有基础的元类的(非严格)子类。我知道我需要创建一个新的元类,它可以从Meta和声明性基础使用的任何元类派生(我认为DeclarativeMeta?)。所以写下来就足够了:
def class NewMeta(Meta, DeclarativeMeta): pass
def class MyBase(metaclass = NewMeta):
#...
def class X(declarative_base(), MyBase):
#...
我尝试了这个,似乎工作;但是我担心这个代码可能会引入一些问题。
我阅读了手册,但对我来说有点太神秘了。什么是
修改
我的课程所用的代码如下:
class IterRegistry(type):
def __new__(cls, name, bases, attr):
attr['_registry'] = {}
attr['_frozen'] = False
print(name, bases)
print(type(cls))
return type.__new__(cls, name, bases, attr)
def __iter__(cls):
return iter(cls._registry.values())
class SQLEnumMeta(IterRegistry, DeclarativeMeta): pass
class EnumType(metaclass = IterRegistry):
def __init__(self, token):
if hasattr(self, 'token'):
return
self.token = token
self.id = len(type(self)._registry)
type(self)._registry[token] = self
def __new__(cls, token):
if token in cls._registry:
return cls._registry[token]
else:
if cls._frozen:
raise TypeError('No more instances allowed')
else:
return object.__new__(cls)
@classmethod
def freeze(cls):
cls._frozen = True
def __repr__(self):
return self.token
@classmethod
def instance(cls, token):
return cls._registry[token]
class C1(Base, EnumType, metaclass = SQLEnumMeta):
__tablename__ = 'c1'
#...
答案 0 :(得分:3)
修改:现在看了IterRegistry
和DeclarativeMeta
,我觉得你的代码还可以。
IterRegistry
定义__new__
和__iter__
,而DeclarativeMeta
定义__init__
和__setattr__
。由于没有重叠,因此无需直接调用super
。不过,最好这样做,以便为将来的代码提供证据。
您是否可以控制Meta
的定义?你能告诉我们它的定义吗?除非我们看到Meta
的定义,否则我认为我们不能说它有效或无效。
例如,如果您的Meta
未致电,则可能存在问题
super(Meta,cls).__init__(classname, bases, dict_)
如果您运行此代码
class DeclarativeMeta(type):
def __init__(cls, classname, bases, dict_):
print('DeclarativeMeta')
# if '_decl_class_registry' in cls.__dict__:
# return type.__init__(cls, classname, bases, dict_)
# _as_declarative(cls, classname, dict_)
return type.__init__(cls, classname, bases, dict_)
class Meta(type):
def __init__(cls, classname, bases, dict_):
print('Meta')
return type.__init__(cls, classname, bases, dict_)
class NewMeta(Meta,DeclarativeMeta): pass
class MyBase(object):
__metaclass__ = NewMeta
pass
然后只打印字符串'Meta'
。
换句话说,只有Meta.__init__
才能运行。 DeclarativeMeta.__init__
被跳过。
另一方面,如果你定义
class Meta(type):
def __init__(cls, classname, bases, dict_):
print('Meta')
return super(Meta,cls).__init__(classname, bases, dict_)
然后Meta.__init__
和DeclarativeMeta.__init__
都会运行。