[英]python import circular dependency (and perhaps function declaration)
你好,我確實進入了循環依賴,除了加倍代碼之外,什么不是重構的。
我有類似的東西(只有更復雜):
myParser.py:
import sys
import main #comment this to make it runnable
def parseEvnt():
sys.stdout.write("evnt:")
main.parseCmd(1) #comment this to make it runnable
tbl.py:
import myParser
tblx = {
1:("cmd",),
2:("evnt",myParser.parseEvnt),
}
main.py:
import tbl
def parseCmd(d):
print(tbl.tblx[d][0])
data=[1,2]
for d in data:
if(d<2):
parseCmd(d)
else:
fce = tbl.tblx[d][1]
fce()
我得到的明顯錯誤是:
File "D:\Data\vbe\workspace\marsPython\testCircular2\main.py", line 1, in <module>
import tbl
File "D:\Data\vbe\workspace\marsPython\testCircular2\tbl.py", line 1, in <module>
import myParser
File "D:\Data\vbe\workspace\marsPython\testCircular2\myParser.py", line 2, in <module>
import main
File "D:\Data\vbe\workspace\marsPython\testCircular2\main.py", line 7, in <module>
parseCmd(d)
File "D:\Data\vbe\workspace\marsPython\testCircular2\main.py", line 3, in parseCmd
print(tbl.tblx[d][0])
AttributeError: module 'tbl' has no attribute 'tblx'
在CI中我想通過tbl.py
的聲明告訴他有函數parseEvnt()
。 我不需要包含myParser
,也不會包含循環包含。
在python我不知道該怎么做。
我讀了幾個帖子,總有一些明智的人推薦重構。 但是,在這種情況下parseCmd()
需要看到tblx
這需要看parseEvnt()
除非函數聲明)和parseEvnt()
需要調用parseCmd()
(COS evnt
包含觸發cmd
,我不希望再次解碼CMD碼)。
有沒有辦法讓它在python中工作?
應避免循環進口。 需要重構,任何仍需要循環導入的解決方法都不是一個好的解決方案。
話雖如此,重構不一定非常廣泛。 至少有幾個相當簡單的解決方案。
由於您想要從多個地方使用parseCmd
,請將其移至單獨的文件中。 這樣, main.py
和myParser.py
都可以導入該函數。
parseCmd
傳遞給parseEvnt
。 首先,讓parseEvnt
接受一個參數來告訴它運行哪個函數:
# myParser.py
import sys
def parseEvnt(parseCmd):
sys.stdout.write("evnt:")
parseCmd(1)
接下來,當您調用myParser.parseEvnt
,傳入對main.parseCmd
的引用:
# main.py:
...
else:
fce = tbl.tblx[d][1]
fce(parseCmd)
還有其他方法可以完成同樣的事情。 例如,您可以在myParser
添加“configure”方法,然后讓main.py
調用configure
方法並傳入對其parseCmd
的引用。 然后, configure
方法可以將此引用存儲在全局變量中。
另一種選擇是在使用它的函數中導入main:
main.py
import sys
def parseEvnt():
import main
sys.stdout.write("evnt:")
main.parseCmd(1)
如果你堅持不重構(這是真正的解決方案 - 不是一個聰明人),你可以將有問題的導入移動到myParser.py
的函數中
import sys
def parseEvnt():
import main ## import moved into function
sys.stdout.write("evnt:")
main.parseCmd(1)
再次,看看您是否可以重新設計代碼,以避免這種相互依賴性。
上面的解決方案是一種破解,並不會解決由於這種依賴性而可能遇到的未來問題。
只要模塊在完成所有導入之前不嘗試使用彼此的數據,您就可以經常擺脫循環依賴 - 實際上,這意味着使用命名空間引用( from module import something
被禁止)並且僅使用函數和方法中的其他模塊(全局空間中沒有mystuff = module.mystuff
)。 那是因為當導入開始時,python將模塊名稱放在sys.modules
並且不會再嘗試導入該模塊。
你遇到了麻煩,因為當你運行main.py
,python會將__main__
添加到sys.modules
。 當代碼最終import main
,模塊列表中沒有“main”,因此再次導入main.py
...並且它的頂級代碼試圖運行。
讓我們重新安排你的測試用例並輸入一些打印語句來告訴導入何時發生。
myParser.py
print(' + importing myParser')
import sys
print('import parsecmd')
import parsecmd
def parseEvnt():
sys.stdout.write("evnt:")
parsecmd.parseCmd(1)
tbl.py
print(' + importing tbl')
print('import myParser')
import myParser
tblx = {
1:("cmd",),
2:("evnt",myParser.parseEvnt),
}
Parsecmd.py(新)
print(' + importing parsecmd')
print('import tbl')
import tbl
def parseCmd(d):
print(tbl.tblx[d][0])
main.py
print('running main.py')
print('import parsecmd')
import parsecmd
if __name__ == "__main__":
data=[1,2]
for d in data:
if(d<2):
parsecmd.parseCmd(d)
else:
fce = parsecmd.tbl.tblx[d][1]
fce()
當我跑它時,我得到了
running main.py
import parsecmd
+ importing parsecmd
import tbl
+ importing tbl
import myParser
+ importing myParser
import parsecmd <-- didn't reimport parsecmd
cmd
evnt:cmd
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.