python导入循环依赖(也许是函数声明)

时间:2015-12-18 19:33:17

标签: python import circular-dependency

你好,我确实进入了循环依赖,除了加倍代码之外,还有什么不可重构。

我有类似的东西(只有更复杂):

myParser.py:

    {
        {"Hello, world", "dlrow ,olleH"},
        {"Hello, 世界", "界世 ,olleH"},
        {"", ""},
    }

tbl.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

main.py:

import myParser
tblx = {
       1:("cmd",),
       2:("evnt",myParser.parseEvnt),
       }

我得到的明显错误是:

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()    

在C中,我想我会在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' 中通过声明告诉他,有功能tbl.py。我不需要包含parseEvnt(),也不会包含循环包含。

在python中我不知道该怎么做。

我读了几个帖子,总有一些聪明人推荐重构。但在这种情况下,myParser需要查看parseCmd()需要查看tblx(除非函数声明)和parseEvnt()需要调用parseEvnt()parseCmd()包含触发evnt并且我不想将解码cmd代码加倍。

有没有办法让它在python中运行?

4 个答案:

答案 0 :(得分:2)

应避免循环进口。需要重构,任何仍需要循环导入的解决方法都不是一个好的解决方案。

话虽如此,重构并不一定非常广泛。至少有几个相当简单的解决方案。

解决方案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) 

还有其他方法可以完成同样的事情。例如,您可以添加&#34;配置&#34; myParser中的方法,然后让main.py调用configure方法并传入对其parseCmd的引用。然后,configure方法可以将此引用存储在全局变量中。

答案 1 :(得分:2)

另一种选择是在使用它的函数中导入main:

main.py

import sys

def parseEvnt():
    import main
    sys.stdout.write("evnt:")
    main.parseCmd(1)     

答案 2 :(得分:2)

如果你坚持不重构(这是真正的解决方案 - 不是一个聪明人),你可以在myParser.py

中将有问题的导入移动到你的函数中
import sys

def parseEvnt():
    import main  ## import moved into function
    sys.stdout.write("evnt:")
    main.parseCmd(1)

再次,看看你是否可以重新设计你的代码,以避免这种相互依赖。

上述解决方案有点像黑客攻击,无法解决因此依赖而可能遇到的未来问题。

答案 3 :(得分:2)

只要模块不尝试使用彼此的数据直到所有导入完成,您就可以经常摆脱循环依赖 - 实际上,这意味着使用命名空间引用({{ 1}}是禁止的)并且只使用函数和方法中的其他模块(全局空间中没有from module import something)。这是因为在导入开始时,python将模块名称放在mystuff = module.mystuff中,并且不再尝试导入该模块。

您遇到了麻烦,因为当您运行sys.modules时,python会将main.py添加到__main__。当代码最终传到sys.modules时,没有&#34; main&#34;在模块列表中,import main再次导入...并且其顶级代码尝试运行。

让我们重新排列您的测试用例并输入一些打印语句来判断导入的时间。

<强> myParser.py

main.py

<强> tbl.py

print('  + importing myParser')
import sys

print('import parsecmd')
import parsecmd
def parseEvnt():
    sys.stdout.write("evnt:")
    parsecmd.parseCmd(1)

Parsecmd.py(新)

print('  + importing tbl')
print('import myParser')
import myParser
tblx = {
       1:("cmd",),
       2:("evnt",myParser.parseEvnt),
       }

<强> main.py

print('  + importing parsecmd')
print('import tbl')
import tbl
def parseCmd(d):
    print(tbl.tblx[d][0])

当我运行它时,我得到了

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()