python导入循环依赖项(可能还有函数声明)

python导入循环依赖项(可能还有函数声明),python,import,circular-dependency,Python,Import,Circular Dependency,您好,我确实进入了循环依赖,除了加倍代码之外,什么是不可重构的 我有一些类似的东西(只是要复杂得多): 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 ru

您好,我确实进入了循环依赖,除了加倍代码之外,什么是不可重构的

我有一些类似的东西(只是要复杂得多):

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()    
导入tbl
def parseCmd(d):
打印(待定。待定[d][0])
数据=[1,2]
对于数据中的d:

如果(d应该避免循环导入。需要重构,任何仍然需要循环导入的解决方案都不是一个好的解决方案

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

解决方案1:将共享功能移动到共享模块 由于要从多个位置使用
parseCmd
,请将其移动到单独的文件中。这样
main.py
myParser.py
都可以导入该函数

解决方案2:将主密码
parseCmd
传递到
parsevnt
。 首先,让
parsevnt
接受一个参数,告诉它要运行哪个函数:

# myParser.py
import sys
def parseEvnt(parseCmd):
    sys.stdout.write("evnt:")
    parseCmd(1) 
接下来,当调用
myParser.parsevnt
时,传入对
main.parseCmd
的引用:

# main.py:

...
else:
    fce = tbl.tblx[d][1]
    fce(parseCmd) 

还有其他方法可以完成同样的任务。例如,您可以添加一个“配置”方法,然后让
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将
\uuu main\uuu
添加到
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)
print('  + importing tbl')
print('import myParser')
import myParser
tblx = {
       1:("cmd",),
       2:("evnt",myParser.parseEvnt),
       }
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()    
tbl.py

print('  + importing myParser')
import sys

print('import parsecmd')
import parsecmd
def parseEvnt():
    sys.stdout.write("evnt:")
    parsecmd.parseCmd(1)
print('  + importing tbl')
print('import myParser')
import myParser
tblx = {
       1:("cmd",),
       2:("evnt",myParser.parseEvnt),
       }
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()    
Parsecmd.py(新)

main.py

print('  + importing myParser')
import sys

print('import parsecmd')
import parsecmd
def parseEvnt():
    sys.stdout.write("evnt:")
    parsecmd.parseCmd(1)
print('  + importing tbl')
print('import myParser')
import myParser
tblx = {
       1:("cmd",),
       2:("evnt",myParser.parseEvnt),
       }
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()    
print('running main.py')
打印('import parsecmd')
导入parsecmd
如果名称=“\uuuuu main\uuuuuuuu”:
数据=[1,2]
对于数据中的d:

如果(我知道我曾经这样做过,当时我不得不为一个学校项目编写递归下降解析器。我想说这与“from import”语法有关,但我现在无法访问需要测试的内容。我不知道这与您的更大项目有何关系,但这里的问题是,您试图使用
main
作为顶级语法evel脚本和导入模块。这通常是有问题的,但在您的情况下,只要您将所有顶级可执行内容放在
下,如果
name\uuuu==“\uuuu main\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu”:
语句,那么它就基本上是无害的。您最终导入了
main
两次(一次为
@tdelaney确实如此。根据项目的不同,如果main应该包含可执行代码,那么它应该只定义将在本地使用的函数。而且由于更多模块使用
parseCmd()
,因此应该将其移动到另一个文件中,根据需要从该文件导入。ad解决方案1)即使您执行
parseCmd
->
tbl
->
myParse
->
parseCmd
。问题的定义中存在逻辑依赖关系。Evnt包含cmd,但也是cmdCode。@VitBernatik:对不起,我不理解该注释。ad解决方案1)即使将其移动到单独的文件中,仍然需要循环导入(
parseCmd
->
tbl
->
myParse
->
parseCmd
).对吗?问题的定义中存在逻辑依赖性。
tbl
包含
cmd
evnt
evnt
解析器必须再次使用
tbl
,因为问题的定义是
evnt
包含
cmd
(触发了
evnt
)。非常感谢!实际上你将
parseCmd(d)
放入
parseCmd.py
具有相同的循环依赖性:->
tbl
>
myParser
->
parseCmd
->。实际上,只要添加一行即可解决此问题:
如果uuuu name\uuuuu==“\uuu main”:
。这一直是个问题!!!我喜欢你的演示
print(“importXY”)
。它甚至会让一个傻瓜(我)理解正在发生的事情。因此,所有明智的人(不是你)再次建议重构:PYTHON不介意循环导入。只要你意识到导入运行的代码不起作用。