>  기사  >  백엔드 개발  >  Python에서 순환 가져오기를 수정하는 다양한 방법

Python에서 순환 가져오기를 수정하는 다양한 방법

Linda Hamilton
Linda Hamilton원래의
2024-11-05 02:21:01727검색

Python에서 순환 가져오기를 접해본 적이 있나요? 글쎄요, 디자인이나 구조에 문제가 있음을 나타내는 매우 일반적인 코드 냄새입니다.

순환 가져오기 예시

순환 가져오기는 어떻게 발생하나요? 이 가져오기 오류는 일반적으로 서로 의존하는 두 개 이상의 모듈이 완전히 초기화되기 전에 가져오려고 할 때 발생합니다.

module_1.py와 module_2.py라는 두 개의 모듈이 있다고 가정해 보겠습니다.

# module_1.py
from module_2 import ModY
class ModX:
    mody_obj = ModY()
# module_2.py
from module_1 import ModX
class ModY:
    modx_obj = ModX()

위 코드 조각에서 module_1과 module_2는 모두 서로 종속되어 있습니다.

mody_1의 mody_obj 초기화는 module_2에 따라 달라지며 module_2의 modx_obj 초기화는 module_1에 따라 다릅니다.

이것을 순환 종속성이라고 부릅니다. 두 모듈이 서로 로드를 시도하는 동안 가져오기 루프에 갇히게 됩니다.

module_1.py를 실행하면 다음과 같은 트레이스백을 얻게 됩니다.

Traceback (most recent call last):
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
  File "module_2.py", line 1, in <module>
    from module_1 import ModX
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
ImportError: cannot import name 'ModY' from partially initialized module 'module_2' (most likely due to a circular import)

이 오류는 순환 가져오기 상황을 설명합니다. 프로그램이 module_2에서 ModY를 가져오려고 시도했을 때 module_2가 완전히 초기화되지 않았습니다(modX1에서 ModX를 가져오려고 시도하는 다른 가져오기 문으로 인해).

Python에서 순환 가져오기를 수정하는 방법은 무엇인가요? Python에서 순환 가져오기를 제거하는 방법에는 여러 가지가 있습니다.

Python에서 순환 가져오기 수정

코드를 공통 파일로 이동

가져오기 오류를 방지하기 위해 코드를 공통 파일로 이동한 다음 해당 파일에서 모듈을 가져올 수 있습니다.

# main.py ----> common file
class ModX:
    pass

class ModY:
    pass

위 코드 조각에서는 ModX 및 ModY 클래스를 공통 파일(main.py)로 이동했습니다.

# module_1.py
from main import ModY

class Mod_X:
    mody_obj = ModY()
# module_2.py
from main import ModX

class Mod_Y:
    modx_obj = ModX()

이제 module_1과 module_2는 순환 가져오기 상황을 수정하는 main에서 클래스를 가져옵니다.

이 접근 방식에는 문제가 있습니다. 때로는 코드베이스가 너무 커서 코드를 다른 파일로 옮기는 것이 위험해질 수 있습니다.

가져오기를 모듈 끝으로 이동

모듈 끝에서 import 문을 이동할 수 있습니다. 이렇게 하면 다른 모듈을 가져오기 전에 모듈을 완전히 초기화할 시간이 주어집니다.

# module_1.py
class ModX:
   pass

from module_2 import ModY

class Mod_X:
   mody_obj = ModY()
# module_2.py
class ModY:
   pass

from module_1 import ModX

클래스/함수 범위 내에서 모듈 가져오기

클래스 또는 함수 범위 내에서 모듈을 가져오면 순환 가져오기를 피할 수 있습니다. 이를 통해 클래스나 함수가 호출될 때만 모듈을 가져올 수 있습니다. 메모리 사용을 최소화하려는 경우에 적합합니다.

# module_1.py
class ModX:
  pass

class Mod_X:
   from module_2 import ModY
   mody_obj = ModY()
# module_2.py
class ModY:
   pass

class Mod_Y:
   from module_1 import ModX
   modx_obj = ModX()

mod_1과 module_2의 Mod_X 및 Mod_Y 클래스 범위 내에서 import 문을 각각 이동했습니다.

module_1 또는 module_2를 실행하면 순환 가져오기 오류가 발생하지 않습니다. 하지만 이 접근 방식을 사용하면 클래스 범위 내에서만 클래스에 액세스할 수 있으므로 가져오기를 전역적으로 활용할 수 없습니다.

모듈 이름/별명 사용

모듈 이름이나 이와 같은 별칭을 사용하면 문제가 해결됩니다. 이를 통해 런타임까지 순환 종속성을 연기하여 두 모듈 모두 완전히 로드할 수 있습니다.

# module_1.py
from module_2 import ModY
class ModX:
    mody_obj = ModY()
# module_2.py
from module_1 import ModX
class ModY:
    modx_obj = ModX()

importlib 라이브러리 사용

importlib 라이브러리를 사용하여 모듈을 동적으로 가져올 수도 있습니다.

Traceback (most recent call last):
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
  File "module_2.py", line 1, in <module>
    from module_1 import ModX
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
ImportError: cannot import name 'ModY' from partially initialized module 'module_2' (most likely due to a circular import)
# main.py ----> common file
class ModX:
    pass

