在Python循环进口依赖在Python循环进口依赖(Circular import depende

2019-05-06 12:20发布

比方说,我有以下目录结构:

a\
    __init__.py
    b\
        __init__.py
        c\
            __init__.py
            c_file.py
        d\
            __init__.py
            d_file.py

a包的__init__.py ,该c包是进口的。 但c_file.py进口abd

该计划失败,说b当它不存在c_file.py尝试导入abd 。 (它确实不存在的,因为我们是在进口它的中间。)

如何解决这个问题加以解决呢?

Answer 1:

如果依赖于C和C取决于,不是他们实际上是相同的单位呢?

你真的应该考虑为什么你有分裂的A和C到两个包,因为无论你有一些代码,您应该分裂成另一个包(以使它们都依赖于新的包装,而不是对方),或者你应该把它们合并在一个封装中。



Answer 2:

您可能会推迟进口,例如a/__init__.py

def my_function():
    from a.b.c import Blah
    return Blah()

也就是说,推迟进口,直到真正需要它。 不过,我也有我的包定义/用途仔细看,像一个循环依赖指出可能表明一个设计问题。



Answer 3:

我想知道,这几次(通常同时与需要知道对方的机型交易)。 简单的解决办法就是导入整个模块,然后引用你所需要的东西。

因此,而不是做

from models import Student

于一体,并

from models import Classroom

在其他的,只是做

import models

在其中的一个,然后调用models.Classroom当你需要它。



Answer 4:

问题是,从一个目录中运行时,默认情况下只有那些子目录的包作为候选进口可见的,所以你不能导入ABD但是,您可以导入BD因为B的一个子包。

如果你真的想要导入ABD在c/__init__.py ,你可以通过改变系统路径为高于一个目录下即可,改变进口的a/__init__.py是进口ABC

你的a/__init__.py应该是这样的:

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是不存在的。 你能砍的__int__.py在c目录移到sys.path指向顶级目录,然后导入__init__在C内任何模块,以便能够使用完整路径导入ABD我怀疑这是很好的做法进口__init__.py ,但它已经为我的使用情况。



Answer 5:

我建议以下模式。 使用它可以让自动完成和类型提示的正常工作。

cyclic_import_a.py

import playground.cyclic_import_b

class A(object):
    def __init__(self):
        pass

    def print_a(self):
        print('a')

if __name__ == '__main__':
    a = A()
    a.print_a()

    b = playground.cyclic_import_b.B(a)
    b.print_b()

cyclic_import_b.py

import playground.cyclic_import_a

class B(object):
    def __init__(self, a):
        self.a: playground.cyclic_import_a.A = a

    def print_b(self):
        print('b1-----------------')
        self.a.print_a()
        print('b2-----------------')

使用此语法您不能导入A和B级

from playgroud.cyclic_import_a import A
from playground.cyclic_import_b import B

你不能在B类声明参数的类型__ __的init方法,但你可以“投”这样说:

def __init__(self, a):
    self.a: playground.cyclic_import_a.A = a


Answer 6:

另一种方法是使用代理服务器的d_file。

例如,假设您想与C_FILE共享等等类。 因此,d_file包含:

class blah:
    def __init__(self):
        print("blah")

以下是你在c_file.py输入:

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

而在一个的init的.py:

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


文章来源: Circular import dependency in Python