繁体   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