英文:
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.
SQLModelitself 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;
registryis not a base class, but a keyword argument intended to be passed to the metaclass. (If you seeself.mapper_registryin 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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论