簡體   English   中英

python導入循環依賴(也許是函數聲明)

[英]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中工作?

應避免循環進口。 需要重構,任何仍需要循環導入的解決方法都不是一個好的解決方案。

話雖如此,重構不一定非常廣泛。 至少有幾個相當簡單的解決方案。

解決方案1:將共享功能移動到共享模塊

由於您想要從多個地方使用parseCmd ,請將其移至單獨的文件中。 這樣, main.pymyParser.py都可以導入該函數。

解決方案2:將主傳遞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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM