我的项目:
project_name
|- my_app
|- __init__.py
|- run.py
|- models.py
第一个例子
run.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)
from models import User
db.create_all()
if __name__ == '__main__':
app.run()
models.py
from run import db
class User(db.Model):
#...
__ init.py __为空
运行此示例后,我收到此错误:
ImportError: cannot import name User
此错误描述了models.py中app变量的循环导入(据我所知)。
第二个例子
run.py
from my_app import app
if __name__ == '__main__':
app.run()
models.py
from my_app import db
class User(db.Model):
#...
__ init.p __
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)
from models import User
db.create_all()
现在一切正常。
而且,在这一点上,我不明白,为什么相同的代码给了我不同的逻辑?
魔法在哪里?为什么__ init.py __中的循环导入不会引发错误?
谢谢!
答案 0 :(得分:0)
我要谈谈你的第一个例子,因为你实际上可以在不改变代码的情况下重现这两种情况:
示例1:直接运行run.py
以查看导入错误
示例2:打开python repl,然后运行:
from run import app
app.run()
你的第一个例子现在有效,出于同样的原因你的第二个代码示例:导入被移出__main__
在示例1中,run.py
是顶级执行环境,此处的代码在__main__
中运行。对models.py
的相对导入要求models.py
中的所有引用都已得到解决(因为您从models.py
导入的类可能依赖于models.py
<的其他部分em>在类本身的之外)。 models.py
做的第一件事是返回到__main__
执行db
的相对导入,因为它需要解析所有引用,它确实 - 和它试图解析的引用之一是原始的from models import user
语句。 Voila,ImportError。
问题是,此时run.py
尚未执行,到目前为止,它仍在尝试导入User
的定义。但是现在models.py
正试图调用它,好像它已经完成加载一样,并且它希望run.py
已经知道 User
的定义,即使它& #39;正好在试图找出那个确切的东西!
这不是循环导入 - 不是真的。 models.py
只是尝试从尚未完成执行的文件导入,其内容无法使用。
将__main__
转移到其他地方 - 或者移动代码,以便run.py不定义任何内容 - 您需要提供代码在任何代码尝试使用它们之前实际解析所有依赖项的机会。使用from run import app; app.run()
,此是未执行的唯一代码。导入本身都可以完成他们的工作,解决他们的依赖关系,并将它们提供给__main__
tl;当__main__
尚未知道要求提供的内容时,请不要意外地编写从__main__
导入的代码