python头文件循环依赖_依赖-Python中的循环导入依赖

依赖-Python中的循环导入依赖

假设我具有以下目录结构:

a\

__init__.py

b\

__init__.py

c\

__init__.py

c_file.py

d\

__init__.py

d_file.py

在b包的c_file.py中,导入了a.b.d包。 但是c_file.py会导入a.b.d。

程序失败,并说当c_file.py尝试导入a.b.d时b不存在(并且它实际上不存在,因为我们正在导入它。)

如何解决这个问题?

6个解决方案

147 votes

您可以推迟导入,例如在a/__init__.py中:

def my_function():

from a.b.c import Blah

return Blah()

也就是说,将导入推迟到真正需要之前。 但是,我还将仔细查看我的程序包定义/用法,因为像所指出的那样循环依赖可能表示设计问题。

Dirk answered 2019-09-30T11:22:10Z

57 votes

如果a取决于c,而c取决于a,那么它们实际上不是同一单位吗?

您应该真正检查一下为什么将a和c拆分为两个包,因为要么您有一些代码应该拆分为另一个包(以使它们都依赖于该新包,而不是彼此依赖),要么应该合并它们 一包

Lasse Vågsæther Karlsen answered 2019-09-30T11:21:37Z

24 votes

我想知道几次(通常是在处理需要彼此了解的模型时)。 简单的解决方案是导入整个模块,然后引用所需的内容。

所以不要做

from models import Student

合而为一

from models import Classroom

在另一种,只是做

import models

在其中之一中,然后在需要时调用model.Classroom。

zachaysan answered 2019-09-30T11:23:00Z

0 votes

问题是,从目录运行时,默认情况下只有作为子目录的软件包才可见为候选导入,因此您不能导入a.b.d。 但是您可以导入b.d. 因为b是a的子包。

如果您确实要在__int__.py中导入a.b.d,则可以通过将系统路径更改为a上方的一个目录,然后将__init__中的导入更改为a.b.c来导入。

您的__int__.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不存在。 您可以修改c目录中的__int__.py以将sys.path指向顶级目录,然后将__init__导入c内的任何模块中,以便能够使用完整路径来导入a.b.d。 我怀疑导入__init__.py是否是一个好习惯,但它已在我的用例中使用。

John Gilmer answered 2019-09-30T11:23:46Z

0 votes

我建议以下模式。 使用它可以使自动完成和键入提示正常工作。

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 __方法中声明参数a的类型,但是可以通过以下方式“投射”它:

def __init__(self, a):

self.a: playground.cyclic_import_a.A = a

RaamEE answered 2019-09-30T11:24:40Z

-3 votes

另一种解决方案是对d_file使用代理。

例如,假设您要与c_file共享blah类。 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()

user474491 answered 2019-09-30T11:25:25Z

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值