将类分开到不同文件时的 metaclass 冲突
编辑
问题出在导入上。我应该写的是: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
里面。
我明白SomeInterface
和Bar
的元类是不同的。问题是我不知道该怎么解决这个问题。我尝试了在三重继承导致元类冲突... 有时中建议的解决方案,这在给出的例子中有效,但在我的情况下不行。不确定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 个回答
好的,我觉得我可能漏掉了什么,因为我创建了一个和你类似的文件结构(我想是这样),在我的电脑上是可以正常工作的。感谢你把问题描述得简洁明了,但可能缺少了一些小细节,导致了某些问题?我也不太确定……(也许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