Python 元类冲突/类型错误

标签 python python-2.7

我正在调试 python 脚本(python 不是我的首选语言),这是我第一次在 python 中使用元类。运行代码时出现元类冲突错误,如下所示。

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)
        ...

主.py

import sys
from mouse.Mouse import Mouse
from mouse.TTime import TTime

...

最佳答案

问题是在选择元类时,python 会选择继承最多的版本。但是,您有两个相互冲突的元类(ABCMeta 和任何 MSoftware 拥有的)。

我认为 python3.x docs在这方面比 python2.x 文档稍微更正确:

The appropriate metaclass for a class definition is determined as follows:

  • if no bases and no explicit metaclass are given, then type() is used
  • if an explicit metaclass is given and it is not an instance of type(), > then it is used directly as the metaclass
  • if an instance of type() is given as the explicit metaclass, or bases are defined, then the most derived metaclass is used

一个解决方案是创建一个新的元类,它是两者的混合:

class NewMeta(type(MSoftware), ABCMeta):
    pass

在这种情况下,由于所有的元类都是MSoftware 的元类的“实例”,NewMeta 将被选中,因为它是最派生的元类,并且应该工作(前提是 MSoftware 的元类可以用于协作多重继承)。

这是一个动态创建 NewMeta 的示例,以通过一些虚拟类解决此问题:

class Meta1(type):
    pass

class Meta2(type):
    pass

class Class1(object):
    __metaclass__ = Meta1


# TypeError!
# class Class2(Class1):
#     __metaclass__ = Meta2

class Class2(Class1):
    __metaclass__ = type('Class2Meta', (type(Class1), Meta2), {})

关于Python 元类冲突/类型错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38403795/

相关文章:

python - 将前缀作为字典值添加到列表的每个元素前面

python - 如何在 Python webapp (Google App Engine) 中导入 gflags?

python - 是否可以在浏览器中运行 pygame 或 pyglet ?

python - 找到斐波那契数列部分和的最后一位

python - 正则表达式删除非字母字符并保留空格

postgresql - 在 Windows 8.1 上安装 psycopg2

python - post_save.disconnect 根本不起作用

python - 匹配python正则表达式中的整行

python - 单元测试 flask flask.g

python - 使用带有 Python Flask 的 AJAX 将 html 插入模板