[python] 파이썬에서 순환 (또는 순환) 가져 오기

두 모듈이 서로 가져 오면 어떻게됩니까?

문제를 일반화하기 위해 파이썬에서 주기적 가져 오기는 어떻습니까?



답변

작년 에 comp.lang.python 에서 이것에 대해 정말 좋은 토론이 있었습니다. 그것은 당신의 질문에 아주 철저하게 대답합니다.

수입품은 정말 간단합니다. 다음을 기억하십시오.

‘import’및 ‘from xxx import yyy’는 실행 문입니다. 실행중인 프로그램이 해당 라인에 도달하면 실행됩니다.

모듈이 sys.modules에 없으면 가져 오기는 sys.modules에 새 모듈 항목을 작성한 다음 모듈에서 코드를 실행합니다. 실행이 완료 될 때까지 호출 모듈로 제어를 되 돌리지 않습니다.

sys.modules에 모듈이 있으면 가져 오기는 실행이 완료되었는지 여부에 관계없이 해당 모듈을 반환합니다. 순환 가져 오기가 부분적으로 비어있는 모듈을 리턴 할 수있는 이유입니다.

마지막으로, 실행 스크립트는 __main__이라는 모듈에서 실행되며 자체 이름으로 스크립트를 가져 오면 __main__과 관련이없는 새 모듈이 생성됩니다.

그 많은 것을 함께 가져 가면 모듈을 가져올 때 놀랄 일이 없습니다.


답변

import foo내부 barimport bar내부 를 수행 foo하면 제대로 작동합니다. 실제로 모든 것이 실행될 때까지 두 모듈이 완전히로드되고 서로 참조됩니다.

대신 당신이 할 때 문제는 from foo import abcfrom bar import xyz. 이제 각 모듈에서 다른 모듈을 가져와야합니다 (가져 오기 이름이 존재하도록).


답변

주기적 가져 오기는 종료되지만 모듈 초기화 중에 주기적으로 가져온 모듈을 사용하지 않도록주의해야합니다.

다음 파일을 고려하십시오.

a.py :

print "a in"
import sys
print "b imported: %s" % ("b" in sys.modules, )
import b
print "a out"

b.py :

print "b in"
import a
print "b out"
x = 3

a.py를 실행하면 다음과 같은 결과가 나타납니다.

$ python a.py
a in
b imported: False
b in
a in
b imported: True
a out
b out
a out

b.py의 두 번째 가져 오기 (두 번째 a in)에서 Python 인터프리터는 가져 오지 않습니다.b 모듈 dict에 이미 존재하므로 다시 .

액세스하려고하면 b.x에서 a모듈을 초기화하는 동안, 당신은 얻을 것이다AttributeError .

다음 줄을 추가하십시오 a.py.

print b.x

그런 다음 출력은 다음과 같습니다.

$ python a.py
a in
b imported: False
b in
a in
b imported: True
a out
Traceback (most recent call last):
  File "a.py", line 4, in <module>
    import b
  File "/home/shlomme/tmp/x/b.py", line 2, in <module>
    import a
 File "/home/shlomme/tmp/x/a.py", line 7, in <module>
    print b.x
AttributeError: 'module' object has no attribute 'x'

가져 오기시 모듈이 실행되고 b.x액세스 x = 3될 때 행 이 아직 실행되지 않았기 때문에이 문제는 이후에만 발생 b out합니다.


답변

다른 답변에서 설명 하듯 이이 패턴은 파이썬에서 허용됩니다.

def dostuff(self):
     from foo import bar
     ...

다른 모듈에서 파일을 가져올 때 import 문이 실행되지 않습니다. 논리적 순환 종속성이있는 경우에만 실패합니다.

대부분의 순환 가져 오기는 실제로 논리적 순환 가져 오기가 아니라 오히려 ImportError오류를 발생시킵니다.import() 호출 될 때 전체 파일의 최상위 문을 평가 .

이들은 ImportErrors당신이 적극적으로 정상에 당신의 수입을 원하는 경우 거의 항상 피할 수 있습니다 :

이 순환 수입을 고려하십시오.

앱 A

# profiles/serializers.py

