ChatGPT解决这个技术问题 Extra ChatGPT

ImportError:无法导入名称 X

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

主要.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

矢量.py:

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

物理.py:

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

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

回溯(最后一次调用):文件“main.py”,第 2 行,在 中从实体导入 Ent 文件“.../entity.py”,第 5 行,在 中从物理导入物理文件“ .../physics.py",第 2 行,在 中从实体导入 Ent ImportError:无法导入名称 Ent

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

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

A
Arkady

您有循环依赖导入。 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 时不必这样做。
b
bharling

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

例如:

import SomeModule

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

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


最好规避循环依赖
基于 pep8,将 import 放入方法中并不是一个好习惯
@TomSawyer 为什么?
@TomSawyer 我不推荐这个,但它是一个快速的解决方案,可以让你摆脱束缚
@bharling 你能再解释一下吗?这对我来说是一个强有力的解决方案
D
Dunes

这是一个循环依赖。它可以在不对代码进行任何结构修改的情况下解决。出现问题是因为在 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
H
Harry M

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

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


相似的。对于 Google Colab 重新启动运行时并重新运行导入对我有用。
g
g10guang

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

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

一个.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()

您将收到 Import Error: ImportError: cannot import name 'a1'

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

一个.py

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

from test.b import b2

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

b1
a1
b2

A
Ankit Patidar

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

py

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

py

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

def b2():
   print('b2')
if __name__ == '__main__':
   b1() 

m
marengaz

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

from my_sub_module import my_function

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


D
DuniC

问题很明显: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!

T
Tomasz Bartkowiak

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

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

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

from my_module import Tree

def func(arg: Tree):
    # code

做:

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

(注意删除的 import 语句)


P
Paul

试试这个解决方案:重命名你的工作 python 脚本

你不应该用你导入的其他模块的名字来命名你当前的 python 脚本,因为你会得到那个错误。

例子:

你在那个脚本中的 medicaltorch.py 中工作,你有: from medicaltorch import X where medicaltorch 应该是一个单独的安装模块

这将因 ImportError 而失败,因为有 2 件事涉及 medicaltorch

因此,只需将您的工作 python 脚本重命名为 1。


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

如果您从 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__'


T
Tom

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

你会得到类似的东西: python ./main.py ImportError: cannot import name A then you launch: python ./modules/a.py ImportError: cannot import name B then you launch: python ./modules/b.py ImportError: cannot导入名称 C(一些不存在的模块或其他一些错误)


d
djvg

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

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


N
Nick Brady

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

我收到了这个错误

ImportError:无法导入名称 IMPLICIT_WAIT

因为我的变量实际上是 IMPLICIT_TIMEOUT

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


我准备杀了一个试图弄清楚为什么 from PIL import Pillow 不起作用的人。 😠
B
Bennett

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


s
sailfish009

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

从 ABC 进口 func_a (x)

从 ABCD 导入 func_a (O)

其中 D 是文件。