2017-04-24 31 views
0

我的項目:圓形進口在Python與SQLAlchemy的

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(據我所知)。

第二示例

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

我只是說說你的第一個例子,因爲你其實可以複製這兩種情形不改變代碼:

例1:運行run.py直接看到的導入錯誤

例2:打開蟒蛇REPL,並運行:

from run import app 
app.run() 

而且你的第一個例子,現在的工作,你的第二個代碼示例做了同樣的道理:進口被移出的__main__

在示例1中,run.py是頂級執行環境,此處的代碼在__main__中運行。 models.py的相對輸入要求解決models.py中的所有參考(因爲您從models.py導入的類可能依賴於該類本身的以外的其他部分models.py)。models.py做的第一件事是去返回__main__執行相對導入db,並且因爲它需要解析所有引用,所以它會 - 並且它試圖解決的其中一個引用是原始from models import user語句。 Voila,ImportError。

的事情是,在這一點上run.py尚未執行完畢,到目前爲止它仍然試圖導入的User定義。但現在models.py正試圖調用它,好像它已經完成加載,並且它預計run.py已知知道User的定義,即使它正確地試圖找出確切的東西!

這不是一個循環導入 - 不是真的。 models.py只是試圖從尚未完成執行的文件導入,其內容不可用。

通過移動__main__別處 - 進入REPL,或通過移動代碼,以便run.py沒有定義任何 - 你給的代碼機會真正解決任何代碼嘗試之前所有的依賴使用它們。通過使用from run import app; app.run(),這個未執行的唯一代碼。進口自己的所有去完成自己的工作,解決他們的依賴關係,讓他們提供給__main__

TL;醫生不小心編寫代碼,從__main__進口時__main__還不知道它被要求

的事情
+0

謝謝你的回答!如果我正確理解,我的第一個例子不起作用,因爲我試圖在執行的文件中使用循環導入? – jQuick

+1

@jQuick這或多或少歸結爲什麼 - 要記住的重要一點是,執行的文件尚未解析所有定義,因此尚未準備好讓其他文件嘗試從它。 – daveruinseverything