class ModY:
    pass

Python 패키지의 순환 가져오기

일반적으로 순환 수입 동일 패키지 내의 모듈에서 가져옵니다. 복잡한 프로젝트에서는 패키지 내에 패키지가 포함되어 디렉토리 구조도 복잡합니다.

이러한 패키지와 하위 패키지에는 모듈에 더 쉽게 액세스할 수 있도록 __init__.py 파일이 포함되어 있습니다. 여기서 의도하지 않게 모듈 간에 순환 종속성이 발생하는 경우가 있습니다.

다음과 같은 디렉토리 구조를 가지고 있습니다.

# module_1.py
from main import ModY

class Mod_X:
    mody_obj = ModY()

mainpkg 패키지와 main.py 파일이 있습니다. mainpkg에는 modpkg_x와 modpkg_y라는 두 개의 하위 패키지가 있습니다.

modpkg_x 및 modpkg_y 내의 각 Python 파일은 다음과 같습니다.

mainpkg/modpkg_x/__init__.py

# module_2.py
from main import ModX

class Mod_Y:
    modx_obj = ModX()

이 파일은 module_1과 module_1_1에서 두 클래스(ModX 및 ModA)를 모두 가져옵니다.

mainpkg/modpkg_x/module_1.py

# module_1.py
class ModX:
   pass

from module_2 import ModY

class Mod_X:
   mody_obj = ModY()

module_1은 module_2에서 ModY 클래스를 가져옵니다.

mainpkg/modpkg_x/module_1_1.py

# module_2.py
class ModY:
   pass

from module_1 import ModX

module_1_1은 아무것도 가져오지 않습니다. 어떤 모듈에도 종속되지 않습니다.

mainpkg/modpkg_y/__init__.py

# module_1.py
class ModX:
  pass

class Mod_X:
   from module_2 import ModY
   mody_obj = ModY()

이 파일은 module_2에서 ModY 클래스를 가져옵니다.

mainpkg/modpkg_y/module_2.py

# module_2.py
class ModY:
   pass

class Mod_Y:
   from module_1 import ModX
   modx_obj = ModX()

module_2는 module_1_1에서 ModA 클래스를 가져옵니다.

main.py 파일에는 다음 코드가 있습니다.

root_dir/main.py

# module_1.py
import module_2 as m2

class ModX:
    def __init__(self):
        self.mody_obj = m2.ModY()

기본 파일은 module_2에서 ModY 클래스를 가져옵니다. 이 파일은 module_2에 종속됩니다.

여기서 가져오기 주기를 시각화하면 modpkg_x 및 modpkg_y 내의 __init__.py 파일을 무시하고 다음과 같이 보일 것입니다.

Different Ways to Fix Circular Imports in Python

메인 파일이 module_2에 종속되고, module_1도 module_2에 종속되고, module_2는 module_1_1에 종속되는 것을 볼 수 있습니다. 수입주기가 없습니다.

하지만 모듈은 __init__.py 파일에 의존하므로 __init__.py 파일이 먼저 초기화되고 모듈을 다시 가져옵니다.

Different Ways to Fix Circular Imports in Python

현재 수입 주기는 이렇습니다.

Different Ways to Fix Circular Imports in Python

이로 인해 module_1_1은 가짜 종속성인 module_1에 종속됩니다.

이 경우 하위 패키지 __init__.py 파일을 비우고 별도의 __init__.py 파일을 사용하면 패키지 수준에서 가져오기를 중앙 집중화하여 도움이 될 수 있습니다.

# module_1.py
from module_2 import ModY
class ModX:
    mody_obj = ModY()

이 구조에서는 mainpkg 내에 또 다른 하위 패키지 subpkg를 추가했습니다.

mainpkg/subpkg/__init__.py

# module_2.py
from module_1 import ModX
class ModY:
    modx_obj = ModX()

이렇게 하면 내부 모듈을 단일 소스에서 가져올 수 있어 교차 가져오기의 필요성이 줄어듭니다.

이제 main.py 파일 내에서 import 문을 업데이트할 수 있습니다.

root_dir/main.py

Traceback (most recent call last):
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
  File "module_2.py", line 1, in <module>
    from module_1 import ModX
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
ImportError: cannot import name 'ModY' from partially initialized module 'module_2' (most likely due to a circular import)

이는 동일한 패키지 내 모듈 간의 순환 종속성 문제를 해결합니다.

결론

Python의 순환 종속성 또는 가져오기는 코드의 심각한 재구성 및 리팩토링을 나타내는 코드 냄새입니다.

Python에서 순환 종속성을 피하기 위해 위에서 언급한 방법 중 하나를 시도해 볼 수 있습니다.


?이 기사가 마음에 든다면 관심을 가질 만한 다른 기사

✅예제를 사용한 Flask의 템플릿 상속

✅예제를 통한 exec()와 eval()의 차이점

✅파이썬에서 전역 키워드 사용 이해

✅Python 유형 힌트: 함수, 반환 값, 변수

✅함수 정의에 슬래시와 별표를 사용하는 이유

✅학습률은 ML 및 DL 모델에 어떤 영향을 미치나요?


지금은 이게 다입니다.

계속 코딩하세요✌✌.

위 내용은 Python에서 순환 가져오기를 수정하는 다양한 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.