python导入循环依赖项(可能还有函数声明)
您好,我确实进入了循环依赖,除了加倍代码之外,什么是不可重构的 我有一些类似的东西(只是要复杂得多): myParser.py: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
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不介意循环导入。只要你意识到导入运行的代码不起作用。