【问题标题】:Metaclass conflict when separating classes into separate files将类分成单独的文件时发生元类冲突
【发布时间】:2014-05-23 07:48:28
【问题描述】:

编辑

问题在于导入。我应该做的是写:from SomeInterface import SomeInterface。真的,我应该按照Python styleguide (PEP 8) 用小写someinterface.py 写模块名称。


我有一个文件model.py,它定义了与我的数据库相关的所有类以及实例化我的 Base。

# 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 的元类是不同的。问题是我不知道如何解决这个问题。我尝试了Triple inheritance causes metaclass conflict... Sometimes 中建议的解决方案,该解决方案适用于给出的示例,但不适用于我的情况。不确定 SqlAlchmey 是否与它有关。

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。

【问题讨论】:

  • 是的...您正面临多重继承问题。还有一个问题......在BarAugmented,它必须将数据保存到的__table__ 是什么?表foo?表bar?你真的需要这种类型的模式吗? (只是问,但对于任何 ORM 来说,它看起来都是一个非常复杂的结构来正确处理)
  • @BorrajaX 非常公平。我编辑了我的问题。
  • MHmm... 看来问题不在 SqlAlchemy... 看看这个:stackoverflow.com/questions/6557407/…code.activestate.com/recipes/… (我刚刚找到那些链接,我不知道是否他们会很有帮助)你能试试非声明性声明吗? (只需声明你的表,然后是你的类,然后是你的映射)?
  • @BorrajaX 感谢您的链接。我之前尝试过,但不幸的是我收到了错误'SomeInterface' has no attribute '_decl_class_registry'
  • 很抱歉 :-( 那么我会选择非声明式的。使用声明式模型可能会改变你的班级__metaclass__(但请等待真正的答案,虽然......你可能不需要这样做)

标签: python sqlalchemy


【解决方案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

【讨论】:

  • 感谢@BorrajaX。真的很有帮助。试图弄清楚为什么我的不工作。这可能是因为我的SomeInterface 具有执行会话查询的方法(但它仍然继承自对象)。
  • 我会弄清楚并报告。
  • 是的,这很奇怪......这不会改变元类......是的,让我知道。我现在很好奇自己:-)
  • 很尴尬。问题在于进口。我应该做的是写:from SomeInterface import SomeInterface。我对 Python 比较陌生。
  • 很高兴我能以某种方式提供帮助......(不知何故......因为我希望我能帮助解决问题,而不是我解决了问题):-D跨度>
猜你喜欢
  • 1970-01-01
  • 2012-01-09
  • 2021-06-18
  • 1970-01-01
  • 2014-11-26
  • 1970-01-01
  • 1970-01-01
  • 2014-02-27
  • 2013-08-27
相关资源
最近更新 更多