본문 바로가기
Python/Python FAQ

Python 상호 또는 순환 (순환적) 임포트를 사용할 때 어떤 일이 발생합니까?, What happens when using mutual or circular (cyclic) imports?

by 베타코드 2023. 10. 6.
반응형

질문


파이썬에서 두 개의 모듈이 서로 import를 시도하면 어떻게 될까요? 더 일반적으로, 여러 모듈이 순환적으로 import를 시도하면 어떻게 될까요?


자주 발생할 수 있는 문제인 "ImportError: Cannot import name X" 또는 "AttributeError: ... (most likely due to a circular import)"에 대한 자세한 내용과 이러한 import를 피하기 위해 코드를 다시 작성하는 방법에 대한 조언은 여기에서 확인할 수 있습니다. 문제가 발생하는 이유와 방법에 대한 기술적인 세부 사항은 여기에서 확인할 수 있습니다.


답변


만약 bar.py 안에서 import foo를 하고 foo.py 안에서 import bar를 한다면, 잘 작동할 것입니다. 실제로 어떤 것이든 실행되기 전에 두 모듈 모두 완전히 로드되고 서로를 참조할 수 있을 것입니다.

문제는 bar.py 안에서 from foo import abc를 하고 foo.py 안에서 from bar import xyz를 할 때입니다. 왜냐하면 이제 각 모듈은 가져오는 이름이 존재하기 때문에 이미 다른 모듈이 가져와져야 합니다.

Python 2와 Python 3에서 작동하는 순환 참조의 예시

When are Python circular imports fatal? 문서는 위에서 설명한 이유로 인해 순환 참조가 치명적이지 않은 경우의 네 가지 예시를 제공합니다.

모듈 상단; from 없음; Python 2 전용

# lib/foo.py                         # lib/bar.py
import bar                           import foo

def abc():                           def xyz():
    print(bar.xyz.__name__)              print(foo.abc.__name__)

모듈 상단; from 가능; 상대경로 가능; Python 3 전용

# lib/foo.py                         # lib/bar.py
from . import bar                    from . import foo

def abc():                           def xyz():
    print(bar.xyz.__name__)              print(abc.__name__)

모듈 상단; from 없음; 상대경로 없음

# lib/foo.py                         # lib/bar.py
import lib.bar                       import lib.foo

def abc():                           def xyz():
    print(lib.bar.xyz.__name__)          print(lib.foo.abc.__name__)

모듈 하단; 모듈이 아닌 속성을 가져오기; from 가능

# lib/foo.py                         # lib/bar.py
def abc():                           def xyz():
    print(xyz.__name__)                  print(abc.__name__)


from .bar import xyz                 from .foo import abc

함수 상단; from 가능

# lib/foo.py                         # lib/bar.py
def abc():                           def xyz():
    from . import bar                    from . import foo
    print(bar.xyz.__name__)              print(foo.abc.__name__)

추가 예시

위에서 인용한 문서는 별표(*)로 모든 것을 가져오는 경우에 대해 논의하지 않습니다.

반응형

댓글