programing

파이썬에서 순환 가져오기를 방지하는 방법은 무엇입니까?

showcode 2023. 6. 14. 21:59
반응형

파이썬에서 순환 가져오기를 방지하는 방법은 무엇입니까?

저는 파이썬의 순환 수입 문제가 이전에도 여러 번 제기되었다는 것을 알고 있으며 이러한 논의를 읽은 적이 있습니다.이러한 논의에서 반복적으로 제기되는 의견은 순환 가져오기는 잘못된 설계의 신호이므로 순환 가져오기를 방지하기 위해 코드를 재구성해야 한다는 것입니다.

이런 상황에서 순환 수입을 피하는 방법을 알려주실 수 있나요?저는 두 개의 클래스가 있고 각 클래스에 다른 클래스의 인스턴스를 가져와서 클래스의 인스턴스를 반환하는 생성자(메소드)가 있기를 원합니다.

좀 더 구체적으로 말하면, 한 클래스는 가변적이고 한 클래스는 불변적입니다.해싱, 비교 등을 위해서는 불변의 클래스가 필요합니다.변화무쌍한 계급은 일을 하기 위해서도 필요합니다.이것은 세트 및 고정 세트 또는 리스트 및 튜플과 유사합니다.

두 클래스 정의를 모두 같은 모듈에 넣을 수 있습니다.다른 제안이 있습니까?

장난감의 예로는 목록인 속성을 가진 클래스 A와 튜플인 속성을 가진 클래스 B가 있습니다.그런 다음 클래스 A에는 클래스 B의 인스턴스를 가져다가 클래스 A의 인스턴스를 반환하는 메서드가 있으며, 클래스 B에도 클래스 A의 인스턴스를 가져다가 클래스 B의 인스턴스를 반환하는 메서드가 있습니다.

다음 예제 python 패키지를 생각해 보십시오.a.py그리고.b.py서로 의존:

/package
    __init__.py
    a.py
    b.py

순환 가져오기 문제 유형

순환 가져오기 종속성은 일반적으로 가져오려는 항목과 각 모듈 내에서 사용하는 위치에 따라 두 가지 범주로 나뉩니다(그리고 python 2 또는 3을 사용하는지 여부).

순환 가져오기를 사용하여 모듈을 가져오는 중 오류 발생

순환 가져오기 종속성이 있는 모듈을 가져오기만 하면 가져온 모듈에서 아무것도 참조하지 않는 경우에도 오류가 발생할 수 있습니다.

파이썬에서 모듈을 가져오는 몇 가지 표준 방법이 있습니다.

import package.a           # (1) Absolute import
import package.a as a_mod  # (2) Absolute import bound to different name
from package import a      # (3) Alternate absolute import
import a                   # (4) Implicit relative import (deprecated, python 2 only)
from . import a            # (5) Explicit relative import

는 첫 와 네 안타깝도나순있때을는첫네이번다번옵실작니만션제로동상승합모째째와두는머지게속종성환나▁unfortun▁actually▁raisethe▁depend(▁whenencies▁(▁rest▁allst▁you상다모승th▁only▁the니▁circular안▁work두▁and▁4합▁have작).ImportError또는AttributeError하면 안 됩니다 일반적으로 4번째 구문은 python2에서만 작동하고 다른 타사 모듈과 충돌할 위험이 있기 때문에 사용하면 안 됩니다.그래서 정말로, 오직 첫번째 구문만 작동하는 것이 보장됩니다.

: 파일ImportError그리고.AttributeError문제는 python 2에서만 발생합니다.python 3에서는 가져오기 시스템이 다시 작성되었으며 4를 제외한 모든 가져오기 문이 순환 종속성과 함께 작동합니다.코드를 는 데 도움이 될 수 , 20을 .

절대 가져오기

위의 첫 번째 가져오기 구문을 사용합니다.이 방법의 단점은 큰 패키지의 경우 가져오기 이름이 매우 길어질 수 있다는 것입니다.

a.py

import package.b

b.py

import package.a

나중으로 가져오기 연기

저는 이 방법이 많은 패키지에 사용되는 것을 보았지만, 여전히 저에게는 진부하게 느껴지고, 저는 모듈의 상단을 보고 모든 종속성을 볼 수 없다는 것이 싫습니다. 저는 모든 기능을 검색해야 합니다.

a.py

def func():
    from package import b

b.py

def func():
    from package import a

모든 가져오기를 중앙 모듈에 저장

이 방법도 작동하지만 모든 패키지 및 하위 모듈 호출이 매우 길어지는 첫 번째 방법과 동일한 문제가 있습니다.그것은 또한 두 가지 주요한 결함을 가지고 있습니다. 그것은 모든 서브모듈들을 가져오도록 강요합니다. 비록 여러분이 한 두 개만 사용하고 있지만, 여전히 서브모듈들 중 어떤 것도 볼 수 없고 상단에 있는 의존성을 빠르게 볼 수 없습니다. 여러분은 기능들을 살펴봐야 합니다.

__init__.py

from . import a
from . import b

a.py

import package

def func():
    package.b.some_object()

b.py

import package

def func():
    package.a.some_object()

순환 종속성이 있는 가져온 개체를 사용하는 중 오류 발생

순환 가져오기 종속성을 가진 모듈을 가져올 수는 있지만 모듈에 정의된 개체를 가져올 수도 없고 가져올 모듈의 최상위 수준에 있는 해당 모듈을 참조할 수도 없습니다.그러나 가져올 실행되지 않는 함수 및 코드 블록 내부에서 가져온 모듈을 사용할 수 있습니다.

예를 들어, 다음과 같이 작동합니다.

포장[포장]파이의

import package.b

def func_a():
    return "a"

꾸러미/b파이의

import package.a

def func_b():
    # Notice how package.a is only referenced *inside* a function
    # and not the top level of the module.
    return package.a.func_a() + "b"

하지만 이것은 안 될 것입니다.

포장[포장]파이의

import package.b

class A(object):
    pass

꾸러미/b파이의

import package.a

# package.a is referenced at the top level of the module
class B(package.a.A):
    pass

당신은 예외가 될 것입니다.

특성 오류: 모듈 'package'에 특성 'a'가 없습니다.

일반적으로 순환 종속성의 대부분의 유효한 경우 코드를 리팩터링하거나 재구성하여 이러한 오류를 방지하고 코드 블록 내에서 모듈 참조를 이동할 수 있습니다.

모듈만 가져오십시오. 모듈에서 가져오지 마십시오.

고려하다a.py:

import b

class A:
    def bar(self):
        return b.B()

그리고.b.py:

import a

class B:
    def bar(self):
        return a.A()

이것은 완벽하게 잘 작동합니다.

우리는 더 나은 읽기와 더 짧은 액세스 문자열을 위해 절대 가져오기와 기능의 조합을 수행합니다.

  • 장점:순수 절대 가져오기에 비해 짧은 액세스 문자열
  • 단점: 추가 기능 호출로 인한 오버헤드가 조금 더 높습니다.

주요/하위/a파이의

import main.sub.b
b_mod = lambda: main.sub.b

class A():
    def __init__(self):
        print('in class "A":', b_mod().B.__name__)

주요/하위/b파이의

import main.sub.a
a_mod = lambda: main.sub.a

class B():
    def __init__(self):
        print('in class "B":', a_mod().A.__name__)

언급URL : https://stackoverflow.com/questions/7336802/how-to-avoid-circular-imports-in-python

반응형