ImportError:无法导入名称 X
Posted
技术标签:
【中文标题】ImportError:无法导入名称 X【英文标题】:ImportError: Cannot import name X 【发布时间】:2012-03-04 09:12:57 【问题描述】:我有四个不同的文件,分别命名为:main.py
、vector.py
、entity.py
和 physics.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 中循环导入的答案:***.com/questions/7199466/… 一般来说,使用from <module> import <name>
或from <modlue> import *
并不是好的编码习惯。最好在模块命名空间下导入,以防止覆盖同名引用。
@jsells 你应该只调用你的类Entity
和Vector
而不是Ent
和Vect
,没有理由缩短这些名称。是的,使用import vector
,然后使用x = vector.Vector(0,0,0)
。
嘿@Kevin,既然你更了解Java,你对这个2008 article的印象如何,作者的第一句话是指循环依赖是如何“相当普遍的做法”爪哇?
【参考方案1】:
您有循环依赖导入。 physics.py
在定义类 Ent
之前从 entity
导入,physics
尝试导入已经初始化的 entity
。从entity
模块中移除对physics
的依赖。
【讨论】:
除了重构代码之外,您无能为力。如果您没有在 Ent 构造函数定义中引用 Physics,则将 mport 移动到 Ent 下方。如果这样做,请添加 setPhysics 之类的方法以在构造函数之后启用导入。 @jsells 由于您使用 C++ 已经“很长时间”,您应该知道两个类永远不应该相互依赖。这在 C++ 中非常重要,即使它不是 Python 中的第一名,遵循此规则仍然是一个非常好的主意。永远不会有两个彼此认识的班级。如果您在为您的类创建结构方面需要帮助,请也发布其余代码。Entity
和 Physics
究竟是如何(就代码而言)相互关联的?我确定您尝试做的事情有解决方法。
@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】:
逻辑清晰很重要。出现这个问题,是因为引用变成了死循环。
如果你不想改变逻辑,你可以把一些导致 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
【讨论】:
【参考方案5】:这是一个循环依赖。 我们可以在需要的地方使用 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()
【讨论】:
【参考方案6】:在我的例子中,我在 Jupyter 笔记本中工作,这是因为当我在工作文件中定义类/函数时,导入已经被缓存。
我重新启动了 Jupyter 内核,错误消失了。
【讨论】:
【参考方案7】:我也遇到了这个错误,原因不同...
from my_sub_module import my_function
主脚本有 Windows 行结尾。 my_sub_module
有 UNIX 行结尾。将它们更改为相同可以解决问题。它们还需要具有相同的字符编码。
【讨论】:
【参考方案8】:问题很明确:entity
和 physics
模块中的名称之间存在循环依赖。
无论是导入整个模块还是只导入一个类,都必须加载名称。
观看此示例:
# 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!
【讨论】:
【参考方案9】:如前所述,这是由循环依赖引起的。没有提到的是,当您使用 Python typing 模块并导入一个仅用于注释 Types 的类时,您可以使用 Forward references:
当类型提示包含尚未定义的名称时, 定义可以表示为字符串文字,稍后再解析。
并删除依赖项(import),例如而不是
from my_module import Tree
def func(arg: Tree):
# code
做:
def func(arg: 'Tree'):
# code
(注意删除的import
语句)
【讨论】:
【参考方案10】:试试这个解决方案:重命名你的工作 python 脚本
你应该不用你导入的其他模块的名字来命名你当前的python脚本,因为你会得到那个错误。
例子:
-
你在
medicaltorch.py
工作
在该脚本中,您有:from medicaltorch import X
其中medicaltorch
应该是单独安装的模块
ImportError
将失败,因为有两件事引用了medicaltorch
所以,只需在 1 中重命名您的工作 python 脚本。
【讨论】:
谢谢,这解决了我遇到的问题。我使用了 colorama 库并将文件命名为 colorama.py,所以 python 不知道要导入什么。更改文件名有帮助。【参考方案11】:如果您从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__'
【讨论】:
【参考方案12】:跟踪导入错误的一种方法是逐步尝试在每个导入的文件上运行 python 以跟踪错误的文件。
你会得到类似的东西:
python ./main.py
ImportError: 无法导入名称 A
然后你启动:
python ./modules/a.py
ImportError: 无法导入名称 B
然后你启动:
python ./modules/b.py
ImportError: cannot import name C (some NON-Existing module or some other error)
【讨论】:
【参考方案13】:也与 OP 没有直接关系,但未能重新启动 PyCharm Python 控制台,在将新对象添加到模块后,也是获得非常混乱的好方法ImportError: Cannot import name ...
令人困惑的部分是 PyCharm 会在控制台中自动完成导入,但导入会失败。
【讨论】:
【参考方案14】:这里还没有看到这个 - 这非常愚蠢,但请确保您正在导入正确的变量/函数。
我遇到了这个错误
ImportError: 无法导入名称 IMPLICIT_WAIT
因为我的变量实际上是IMPLICIT_TIMEOUT
。
当我将导入更改为使用正确的名称时,我不再收到错误?♂️
【讨论】:
我已经准备好杀死一个试图找出from PIL import Pillow
不起作用的人。 ?【参考方案15】:
并非专门针对此提问者,但如果您导入的类名与您从中导入的文件中的定义不匹配,则会显示相同的错误。
【讨论】:
【参考方案16】:就我而言,只是错过了文件名:
从 A.B.C 导入 func_a (x)
从 A.B.C.D 导入 func_a (O)
其中 D 是文件。
【讨论】:
以上是关于ImportError:无法导入名称 X的主要内容,如果未能解决你的问题,请参考以下文章
ImportError:无法导入名称“AFAVSignature”
ImportError:无法导入名称“评估”(来自意外导入评估)
Django 'ImportError: 无法导入名称 url'