【问题标题】:ImportError: Cannot import name XImportError:无法导入名称 X
【发布时间】:2019-03-01 19:29:20
【问题描述】:

我有四个不同的文件,分别命名为:main.pyvector.pyentity.pyphysics.py。我不会发布所有代码,只发布导入,因为我认为这就是错误所在(如果你愿意,我可以发布更多)。

main.py:

import time
from entity import Ent
from vector import Vect
#the rest just creates an entity and prints the result of movement

实体.py:

from vector import Vect
from physics import Physics
class Ent:
    #holds vector information and id
def tick(self, dt):
    #this is where physics changes the velocity and position vectors

vector.py:

from math import *
class Vect:
    #holds i, j, k, and does vector math

physics.py:

from entity import Ent
class Physics:
    #physics class gets an entity and does physics calculations on it.

然后我从main.py 运行,我收到以下错误:

Traceback (most recent call last):
File "main.py", line 2, in <module>
    from entity import Ent
File ".../entity.py", line 5, in <module>
    from physics import Physics
File ".../physics.py", line 2, in <module>
    from entity import Ent
ImportError: cannot import name Ent

我猜测错误是由于两次导入实体造成的,一次在main.py,然后在physics.py,但我不知道解决方法。有人可以帮忙吗?

【问题讨论】:

  • 它们的存储位置和目录的目录结构是什么?
  • 看看这个在 python 中循环导入的答案:stackoverflow.com/questions/7199466/…
  • 一般来说,使用from &lt;module&gt; import &lt;name&gt;from &lt;modlue&gt; import * 并不是一个好的编码习惯。最好在模块命名空间下导入,以防止覆盖同名引用。
  • @jsells 你应该只调用你的类EntityVector 而不是EntVect,没有理由缩短这些名称。是的,使用import vector,然后使用x = vector.Vector(0,0,0)
  • 嘿@Kevin,既然你更了解Java,你对这个2008 article的印象如何,作者的第一句话是指循环依赖是如何“相当普遍的做法”爪哇?

标签: python python-import importerror circular-dependency


【解决方案1】:

您有循环依赖导入。 physics.py 在定义类 Ent 之前从 entity 导入,physics 尝试导入已经初始化的 entity。从entity 模块中移除对physics 的依赖。

【讨论】:

  • 除了重构代码之外,您无能为力。如果您没有在 Ent 构造函数定义中引用 Physics,则将 mport 移动到 Ent 下方。如果这样做,请添加 setPhysics 之类的方法以在构造函数之后启用导入。
  • @jsells 由于您已经使用 C++“很长时间”,您应该知道两个类永远不应该相互依赖。这在 C++ 中非常重要,即使它不是 Python 中的第一名,遵循此规则仍然是一个非常好的主意。永远不会有两个彼此认识的班级。如果您在为您的类创建结构方面需要帮助,请也发布其余代码。 EntityPhysics 究竟是如何(就代码而言)相互关联的?我确定您尝试做的事情有解决方法。
  • @user2032433 这真的取决于你所说的“相互了解”是什么意思。确实,好的设计通常会产生一棵单向依赖树,这通常是最好的方法。但也有例外。 C++ 类当然可以循环引用彼此。 (尽管它们不可能由彼此组成。)如果没有前向声明,这是 Python 中的一个问题,它并不总是有 C++ 解决方案。
  • “两个类永远不应该相互依赖”的说法是垃圾。双向(双向)导航在面向对象中非常常见。 books.google.co.uk/…
  • State 设计模式(例如)通常使用 Context 类和 State 接口来实现。 State 的实例被传递给 Context 实例,以便它们可以调用 setState。这需要状态了解上下文,反之亦然。这个经典结构是如何“不擅长代码”的?实际上,这正是我在 Python 中遇到的问题,但当我在 Java 中实现 State 时不必这样做。
【解决方案2】:

虽然您绝对应该避免循环依赖,但您可以在 python 中延迟导入。

例如:

import SomeModule

