处理与 SQL Alchemy 声明基的元类冲突
我有一个 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'
#...
I have a class X
which derives from a class with its own metaclass Meta
. I want to also derive X from the declarative base in SQL Alchemy. But I can't do the simple
def class MyBase(metaclass = Meta):
#...
def class X(declarative_base(), MyBase):
#...
since I would get metaclass conflict error: 'the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases'. I understand that I need to create a new metaclass that would derive from both Meta and from whatever metaclass the declarative base uses (DeclarativeMeta I think?). So is it enough to write:
def class NewMeta(Meta, DeclarativeMeta): pass
def class MyBase(metaclass = NewMeta):
#...
def class X(declarative_base(), MyBase):
#...
I tried this, and it seems to work; but I'm afraid I may have introduced some problem with this code.
I read the manual, but it's a bit too cryptic for me. What's
EDIT:
The code used for my classes is as follows:
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'
#...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
编辑:现在查看了
IterRegistry
和DeclarativeMeta
,我认为您的代码没问题。IterRegistry
定义__new__
和__iter__
,而DeclarativeMeta
定义__init__
和__setattr__
。由于没有重叠,因此不需要直接调用super
。尽管如此,为了让您的代码面向未来,最好这样做。您可以控制
Meta
的定义吗?你能告诉我们它的定义吗?我认为除非我们看到Meta
的定义,否则我们不能说它有效或无效。例如,如果您的
Meta
不调用,则存在潜在问题super(Meta,cls).__init__(classname, bases, dict_)
如果运行此代码
,则仅打印字符串
'Meta'
。换句话说,只有
Meta.__init__
运行。DeclarativeMeta.__init__
被跳过。另一方面,如果您定义
Then
Meta.__init__
和DeclarativeMeta.__init__
都会运行。Edit: Now having looked at
IterRegistry
andDeclarativeMeta
, I think you're code is okay.IterRegistry
defines__new__
and__iter__
, whileDeclarativeMeta
defines__init__
and__setattr__
. Since there is no overlap, there's no direct need to callsuper
. Nevertheless, it would good to do so, to future-proof your code.Do you have control over the definition of
Meta
? Can you show us its definition? I don't think we can say it works or does not work unless we see the definition ofMeta
.For example, there is a potential problem if your
Meta
does not callsuper(Meta,cls).__init__(classname, bases, dict_)
If you run this code
Then only the string
'Meta'
gets printed.In other words, only
Meta.__init__
gets run.DeclarativeMeta.__init__
gets skipped.On the other hand, if you define
Then both
Meta.__init__
andDeclarativeMeta.__init__
gets run.