使用 ABC、PolymorphicModel、django-models 给出元类冲突
Using ABC, PolymorphicModel, django-models gives metaclass conflict
到目前为止,关于 SO 的所有其他答案都以完全相同的方式回答:构建你的元classes,然后继承那些元classes 的'joined' 版本,即
class M_A(type): pass
class M_B(type): pass
class A(metaclass=M_A): pass
class B(metaclass=M_B): pass
class M_C(M_A, M_B): pass
class C:(A, B, metaclass=M_C): pass
但我不知道这些人生活在什么世界里,他们在那里构建自己的元classes!显然,人们会使用来自其他库的 classes,除非你对元编程有完美的处理,否则你怎么知道你是否可以覆盖 class 的元class? (显然我还没有掌握它们)。
我的问题是:
class InterfaceToTransactions(ABC):
def account(self):
return None
...
class Category(PolymorphicModel, InterfaceToTransactions):
def account(self):
return self.source_account
...
class Income(TimeStampedModel, InterfaceToTransactions):
def account(self):
return self.destination_account
...
这当然给了我错误:"metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases"
我已经尝试了上面给出的解决方案的许多变体,下面的不起作用,给出了同样的错误。
class InterfaceToTransactionsIntermediaryMeta(type(PolymorphicModel), type(InterfaceToTransactions)):
pass
class Category(PolymorphicModel, InterfaceToTransactions):
__metaclass__ = InterfaceToTransactionsIntermediaryMeta
...
也不会将任何内容放入 class 元函数中。我已经阅读了关于该主题的所有其他 SO 问题,请不要简单地将其标记为重复。
--------------------接受解决方案后编辑 1/8/18------
奇怪的是,如果我尝试使用这个新配置(我接受的配置)进行迁移,它会再次开始出现 metaclass 错误,但它在运行时仍然有效。如果我注释掉 metaclass 部分,然后 makemigrations 和 migrate,它会成功,但每次迁移后我都必须把它放回那里。
如果您使用的是 Python 3,则说明您正在尝试错误地使用派生元class。
并且由于您得到 "the same error",而不是其他可能的、更微妙的错误,我想说这就是正在发生的事情。
试着改成:
class IntermediaryMeta(type(InterfaceToTransactions), type(PolymorphicModel)):
pass
class Category(PolymorphicModel, InterfaceToTransactions, metaclass=IntermediaryMeta):
...
(至少 ABCMeta class 可以保证使用 super
协同工作,这足以让 classe 它首先放在基础上)
元组)
如果这给您带来了新的和改进的错误,这意味着这些 class 中的一个或两个由于多种动机之一而无法真正正确地协作。然后,要走的路是强制依赖于 ABCMeta 的继承树不要这样做,因为它的作用在一种语言中几乎是审美的,而其他一切都是 "consenting adults" 像 Python.
不幸的是,实现这一点的方法是使用不同的暴力方法,从安全的 "rewritting everything" 到猴子修补 ABCMeta 和抽象方法 "InterfaceToTransactions" 被定义为什么都不做。
如果您需要到达那里并需要一些帮助,请post另一个问题。
抱歉 - 这实际上是使用 metaclasses 的主要缺点。
除非django-polymorphic决定从abc.ABC继承,否则这将很难实现。一个好的解决方案是“手动”创建您的界面。例如:
class InterfaceToTransactions:
def account(self):
raise NotImplementedError("Account method must be implemented.")
...
class Category(PolymorphicModel, InterfaceToTransactions):
def account(self):
return self.source_account
...
class Income(TimeStampedModel, InterfaceToTransactions):
def account(self):
return self.destination_account
...
到目前为止,关于 SO 的所有其他答案都以完全相同的方式回答:构建你的元classes,然后继承那些元classes 的'joined' 版本,即
class M_A(type): pass
class M_B(type): pass
class A(metaclass=M_A): pass
class B(metaclass=M_B): pass
class M_C(M_A, M_B): pass
class C:(A, B, metaclass=M_C): pass
但我不知道这些人生活在什么世界里,他们在那里构建自己的元classes!显然,人们会使用来自其他库的 classes,除非你对元编程有完美的处理,否则你怎么知道你是否可以覆盖 class 的元class? (显然我还没有掌握它们)。
我的问题是:
class InterfaceToTransactions(ABC):
def account(self):
return None
...
class Category(PolymorphicModel, InterfaceToTransactions):
def account(self):
return self.source_account
...
class Income(TimeStampedModel, InterfaceToTransactions):
def account(self):
return self.destination_account
...
这当然给了我错误:"metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases" 我已经尝试了上面给出的解决方案的许多变体,下面的不起作用,给出了同样的错误。
class InterfaceToTransactionsIntermediaryMeta(type(PolymorphicModel), type(InterfaceToTransactions)):
pass
class Category(PolymorphicModel, InterfaceToTransactions):
__metaclass__ = InterfaceToTransactionsIntermediaryMeta
...
也不会将任何内容放入 class 元函数中。我已经阅读了关于该主题的所有其他 SO 问题,请不要简单地将其标记为重复。
--------------------接受解决方案后编辑 1/8/18------
奇怪的是,如果我尝试使用这个新配置(我接受的配置)进行迁移,它会再次开始出现 metaclass 错误,但它在运行时仍然有效。如果我注释掉 metaclass 部分,然后 makemigrations 和 migrate,它会成功,但每次迁移后我都必须把它放回那里。
如果您使用的是 Python 3,则说明您正在尝试错误地使用派生元class。
并且由于您得到 "the same error",而不是其他可能的、更微妙的错误,我想说这就是正在发生的事情。
试着改成:
class IntermediaryMeta(type(InterfaceToTransactions), type(PolymorphicModel)):
pass
class Category(PolymorphicModel, InterfaceToTransactions, metaclass=IntermediaryMeta):
...
(至少 ABCMeta class 可以保证使用 super
协同工作,这足以让 classe 它首先放在基础上)
元组)
如果这给您带来了新的和改进的错误,这意味着这些 class 中的一个或两个由于多种动机之一而无法真正正确地协作。然后,要走的路是强制依赖于 ABCMeta 的继承树不要这样做,因为它的作用在一种语言中几乎是审美的,而其他一切都是 "consenting adults" 像 Python.
不幸的是,实现这一点的方法是使用不同的暴力方法,从安全的 "rewritting everything" 到猴子修补 ABCMeta 和抽象方法 "InterfaceToTransactions" 被定义为什么都不做。
如果您需要到达那里并需要一些帮助,请post另一个问题。
抱歉 - 这实际上是使用 metaclasses 的主要缺点。
除非django-polymorphic决定从abc.ABC继承,否则这将很难实现。一个好的解决方案是“手动”创建您的界面。例如:
class InterfaceToTransactions:
def account(self):
raise NotImplementedError("Account method must be implemented.")
...
class Category(PolymorphicModel, InterfaceToTransactions):
def account(self):
return self.source_account
...
class Income(TimeStampedModel, InterfaceToTransactions):
def account(self):
return self.destination_account
...