ImportError:无法导入名称X.

jse*_*lls 475 python circular-dependency python-import importerror

我有四个不同的文件:main,vector,entity和physics.我不会发布所有代码,只发布导入,因为我认为这就是错误所在.(如果你愿意,我可以发布更多)

主要:

import time
from entity import Ent
from vector import Vect
#the rest just creates an entity and prints the result of movement
Run Code Online (Sandbox Code Playgroud)

实体:

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
Run Code Online (Sandbox Code Playgroud)

向量:

from math import *
class Vect:
    #holds i, j, k, and does vector math
Run Code Online (Sandbox Code Playgroud)

物理:

from entity import Ent
class Physics:
    #physics class gets an entity and does physics calculations on it.
Run Code Online (Sandbox Code Playgroud)

然后我从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
Run Code Online (Sandbox Code Playgroud)

我是Python的新手,但长期以来一直使用C++.我猜这个错误是由于导入实体两次,一次是在main,后来是物理,但我不知道一种解决方法.有人可以帮忙吗?

Tee*_*nen 451

您有循环依赖导入.physics.py从定义entity类之前导入Entphysics尝试导入entity已经初始化的类.physicsentity模块中删除依赖项.

  • 声明"两个类别永远不应该相互依赖"是垃圾.双向(双向)导航在面向对象中非常常见.http://books.google.co.uk/books?id=nHZslSr1gJAC&lpg=PR17&ots=V82ZJRMA1F&dq=OO%20uml%20bidirectional%20navigation&lr&pg=PA42#v=onepage&q=bidirectional&f=false (83认同)
  • @jsells由于你已经"使用了很长时间"的C++,你应该知道两个类永远不应该相互依赖.这在C++中非常重要,即使它不是Python中的第一件事,遵循这条规则仍然是一个非常好的主意.从来没有两个相互认识的课程.如果您需要有关为类创建结构的帮助,请发布其余代码.究竟(在代码方面)的"实体"和"物理"是如何相互联系的?我确信你正在尝试做什么的解决方法. (12认同)
  • @ user2032433这真的取决于你们"彼此认识"的含义.确实,好的设计通常会生成单向依赖树,这通常是最好的方法.但也有例外.C++类当然可以循环引用彼此.(虽然它们不可能由彼此组成.)如果没有前向声明,这是Python中的一个问题,它并不总是有C++解决方案. (7认同)
  • 除了重构代码之外,没有什么可以做的.如果你没有在Ent构造函数定义中引用Physics,则在Ent下面移动mport.如果这样做,添加类似setPhysics的方法以在构造函数后启用导入. (5认同)
  • 状态设计模式(例如)通常使用Context类和State接口实现.State实例传递Context实例,以便它们可以调用setState.这要求国家了解背景,反之亦然.这个经典结构如何"对代码不好"?实际上,这正是我在Python中挣扎的问题,但在我用Java实现State时并没有这个问题. (5认同)
  • 好吧,我知道物理学是导入实体,而实体又导入物理学.但是,我无法在实体中删除对物理的依赖,因为类Ent需要调用它来更新它的位置.我还尝试在文件末尾或构造函数中导入物理,并且只给出NameError:名称'x'未定义. (2认同)

bha*_*ing 130

虽然你绝对应该避免循环依赖,但你可以推迟python中的导入.

例如:

import SomeModule

def someFunction(arg):
    from some.dependency import DependentClass
Run Code Online (Sandbox Code Playgroud)

这(至少在某些情况下)将绕过错误.

  • 循环依赖是最好的规避 (35认同)
  • 基于pep8,将import放入方法内部不是一个好习惯 (3认同)
  • @TomSawyer 我不推荐这样做,但这是一个可以让您摆脱困境的快速解决方案 (3认同)

Dun*_*nes 111

这是循环依赖.它可以在不对代码进行任何结构修改的情况下解决.出现此问题是因为vector您要求entity立即使用,反之亦然.出现此问题的原因是您要求在模块准备就绪之前访问该模块的内容 - 使用from x import y.这与...基本相同

import x
y = x.y
del x
Run Code Online (Sandbox Code Playgroud)

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

a = module() # import a

# rest of module

a.update_contents(real_a)
Run Code Online (Sandbox Code Playgroud)

要使python能够使用循环依赖项,您必须import x仅使用样式.

