英文:
Dynamically define class with inheritance and static attributes (sqlmodel / sqlalchemy metaclasses)
问题
class SQLModel_custom(SQLModel, registry=self.mapper_registry):
metadata = MetaData(schema=self.schema)
我尝试了类似这样的方式:
type('SQLModel_custom', (SQLModel, self.mapper_registry), {'metadata': MetaData(schema=self.schema)})
但是这给我产生了以下错误:
TypeError: metaclass conflict: 派生类的元类必须是其所有基类的元类的(非严格的)子类
也许问题出在我在动态版本中定义父类时没有使用 registry=
,但我不知道如何实现相同的结果。有什么建议吗?谢谢!
英文:
I have the following class definition that I would like to make dynamic:
class SQLModel_custom(SQLModel, registry=self.mapper_registry):
metadata = MetaData(schema=self.schema)
I've tried something like that:
type('SQLModel_custom', (SQLModel, self.mapper_registry), {'metadata': MetaData(schema=self.schema)})
But this give me the following error:
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
Maybe the issue comes from the fact I'm not using registry=
when defining parent classes in the dynamic version, but I don't see how I could acheive the same result.
Any advice? Thank you!
答案1
得分: 1
这里有两个问题:
-
正如错误消息所指示的,你调用了错误的元类。
SQLModel
本身并不是用type
构造的,而是type
的某个子类。确定正确元类的规则可能很复杂,但在这里很简单:使用与(唯一的)父类相同的元类。 -
第二个参数中只包括基类;
registry
不是一个基类,而是一个关键字参数,意图是传递给元类。(如果在元组中看到self.mapper_registry
,一旦你调用正确的元类,应该会看到相关错误。)
以下代码应该可以工作:
mc = type(SQLModel)
SQLModel_custom = mc('SQLModel_custom',
(SQLModel,),
{'metadata': MetaData(schema=self.schema)},
registry=self.mapper_registry)
第一个问题没有我之前认为的那么严重;错误消息来自尝试使用 SQLModel
和 self.mapper_registry
的类型来确定正确的元类。显然,type
本身可以返回适当元类的实例,而无需显式调用它。一个简单的例子:
class MyMeta(type):
pass
class Foo(metaclass=MyMeta):
pass
Bar = type('Bar', (Foo,), {})
# 对 type 的调用找出正确的元类是 type(Foo) == MyMeta,而不是 type 本身。
assert isinstance(Bar, MyMeta)
英文:
There are two problems here:
-
As the error message indicates, you are calling the wrong metaclass.
SQLModel
itself is not constructed withtype
, but some other subclass oftype
. While the rules for determining the correct metaclass can be complicated, here it's simple: use the same one the (only) parent uses. -
Only base classes are included in the 2nd argument to the metaclass;
registry
is not a base class, but a keyword argument intended to be passed to the metaclass. (If you seeself.mapper_registry
in the tuple, you should see a relevant error once you call the correct metaclass.)
The following should work:
mc = type(SQLModel)
SQLModel_custom = mc('SQLModel_custom',
(SQLModel,),
{'metadata': MetaData(schema=self.schema)},
registry=self.mapper_registry)
Point 1 is less of an issue than I previously thought; the error message comes from trying to use the types of SQLModel
and self.mapper_registry
to determine the correct metaclass. type
itself apparently can return an instance of the proper metaclass without you needing to call it explicitly. A simple example:
class MyMeta(type):
pass
class Foo(metaclass=MyMeta):
pass
Bar = type('Bar', (Foo,), {})
# The call to type figures out that the correct metaclass is
# type(Foo) == MyMeta, not type itself.
assert isinstance(Bar, MyMeta)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论