from images.serializers import SimplifiedImageSerializer

class SimplifiedProfileSerializer(serializers.Serializer):
    name = serializers.CharField()

class ProfileSerializer(SimplifiedProfileSerializer):
    recent_images = SimplifiedImageSerializer(many=True)

앱 B

# images/serializers.py

from profiles.serializers import SimplifiedProfileSerializer

class SimplifiedImageSerializer(serializers.Serializer):
    title = serializers.CharField()

class ImageSerializer(SimplifiedImageSerializer):
    profile = SimplifiedProfileSerializer()

David Beazleys의 뛰어난 대화 모듈 및 패키지 : Live and Let Die! -PyCon 2015 ,, 1:54:00python에서 순환 수입을 처리하는 방법은 다음과 같습니다.

try:
    from images.serializers import SimplifiedImageSerializer
except ImportError:
    import sys
    SimplifiedImageSerializer = sys.modules[__package__ + '.SimplifiedImageSerializer']

가져 오려고 SimplifiedImageSerializer하면ImportError 발생합니다 이미 수입되기 때문에, 그것은 importcache에서 그것을 가져옵니다.

추신 : David Beazley의 목소리로이 글 전체를 읽어야합니다.


답변

나는 여기를 쳤다는 예를 얻었다!

foo.py

import bar

class gX(object):
    g = 10

bar.py

from foo import gX

o = gX()

main.py

import foo
import bar

print "all done"

명령 행에서 : $ python main.py

Traceback (most recent call last):
  File "m.py", line 1, in <module>
    import foo
  File "/home/xolve/foo.py", line 1, in <module>
    import bar
  File "/home/xolve/bar.py", line 1, in <module>
    from foo import gX
ImportError: cannot import name gX


답변

모듈 a.py :

import b
print("This is from module a")

모듈 b.py

import a
print("This is from module b")

“모듈 a”를 실행하면 다음이 출력됩니다.

>>>
'This is from module a'
'This is from module b'
'This is from module a'
>>> 

순환 가져 오기로 인해 무한을 출력 해야하는 동안이 3 줄을 출력합니다. “모듈 a”를 실행하는 동안 한 줄씩 수행되는 작업은 다음과 같습니다.

  1. 첫 번째 줄은 import b입니다. 모듈 b를 방문합니다
  2. 모듈 b의 첫 번째 줄은 import a입니다. 모듈 A를 방문합니다
  3. 모듈 a의 첫 번째 줄은 import b그러나이 줄은 더 이상 다시 실행되지 않습니다 . 파이썬의 모든 파일은 가져 오기 줄을 한 번만 실행하기 때문에 언제 어디서 실행되는지는 중요하지 않습니다. 다음 행으로 넘어 가서 인쇄 "This is from module a"합니다.
  4. 모듈 b에서 전체 모듈 a를 방문한 후에도 여전히 모듈 b에 있습니다. 다음 줄이 인쇄됩니다"This is from module b"
  5. 모듈 b 라인이 완전히 실행됩니다. 모듈 b를 시작한 모듈 a로 돌아갑니다.
  6. 가져 오기 b 행이 이미 실행되었으며 다시 실행되지 않습니다. 다음 줄이 인쇄 "This is from module a"되고 프로그램이 완료됩니다.

답변

나는 pythoneer의 대답에 전적으로 동의합니다. 그러나 순환 가져 오기에 결함이 있고 단위 테스트를 추가하려고 할 때 문제가 발생하는 일부 코드를 발견했습니다. 모든 것을 변경하지 않고 빠르게 패치하려면 동적 가져 오기를 수행하여 문제를 해결할 수 있습니다.

# Hack to import something without circular import issue
def load_module(name):
    """Load module using imp.find_module"""
    names = name.split(".")
    path = None
    for name in names:
        f, path, info = imp.find_module(name, path)
        path = [path]
    return imp.load_module(name, f, path[0], info)
constants = load_module("app.constants")

다시 말하지만 이것은 영구적 수정은 아니지만 너무 많은 코드를 변경하지 않고 가져 오기 오류를 수정하려는 사람에게 도움이 될 수 있습니다.

건배!