import x
class cls:
    def __init__(self):
        self.y = x.y
Run Code Online (Sandbox Code Playgroud)

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

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

g10*_*ang 21

使逻辑清晰是非常重要的.出现此问题,因为引用变为死循环.

如果您不想更改逻辑,可以将导致ImportError的一些import语句放到文件的另一个位置,例如end.

a.py

from test.b import b2

def a1():
    print('a1')
    b2()
Run Code Online (Sandbox Code Playgroud)

b.py

from test.a import a1

def b1():
    print('b1')
    a1()

def b2():
    print('b2')

if __name__ == '__main__':
    b1()
Run Code Online (Sandbox Code Playgroud)

您将获得导入错误: ImportError: cannot import name 'a1'

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

a.py

def a1():
    print('a1')
    b2()

from test.b import b2
Run Code Online (Sandbox Code Playgroud)

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

b1
a1
b2
Run Code Online (Sandbox Code Playgroud)


Har*_*y M 19

就我而言,我在 Jupyter 笔记本中工作,这是由于在我在工作文件中定义类/函数时已经缓存了导入。

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


小智 16

问题很明显:名称和模块之间的循环依赖entityphysics

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

看这个例子:

# a.py
import b
def foo():
  pass
b.bar()
Run Code Online (Sandbox Code Playgroud)
# b.py
import a
def bar():
  pass
a.foo()
Run Code Online (Sandbox Code Playgroud)

这将被编译为:

# 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!
Run Code Online (Sandbox Code Playgroud)

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

# a.py
def foo():
  pass
import b
b.bar()
Run Code Online (Sandbox Code Playgroud)
# b.py
def bar():
  pass
import a
a.foo()
Run Code Online (Sandbox Code Playgroud)

这将被编译为:

# 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!
Run Code Online (Sandbox Code Playgroud)


Tom*_*iak 15

正如已经提到的,这是由循环依赖引起的。没有提到的是,当您使用 Python类型模块并且导入一个仅用于注释Types 的类时,您可以使用前向引用

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

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

from my_module import Tree

def func(arg: Tree):
    # code
Run Code Online (Sandbox Code Playgroud)

做:

def func(arg: 'Tree'):
    # code
Run Code Online (Sandbox Code Playgroud)

(注意删除的import语句)


mar*_*gaz 14

我也有这个错误,原因不同......

from my_sub_module import my_function
Run Code Online (Sandbox Code Playgroud)

主脚本有Windows行结尾.my_sub_module有UNIX行结尾.改变他们是相同的修复问题.它们还需要具有相同的字符编码.


小智 10

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

py

from B import b2
def a1():
    print('a1')
    b2()
Run Code Online (Sandbox Code Playgroud)

py

def b1():
   from A import a1
   print('b1')
   a1()

def b2():
   print('b2')
if __name__ == '__main__':
   b1() 
Run Code Online (Sandbox Code Playgroud)


Pau*_*aul 9

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

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

例子:

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

这将失败与ImportError. 只需将您的工作 python 脚本重命名为 1。


Nic*_*ais 7

如果您file1.py从这里导入file2.py并使用它:

if __name__ == '__main__':
    # etc
Run Code Online (Sandbox Code Playgroud)

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

如果你想从进口的东西file1.pyfile2.py,你需要使用此file1.py

if __name__ == 'file1':
    # etc
Run Code Online (Sandbox Code Playgroud)

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


Eva*_*ans 6

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

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

    python ./main.py
    
    Run Code Online (Sandbox Code Playgroud)

    导入错误:无法导入名称 A

  2. 然后你启动:

    python ./modules/a.py
    
    Run Code Online (Sandbox Code Playgroud)

    导入错误:无法导入名称 B

  3. 然后你启动:

    python ./modules/b.py
    
    Run Code Online (Sandbox Code Playgroud)

    导入错误:无法导入名称 C(某些非现有模块或其他错误)


djv*_*jvg 6

也与 OP 没有直接关系,但是在向模块添加新对象后未能重新启动PyCharm Python 控制台也是一种非常令人困惑的好方法ImportError: Cannot import name ...

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


Nic*_*ady 5

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

我收到这个错误

导入错误:无法导入名称 IMPLICIT_WAIT

因为我的变量实际上是IMPLICIT_TIMEOUT.

当我更改导入以使用正确的名称时,我不再收到错误???