我正在调试一个python脚本(python不是我的语言),这是我第一次在python中使用元类#s。当我运行下面的代码时,我遇到了元类冲突错误。
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
在尝试解决它时,我在MySQLMSoftware
中注释掉了元类声明,认为它是多余的,因为它继承自具有相同元类声明的类,但这导致:
TypeError: Error when calling the metaclass bases
module.__init__() takes at most 2 arguments (3 given)
非常感谢任何见解,指导或指导。我一直在阅读关于python的元类实现的问题,到目前为止这个问题还没有出现。
MSoftware.py
from abc import ABCMeta, abstractmethod
class MSoftware(object) :
__metaclass__ = ABCMeta
def __init__(self,name,spark=None,mysql=None):
self.name = name
...
MySQLMSoftware.py
from mouse import Mouse, MSoftware
from abc import ABCMeta, abstractmethod
class MySQLMSoftware(MSoftware): # Traceback always goes here
__metaclass__ = ABCMeta
MAX_ROWS = 30000000
def __init__(self,name,years,spark=None,mysql=None):
MSoftware.__init__(self,name,spark,mysql)
self.years = years
...
TTime.py
from mouse.Mouse import Mouse
from mouse.MySQLMSoftware import MySQLMSoftware
class TTime(MySQLMSoftware) :
DATABASE = "Database"
NAME = "table"
YEARS = [2014,2016]
def __init__(self,spark=None,mysql=None):
MySQLMSoftware.__init__(self,TTime.NAME,TTime.YEARS,spark,mysql)
...
main.py
import sys
from mouse.Mouse import Mouse
from mouse.TTime import TTime
...
答案 0 :(得分:4)
问题在于,当选择元类时,python会选择最继承的版本。但是,您有两个相互冲突的元类(ABCMeta
和MSoftware
)。
我认为python3.x docs在这方面比python2.x文档更正确:
类定义的适当元类确定如下:
- 如果没有给出基数且没有给出明确的元类,则使用类型()
- 如果给出了显式元类,并且它不是type()的实例,则>然后它直接用作元类
- 如果
type()
的实例作为显式元类,或base定义,那么使用最多派生的元类
一种解决方案是创建一个新的元类,它是两者的混合:
class NewMeta(type(MSoftware), ABCMeta):
pass
在这种情况下,由于所有元类都是MSoftware
的元类的“实例”,因此它将被选中NewMeta
,因为它是派生最多的元类,并且事情应该有效(前提是{{ 1}}的元类可用于协同多继承)。
这是一个示例,我动态地创建MSoftware
来解决一些虚拟类的问题:
NewMeta
答案 1 :(得分:3)
问题与您的导入有关,并且在同名的类和模块之间存在混淆。您在MSoftware
中导入的MySQLMSoftware.py
是MSoftware.py
中实现的模块,而不是该模块中同名的类。要获得后者(不更改导入),您需要使用MSoftware.MSoftware
。 Mouse
类和模块可能存在类似的问题(更糟糕的是,因为顶级包也被命名为mouse
。)
尝试更改行:
from mouse import Mouse, MSoftware
这两行:
from mouse.Mouse import Mouse
from mouse.MSoftware import MSoftware
这将修复元类冲突问题,并使MySQLMSoftware
类中的元类声明变得不必要。
我想指出问题的根本原因(从更高层面来看)是模块设计不佳。您有几个模块,每个模块似乎包含一个与它们具有相同名称的类。这是其他语言(如Java)中常见的项目布局,但它在Python中并不是必需或不可取的。 <{1}}永远不是一个很好的理由。
可能你应该将大多数(或者全部)软件包的模块组合成少量文件,可能首先将大部分内容放在mouse.Mouse.Mouse
(或顶级{{1}如果你把它们全部组合起来并且不再需要这个包了)。这样你就不会有太多的冗余导入。