def someFunction(arg):
    from some.dependency import DependentClass

这(至少在某些情况下)将规避错误。

【讨论】:

  • 最好规避循环依赖
  • 基于 pep8,将 import 放在方法中并不是好的做法
  • @TomSawyer 为什么?
  • @TomSawyer 我不推荐这个,但它是一个快速的解决方案,可以让你摆脱束缚
【解决方案3】:

这是一个循环依赖。它可以在不对代码进行任何结构修改的情况下解决。出现问题是因为在vector 中,您要求entity 立即可用,反之亦然。这个问题的原因是你要求在模块准备好之前访问它的内容——通过使用from x import y。这与

基本相同
import x
y = x.y
del x

Python 能够检测循环依赖并防止导入的无限循环。基本上所有发生的事情是为模块创建了一个空占位符(即它没有内容)。一旦循环依赖的模块被编译,它就会更新导入的模块。这是这样的。

a = module() # import a

# rest of module

a.update_contents(real_a)

为了使 python 能够处理循环依赖,您必须仅使用 import x 样式。

import x
class cls:
    def __init__(self):
        self.y = x.y

由于您不再引用顶层模块的内容,python 可以编译模块而无需实际访问循环依赖项的内容。顶层是指将在编译期间执行的行,而不是函数的内容(例如y = x.y)。访问模块内容的静态或类变量也会导致问题。

