[python] ImportError : 이름 X를 가져올 수 없습니다

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

실재:

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

벡터:

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

물리학:

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

저는 Python을 처음 접했지만 오랫동안 C ++로 작업했습니다. 나는 오류가 엔티티에서 두 번, 메인에서 한 번, 나중에 물리에서 가져 오기 때문이라고 생각하지만 해결 방법을 모르겠습니다. 누구든지 도울 수 있습니까?



답변

순환 종속 가져 오기가 있습니다. physics.py에서 수입되는 entity클래스가 이전에 Ent정의 및 physics수입에 대한 시도가 entity이미 초기화된다. 모듈 physics에서에 대한 종속성을 제거하십시오 entity.


답변

순환 의존성을 피해야하지만 파이썬에서 가져 오기를 연기 할 수 있습니다.

예를 들면 다음과 같습니다.

import SomeModule

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

이것은 (적어도 일부 경우) 오류를 피할 것입니다.


답변

이것은 순환 종속성입니다. 코드를 구조적으로 수정하지 않고도 해결할 수 있습니다. 에 있기 때문에 문제가 발생합니다 vector당신이 요구하는 그 entity반대의 즉시 사용 가능하게하고, 그 반대도 될 수있다. 이 문제의 원인은 준비하기 전에 모듈의 내용에 액세스하도록 요청하기 때문입니다 from x import y. 이것은 본질적으로

import x
y = x.y
del x

파이썬은 순환 의존성을 감지하고 무한한 수입 루프를 방지 할 수 있습니다. 본질적으로 일어나는 일은 모듈에 대해 빈 자리 표시자가 만들어지는 것입니다 (즉, 내용이 없음). 순환 종속 모듈이 컴파일되면 가져온 모듈을 업데이트합니다. 이것은 이런 식으로 작동합니다.

a = module() # import a

# rest of module

a.update_contents(real_a)

파이썬이 순환 종속성으로 작업 할 수 있으려면 import x스타일 만 사용해야 합니다.

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

더 이상 최상위 레벨에서 모듈의 내용을 참조하지 않기 때문에 Python은 실제로 순환 종속성의 내용에 액세스하지 않고도 모듈을 컴파일 할 수 있습니다. 최상위 레벨은 함수의 내용 (예 :)과 반대로 컴파일 중에 실행될 라인을 의미합니다 y = x.y. 모듈 내용에 액세스하는 정적 또는 클래스 변수도 문제를 일으킬 수 있습니다.


답변

논리를 명확하게하는 것이 매우 중요합니다. 참조가 데드 루프가되기 때문에이 문제가 나타납니다.

논리를 변경하지 않으려면 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'

그러나 다음과 같이 A에서 test.b import b2의 위치를 ​​변경하면 :

a.py

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

from test.b import b2

그리고 우리는 우리가 원하는 것을 얻을 수 있습니다 :

b1
a1
b2


답변

이것은 순환 종속성입니다. 가져 오기 모듈이나 필요한 클래스 또는 함수 를 사용하여이 문제를 해결할 수 있습니다 . 이 방법을 사용하면 순환 종속성을 수정할 수 있습니다

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() 


답변

다른 이유로이 오류가 발생했습니다 …

from my_sub_module import my_function

기본 스크립트에는 Windows 줄 끝이있었습니다. my_sub_module유닉스 줄 끝이 있었다. 그것들을 동일하게 변경하면 문제가 해결되었습니다. 또한 동일한 문자 인코딩이 필요합니다.


답변

이미 언급했듯이 이것은 순환 종속성 에 의해 발생합니다 . 언급되지 않은 것은 파이썬 타이핑 모듈을 사용하고 타입 에 주석을 달기 위해 클래스 만 가져올 때 Forward 참조를 사용할 수 있다는 것입니다 .

형식 힌트에 아직 정의되지 않은 이름이 포함 된 경우 해당 정의는 문자열 리터럴로 표현되어 나중에 확인할 수 있습니다.

의존성을 제거하십시오 ( 가져 오기 )

from my_module import Tree

def func(arg: Tree):
    # code

하다:

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

(제거 된 import진술에 유의 )