处理SQL Alchemy声明基的metaclass冲突
我有一个 class X
,它是从一个有自己元类 Meta
的类派生出来的。我还想让 X 也从 SQL Alchemy 的声明性基础类派生。但是我不能简单地这样做:
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'
#...
1 个回答
3
编辑:现在看过 IterRegistry
和 DeclarativeMeta
之后,我觉得你的代码是没问题的。
IterRegistry
定义了 __new__
和 __iter__
,而 DeclarativeMeta
定义了 __init__
和 __setattr__
。因为它们之间没有重叠,所以不一定需要调用 super
。不过,调用 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__
都会被执行。