【讨论】:

  • 这个答案很重要,对其他人来说也是一个更通用的解决方案。请注意,如果您要导入本地子模块(即import app.foo.bar),则需要为其命名(即import app.foo.bar as bar
【解决方案4】:

我也遇到了这个错误,原因不同...

from my_sub_module import my_function

主脚本有 Windows 行结尾。 my_sub_module 有 UNIX 行结尾。将它们更改为相同可以解决问题。它们还需要具有相同的字符编码。

【讨论】:

    【解决方案5】:

    逻辑清晰很重要。出现这个问题,是因为引用变成了死循环。

    如果你不想改变逻辑,你可以把一些导致 ImportError 的 import 语句放到文件的其他位置,例如结尾。

    a.py

    from test.b import b2
    
    def a1():
        print('a1')
        b2()
    

    b.py

    from test.a import a1
    
    def b1():
        print('b1')
        a1()
    
    def b2():
        print('b2')
    
    if __name__ == '__main__':
        b1()
    

    您将收到导入错误:ImportError: cannot import name 'a1'

    但是如果我们改变 from test.b import b2 在 A 中的位置,如下所示:

    a.py

    def a1():
        print('a1')
        b2()
    
    from test.b import b2
    

    我们可以得到我们想要的:

    b1
    a1
    b2
    

    【讨论】:

      【解决方案6】:

      不要用你导入的其他模块的名字来命名你当前的 python 脚本

      解决方案:重命名您的工作 python 脚本

      例子:

      1. 你在medicaltorch.py工作
      2. 在该脚本中,您有:from medicaltorch import datasets as mt_datasets 其中medicaltorch 应该是已安装的模块

      ImportError 将失败。只需在 1 中重命名您的工作 python 脚本。

      【讨论】:

      • 谢谢,这解决了我遇到的问题。我使用了 colorama 库并将文件命名为 colorama.py,所以 python 不知道要导入什么。更改文件名有帮助。
      【解决方案7】:

      这里还没有看到这个 - 这非常愚蠢,但请确保您正在导入正确的变量/函数。

      我遇到了这个错误

      ImportError: 无法导入名称 IMPLICIT_WAIT

      因为我的变量实际上是IMPLICIT_TIMEOUT

      当我将导入更改为使用正确的名称时,我不再收到错误?‍♂️

      【讨论】:

      • 我已经准备好杀死一个试图找出from PIL import Pillow 不起作用的人。 ?
      【解决方案8】:

      这是一个循环依赖。 我们可以在需要的地方使用 import 模块或类或函数来解决这个问题。 如果我们使用这种方法,我们可以修复循环依赖

      A.py

      from B import b2
      def a1():
          print('a1')
          b2()
      

      B.py

      def b1():
         from A import a1
         print('b1')
         a1()
      
      def b2():
         print('b2')
      if __name__ == '__main__':
         b1() 
      

      【讨论】:

        【解决方案9】:

        并非专门针对此提问者,但如果您导入的类名与您从中导入的文件中的定义不匹配,则会显示相同的错误。

        【讨论】:

          【解决方案10】:

          跟踪导入错误的一种方法是逐步尝试在每个导入的文件上运行 python 以跟踪错误的文件。

          1. 你会得到类似的东西:

            python ./main.py
            

            ImportError: 无法导入名称 A

          2. 然后你启动:

            python ./modules/a.py
            

            ImportError: 无法导入名称 B

          3. 然后你启动:

            python ./modules/b.py
            

            ImportError: cannot import name C (some NON-Existing module or some other error)

          【讨论】:

            【解决方案11】:

            也与 OP 没有直接关系,但未能重新启动 PyCharm Python 控制台,在将新对象添加到模块后,也是获得非常混乱的好方法ImportError: Cannot import name ...

            令人困惑的部分是 PyCharm 在控制台中自动完成导入,但导入会失败。

            【讨论】:

              【解决方案12】:

              如果您从 file2.py 导入 file1.py 并使用了这个:

              if __name__ == '__main__':
                  # etc
              

              低于file1.py的变量无法导入file2.py,因为__name__不等于__main__

              如果你想从file1.py导入一些东西到file2.py,你需要在file1.py中使用这个:

              if __name__ == 'file1':
                  # etc
              

              如有疑问,请发出assert 声明以确定是否__name__=='__main__'

              【讨论】:

                【解决方案13】:

                如前所述,这是由循环依赖引起的。没有提到的是,当您使用 Python typing 模块并导入一个仅用于注释 Types 的类时,您可以使用 Forward references

                当类型提示包含尚未定义的名称时, 定义可以表示为字符串文字,稍后再解析。

                并删除依赖项(import),例如而不是

                from my_module import Tree
                
                def func(arg: Tree):
                    # code
                

                做:

                def func(arg: 'Tree'):
                    # code
                

                (注意删除的import 语句)

                【讨论】:

                  【解决方案14】:

                  问题很明确:entityphysics 模块中的名称之间存在循环依赖

                  无论导入整个模块还是只导入一个类,都必须加载名称。

                  观看此示例:

                  # a.py
                  import b
                  def foo():
                    pass
                  b.bar()
                  
                  # b.py
                  import a
                  def bar():
                    pass
                  a.foo()
                  

                  这将被编译成:

                  # a.py
                  # import b
                  # b.py
                  # import a # ignored, already importing
                  def bar():
                    pass
                  a.foo()
                  # name a.foo is not defined!!!
                  # import b done!
                  def foo():
                    pass
                  b.bar()
                  # done!
                  

                  稍作改动我们就可以解决这个问题:

                  # a.py
                  def foo():
                    pass
                  import b
                  b.bar()
                  
                  # b.py
                  def bar():
                    pass
                  import a
                  a.foo()
                  

                  这将被编译成:

                  # a.py
                  def foo():
                    pass
                  # import b
                  # b.py
                  def bar():
                    pass
                  # import a # ignored, already importing
                  a.foo()
                  # import b done!
                  b.bar()
                  # done!
                  

                  【讨论】:

                    【解决方案15】:

                    在我的例子中,我在 Jupyter 笔记本中工作,这是因为当我在工作文件中定义类/函数时,导入已经被缓存。

                    我重新启动了 Jupyter 内核,错误消失了。

                    【讨论】:

                      【解决方案16】:

                      就我而言,只是错过了文件名:

                      从 A.B.C 导入 func_a (x)

                      从 A.B.C.D 导入 func_a (O)

                      其中 D 是文件。

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2016-03-31
                        • 2014-10-10
                        • 2014-09-20
                        • 2014-08-28
                        相关资源
                        最近更新 更多