改变进口处理/模块从python2到python3?


问题内容

我试图遵循上一个问题中与SQLAlchemy有关的设计模式,并打算在多个文件之间共享一个公共Base实例。该代码完全适用于python2和python3。

但是,当我在一个模块(称为模型)中移动文件a.py,b.py,c.py和base.py并添加必要的__init__.py文件时,它继续在python2上工作,但会产生错误在python3上(详情如下)。

我有以下文件:

型号/base.py

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

型号/a.py

from sqlalchemy import *
from base import Base
from sqlalchemy.orm import relationship

class A(Base):
    __tablename__ = "A"
    id  = Column(Integer, primary_key=True)
    Bs  = relationship("B", backref="A.id")
    Cs  = relationship("C", backref="A.id")

型号/b.py

from sqlalchemy import *
from base import Base

class B(Base):
    __tablename__ = "B"
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))

型号/c.py

from sqlalchemy import *
from base import Base

class C(Base):
    __tablename__ = "C"    
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))

型号/init.py

(空)

main.py

from sqlalchemy import create_engine
from sqlalchemy.orm import relationship, backref, sessionmaker

from model import base


from model import a
from model import b
from model import c

engine = create_engine("sqlite:///:memory:")
base.Base.metadata.create_all(engine, checkfirst=True)
Session = sessionmaker(bind=engine)
session = Session()

a1 = a.A()
b1 = b.B()
b2 = b.B()
c1 = c.C()
c2 = c.C()

a1.Bs.append(b1)
a1.Bs.append(b2)    
a1.Cs.append(c1)
a1.Cs.append(c2)    
session.add(a1)
session.commit()

python2的工作原理:

$ python main.py ; echo $?
0

python3错误:

$ python3 main.py ; echo $?
Traceback (most recent call last):
  File "main.py", line 7, in <module>
    from model import a
  File "/home/shale/code/py/try/model/a.py", line 2, in <module>
    from base import Base
ImportError: No module named base
1

我最终通过将来自base.py的代码放入我的__init__.py文件(在下面的一个答案中进行描述)解决了这个问题,但是有人知道为什么这会在python3中而不是在python2中产生错误吗?首先是什么原因造成的?


问题答案:

默认情况下,Python 3切换为 绝对 导入,并禁止不合格的相对导入。该from base import Base行就是这样的导入。

Python 3只会寻找顶层模块;您只有一个base顶级模块model.base。使用完整的模块路径,或使用相对的限定词:

from .base import Base

.一开始告诉Python 3的导入,从当前的包开始。

您可以通过添加以下内容在Python 2中启用相同的行为:

from __future__ import absolute_import

这是PEP 328引入的更改,并且from future可以从Python 2.5开始使用导入。