将类分开到不同文件时的 metaclass 冲突

0 投票
1 回答
513 浏览
提问于 2025-04-18 02:06

编辑

问题出在导入上。我应该写的是:from SomeInterface import SomeInterface。其实我应该把模块名写成小写,也就是someinterface.py,这符合Python的风格指南(PEP 8)


我有一个文件model.py,里面定义了所有与我的数据库相关的类,并且实例化了我的基础类。

# model.py
metadata = MetaData()
DeclarativeBase = declarative_base()
metadata = DeclarativeBase.metadata

class Bar(DeclarativeBase):
    __tablename__ = 'Bar'
    __table_args__ = {}
    # column and relation definitions

这个model.py文件是自动生成的,所以我不能随便修改它。我做的事情是创建了一个叫modelaugmented.py的文件,在里面通过继承为一些模型类添加额外的功能。

# modelaugmented.py
from model import *
import SomeInterface

class BarAugmented(Bar, SomeInterface):
    pass

# SomeInterface.py
class SomeInterface(object):
    some_method(): pass

我遇到的问题是,对于像BarAugmented这样的类,我收到了以下错误:

 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

只有当SomeInterface在一个单独的文件中时,我才会遇到这个错误,而不是在modelaugmented.py里面。

我明白SomeInterfaceBar的元类是不同的。问题是我不知道该怎么解决这个问题。我尝试了在三重继承导致元类冲突... 有时中建议的解决方案,这在给出的例子中有效,但在我的情况下不行。不确定SqlAlchemy是否与此有关。

class MetaAB(type(DeclarativeBase), type(SomeInterface)):
    pass

class BarAugmented(Bar, SomeInterface):
    __metaclass__ = MetaAB

但随后我又收到了这个错误:

TypeError: Error when calling the metaclass 
bases multiple bases have instance lay-out conflict

使用的是SQLAlchemy 0.8和Python 2.7。

1 个回答

1

好的,我觉得我可能漏掉了什么,因为我创建了一个和你类似的文件结构(我想是这样),在我的电脑上是可以正常工作的。感谢你把问题描述得简洁明了,但可能缺少了一些小细节,导致了某些问题?我也不太确定……(也许SomeInterface有一个abc.abstract的元类?)如果你更新了你的问题,请通过评论告诉我,我会尽量更新我的回答。

接下来是:

文件 stack29A.py(相当于你的 model.py):

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session

DSN = "mysql://root:foobar@localhost/so_tests?charset=utf8"
engine = create_engine(DSN)
Session = scoped_session(sessionmaker(bind=engine))
session = Session()

DeclarativeBase = declarative_base()

class Bar(DeclarativeBase):
    __tablename__ = 'Bar'
    _id = Column('_id', Integer, primary_key=True)
    email = Column('email', String(50)) 

文件 stack29B.py(相当于你的 someinterface.py):

class SomeInterface(object):
    def some_method(self):
        print "hellou"   

文件 stack29C.py(相当于你的 modelaugmented.py):

from stack29A import Bar
from stack29B import SomeInterface

class BarAugmented(Bar, SomeInterface):
    pass

文件 stack29D.py(类似于一个 main.py:用于创建表格和示例):

from stack29C import BarAugmented
from stack29A import session, engine, DeclarativeBase

if __name__ == "__main__":
    DeclarativeBase.metadata.create_all(engine)
    b1 = BarAugmented()
    b1.email = "foo@bar.baz"
    b2 = BarAugmented()
    b2.email = "baz@bar.foo"
    session.add_all([b1, b2])
    session.commit()
    b3 = session.query(BarAugmented)\
                    .filter(BarAugmented.email == "foo@bar.baz")\
                    .first()
    print "b3.email: %s" % b3.email                    
    b3.some_method()

如果我运行“主”文件(stack29D.py),一切都按预期工作:

(venv_SO)borrajax@borrajax:~/Documents/Tests$ python ./stack29D.py
b3.email: foo@bar.baz
hellou

撰写回答