Circular import dependency in Python
假设我有以下目录结构:
1 2 3 4 5 6 7 8 9 10 | a\ __init__.py b\ __init__.py c\ __init__.py c_file.py d\ __init__.py d_file.py |
在
程序失败,说当
如何解决这个问题?
您可以推迟进口,例如在
1 2 3 | def my_function(): from a.b.c import Blah return Blah() |
也就是说,把进口推迟到真正需要的时候。但是,我也会仔细查看我的包定义/使用,因为像所指出的那样的循环依赖可能表示一个设计问题。
如果a依赖于c,c依赖于a,那么它们不是同一个单位吗?
您应该真正检查为什么将A和C拆分为两个包,因为要么您有一些代码,要么您应该拆分为另一个包(以使它们都依赖于该新包,而不是彼此),要么您应该将它们合并到一个包中。
我想了好几次(通常是在处理需要相互了解的模型时)。简单的解决方案就是导入整个模块,然后引用您需要的东西。
所以不要这么做
1 | from models import Student |
一,和
1 | from models import Classroom |
在另一个,就这么做吧
1 | import models |
在其中一个,然后打电话给模特。需要的时候就叫教室。
问题是,从目录运行时,默认情况下只有子目录的包作为候选导入可见,因此不能导入a.b.d。但是,可以导入b.d,因为b是a的子包。
如果您真的想在
您的
1 2 3 4 5 6 7 | import sys import os # set sytem path to be directory above so that a can be a # package namespace DIRECTORY_SCRIPT = os.path.dirname(os.path.realpath(__file__)) sys.path.insert(0,DIRECTORY_SCRIPT+"/..") import a.b.c |
当您想在C中以脚本的形式运行模块时,会遇到一个额外的困难。在这里,包A和包B不存在。您可以对c目录中的
另一种解决方案是使用d_文件的代理。
例如,假设您希望与C_文件共享blah类。因此,D_文件包含:
1 2 3 | class blah: def __init__(self): print("blah") |
以下是您在c_file.py中输入的内容:
1 2 3 4 5 6 7 | # do not import the d_file ! # instead, use a place holder for the proxy of d_file # it will be set by a's __init__.py after imports are done d_file = None def c_blah(): # a function that calls d_file's blah d_file.blah() |
在A的init.py中:
1 2 3 4 5 6 7 8 9 10 11 12 13 | from b.c import c_file from b.d import d_file class Proxy(object): # module proxy pass d_file_proxy = Proxy() # now you need to explicitly list the class(es) exposed by d_file d_file_proxy.blah = d_file.blah # finally, share the proxy with c_file c_file.d_file = d_file_proxy # c_file is now able to call d_file.blah c_file.c_blah() |