Python循环导入?

Python循环导入?,python,import,circular-dependency,Python,Import,Circular Dependency,所以我得到了这个错误 Traceback (most recent call last): File "/Users/alex/dev/runswift/utils/sim2014/simulator.py", line 3, in <module> from world import World File "/Users/alex/dev/runswift/utils/sim2014/world.py", line 2, in

所以我得到了这个错误

Traceback (most recent call last):
  File "/Users/alex/dev/runswift/utils/sim2014/simulator.py", line 3, in <module>
    from world import World
  File "/Users/alex/dev/runswift/utils/sim2014/world.py", line 2, in <module>
    from entities.field import Field
  File "/Users/alex/dev/runswift/utils/sim2014/entities/field.py", line 2, in <module>
    from entities.goal import Goal
  File "/Users/alex/dev/runswift/utils/sim2014/entities/goal.py", line 2, in <module>
    from entities.post import Post
  File "/Users/alex/dev/runswift/utils/sim2014/entities/post.py", line 4, in <module>
    from physics import PostBody
  File "/Users/alex/dev/runswift/utils/sim2014/physics.py", line 21, in <module>
    from entities.post import Post
ImportError: cannot import name Post
回溯(最近一次呼叫最后一次):
文件“/Users/alex/dev/runswift/utils/sim2014/simulator.py”,第3行,在
从世界进口世界
文件“/Users/alex/dev/runswift/utils/sim2014/world.py”,第2行,在
从entities.field导入字段
文件“/Users/alex/dev/runswift/utils/sim2014/entities/field.py”,第2行,在
从entities.goal导入目标
文件“/Users/alex/dev/runswift/utils/sim2014/entities/goal.py”,第2行,在
from entities.post导入post
文件“/Users/alex/dev/runswift/utils/sim2014/entities/post.py”,第4行,在
从物理学导入后体
文件“/Users/alex/dev/runswift/utils/sim2014/physics.py”,第21行,在
from entities.post导入post
ImportError:无法导入姓名栏
你可以看到,我进一步使用了相同的import语句,它可以工作吗?关于循环导入是否有一些不成文的规定?如何进一步使用调用堆栈中的同一类?

当您第一次导入模块(或其成员)时,模块内的代码会像任何其他代码一样按顺序执行;e、 例如,对函数体的处理没有任何不同。
import
与其他命令一样,只是一个命令(赋值、函数调用、
def
class
)。假设您的导入发生在脚本的顶部,那么下面是发生的情况:

  • 当您尝试从
    World
    导入
    World
    时,将执行
    World
    脚本
  • world
    脚本导入
    字段
    ,从而执行
    实体.Field
    脚本
  • 此过程将继续,直到您到达
    实体.post
    脚本,因为您尝试导入
    post
  • entities.post
    脚本导致执行
    physics
    模块,因为它试图导入
    PostBody
  • 最后,
    physics
    尝试从
    实体导入
    Post
    。Post
  • 我不确定
    entities.post
    模块是否存在于内存中,但这并不重要。模块不在内存中,或者模块没有
    Post
    成员,因为它尚未完成定义
    Post
  • 无论哪种方式,都会发生错误,因为不存在要导入的
    Post
因此,它不是“在调用堆栈中进一步工作”。这是错误发生位置的堆栈跟踪,这意味着它在该类中尝试导入
Post
时出错。你不应该使用循环导入。充其量,它的好处可以忽略不计(通常,没有好处),并且它会导致类似这样的问题。它给任何维护它的开发者带来负担,迫使他们在蛋壳上行走以避免打破蛋壳。重构您的模块组织。

我认为,虽然这一点都没有错,但循环导入的影响太大了。如果设置正确,它们可以正常工作

最简单的方法是使用
导入我的\u模块
语法,而不是从我的\u模块导入一些\u对象。前者几乎总是有效的,即使所包含的
myu模块
将我们重新导入。只有在
my_模块
中已经定义了
my_对象
时,后者才起作用,而在循环导入中可能不是这样


针对您的具体情况:尝试更改
实体/post.py
以执行
导入物理
,然后直接参考
物理.PostBody
,而不仅仅是
PostBody
。类似地,将
physics.py
更改为执行
导入实体.post
,然后使用
实体.post.post
,而不仅仅是
post
,对于像我一样从Django来到这个问题的人,您应该知道文档提供了一个解决方案:

“…要引用在另一个应用程序中定义的模型,可以显式指定带有完整应用程序标签的模型。例如,如果上面的制造商模型是在另一个名为production的应用程序中定义的,则需要使用:

class Car(models.Model):
    manufacturer = models.ForeignKey(
        'production.Manufacturer',
        on_delete=models.CASCADE,
)

在解析两个应用程序之间的循环导入依赖关系时,此类参考非常有用。…“

要理解循环依赖关系,您需要记住Python本质上是一种脚本语言。方法外的语句在编译时执行。Import语句的执行与方法调用一样,要理解它们,您应该像方法调用一样考虑它们

执行导入时,发生的情况取决于要导入的文件是否已存在于模块表中。如果是这样,Python将使用符号表中当前的内容。如果没有,Python开始读取模块文件,编译/执行/导入在那里找到的任何内容。是否找到编译时引用的符号,取决于编译器是否已看到或尚未看到它们

假设您有两个源文件:

文件X.py

def X1:
    return "x1"

from Y import Y2

def X2:
    return "x2"
文件Y.py

def Y1:
    return "y1"

from X import X1

def Y2:
    return "y2"
现在假设编译文件X.py。编译器首先定义方法X1,然后点击X.py中的import语句。这会导致编译器暂停编译X.py并开始编译Y.py。此后不久,编译器在Y.py中点击import语句。由于X.py已经在模块表中,Python使用现有的不完整的X.py符号表来满足任何请求的引用。X.py中import语句之前出现的任何符号现在都在符号表中,但后面出现的任何符号都不在符号表中。由于X1现在出现在import语句之前,因此它已成功导入。Python然后继续编译Y.py。在此过程中,它定义了Y2并完成了Y.py的编译。然后继续编译X.py,并在Y.py符号表中找到Y2。编译最终完成,没有错误

如果尝试从th编译Y.py,则会发生非常不同的情况
from X import Y
import X
z = X.Y
#import X   (actual import moved down to avoid circular dependency)
from module import Foo

foo_instance = Foo()
import module.foo

foo_instance = foo.Foo()
def my_func():
    import Foo
    foo_instance = Foo()