programing

상호 또는 순환(순환) 가져오기를 사용하면 어떻게 됩니까?

jooyons 2023. 4. 20. 21:13
반응형

상호 또는 순환(순환) 가져오기를 사용하면 어떻게 됩니까?

이 Python을 ?import서로?보다 일반적으로는 여러 모듈이 다음을 시도하면 어떻게 됩니까?import★★★★★★★★★★★★★★★★★★?


자세한 내용은 "ImportError: Cannot import name X" 또는 "AttributeError: ..."(순환 Import로 인해 발생할 있음)를 참조하십시오.발생할 수 있는 일반적인 문제에 대한 설명 및 이러한 Import를 피하기 위한 코드 재작성 방법에 대한 조언.순환 Import가 콜스택에서 위쪽에서 기능하는 것처럼 보이지만 ImportError가 더 아래쪽에서 발생하는 이유는 무엇입니까?를 참조하십시오.문제의 발생 원인과 발생 방법에 대한 자세한 내용은 를 참조하십시오.

하면.import foo (비밀(이행)bar.py 및 )의 개요import bar (비밀(이행)foo.py정상적으로 동작합니다.어떤 것이 실제로 실행될 때까지 두 모듈은 완전히 로딩되어 서로 참조할 수 있습니다.

는 ' 때'를 할 때 입니다.from foo import abc (비밀(이행)bar.py 및 )의 개요from bar import xyz (inside (비활성화)foo.py) 이제 각 모듈은 이미 수입될 수 있도록 다른 모듈이 필요합니다.각 모듈을 Import하기 전에 다른 모듈을 Import(Import하는 이름이 존재하도록)해야 하기 때문입니다.

작년에 comp.lang.python에서 정말 좋은 토론이 있었어요.당신의 질문에 아주 잘 대답해주네요.

수입은 정말 간단하다.다음 사항에 주의해 주십시오.

'import' 및 'from xxx import yyy'는 실행 가능한 문입니다.실행 중인 프로그램이 해당 회선에 도달하면 실행됩니다.

모듈이 sys.modules에 없는 경우 Import에 의해 sys.modules에 새로운 모듈엔트리가 생성되어 모듈의 코드가 실행됩니다.실행이 완료될 때까지 콜링 모듈로 제어가 반환되지 않습니다.

모듈이 sys.modules에 존재하는 경우 Import는 단순히 실행 완료 여부에 관계없이 해당 모듈을 반환합니다.그렇기 때문에 주기적인 Import는 부분적으로 비어 있는 것처럼 보이는 모듈을 반환할 수 있습니다.

마지막으로 실행 중인 스크립트는 __main__라는 이름의 모듈에서 실행되며 스크립트를 자체 이름으로 Import하면 __main_과(와) 관련이 없는 새로운 모듈이 생성됩니다.

모듈을 Import 할 때 놀라지 않도록 이 제품들을 함께 보관하십시오.

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

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

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의 두 번째 가져오기( b.py 의)의 두 번째 가져오기a in), the Python interpreter does not import Python 인터프리터는 Import하지 않습니다.b again, because it already exists in the module dict.module dict에 이미 존재하기 때문입니다.

속 도 하 if면 you to access?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.

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

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

그러면 다른 모듈에 의해 파일이 Import될 때 Import 문이 실행되지 않습니다.논리적 순환 종속성이 있는 경우에만 실패합니다.

의 순환 를 올립니다.ImportError 「」, 「」의 에러import()는 호출 시 파일 전체의 최상위 스테이트먼트를 평가합니다.

Import를 확실히 선두에 두고 싶은 경우는, 거의 항상 이러한 문제를 회피할 수 있습니다.

다음 순환 가져오기를 고려하십시오.

앱 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 Beazley의 훌륭한 토크 모듈패키지: Live and Let Die! - PyCon 2015,1:54:00비단뱀의 python 서를를를 Import 。

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

은 Import를 합니다.SimplifiedImageSerializer, 「」의 경우는,ImportError수입하다

추신: 이 글 전체를 데이비드 비즐리의 목소리로 읽어야 합니다.

놀랍게도, 타입 힌트에 의한 주기적인 수입에 대해서는 아직 아무도 언급하지 않았습니다.
타입 힌트의 결과로서만 주기적인 Import가 있는 경우, 그것들을 깔끔하게 회피할 수 있습니다.

main.py하다

from src.exceptions import SpecificException

class Foo:
    def __init__(self, attrib: int):
        self.attrib = attrib

raise SpecificException(Foo(5))

클래스 「」는, 「」입니다.exceptions.py:

from src.main import Foo

class SpecificException(Exception):
    def __init__(self, cause: Foo):
        self.cause = cause

    def __str__(self):
        return f'Expected 3 but got {self.cause.attrib}.'

렇게 an an an가 .ImportErrormain.py ( 입) )exception.py를 통해서도 마찬가지고요.Foo ★★★★★★★★★★★★★★★★★」SpecificException.

★★★★★★★★★★★★★★★★★★Foo는 에 is필필 required 에서만 필요합니다.exceptions.py로 할 수 .TYPE_CHECKING입력 모듈에서 상수입니다.이 상수는True 확인 시 로 Import할 수 .Foo수입하다
할 점은 으로써 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」Foo.py에서 , 로 인해 "syslog" 예외가 합니다.py 에 py py에 py에 pyNameError 않기 from __future__ import annotations모듈 내의 모든 유형의 주석을 문자열로 변환합니다.

따라서 Python 3.7+용 코드는 다음과 같습니다.

from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:  # Only imports the below statements during type checking
   ​from src.main import Foo

class SpecificException(Exception):
   def __init__(self, cause: Foo):  # Foo becomes 'Foo' because of the future import
       ​self.cause = cause

   ​def __str__(self):
       ​return f'Expected 3 but got {self.cause.attrib}.'

하지 않기 에 Python 3.6 Import는 Import가 됩니다.Foo문자열이어야 합니다.

from typing import TYPE_CHECKING
if TYPE_CHECKING:  # Only imports the below statements during type checking
   ​from src.main import Foo

class SpecificException(Exception):
   ​def __init__(self, cause: 'Foo'):  # Foo has to be a string
       ​self.cause = cause

   ​def __str__(self):
       ​return f'Expected 3 but got {self.cause.attrib}.'

Python 3.5 이하에서는 타입 힌트 기능이 아직 존재하지 않았습니다.
Python의 향후 버전에서는 주석 기능이 필수화 되어 향후 Import가 불필요하게 됩니다.어떤 버전에서 이 문제가 발생할지는 아직 결정되지 않았습니다.

이 답변은 Stefaan Lippens가 Python의 원형 Import 홀에서 당신을 꺼내주는 Yet another 솔루션에 기초하고 있습니다.

모듈 a.py:

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

모듈 b.py

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

"Module a"를 실행하면 다음과 같이 출력됩니다.

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

순환 Import로 인해 무한출력을 하기로 되어 있었는데 이 3줄을 출력했습니다."Module a" 실행 중 행별로 수행되는 작업을 다음에 나타냅니다.

  1. 번째 은 " " " 입니다.import b b를
  2. 의 첫 은 "b" 입니다.import a a에
  3. 의 첫 은 "a" 입니다.import b그러나 python 내의 모든 파일은 Import 행을 한 번만 실행하므로 이 행은 더 이상 실행되지 않습니다.어디서 실행되든 언제 실행되든 상관없습니다.그래서 다음 행으로 넘어가서 인쇄를 합니다."This is from module a".
  4. 은 "b"로 됩니다."This is from module b"
  5. 모듈 b 라인은 완전히 실행되므로 모듈 b를 시작한 모듈a로 돌아갑니다
  6. b가져오면 다음 ."This is from module a"프로그램이 종료됩니다.

여기 문득 떠오른 예가 있어요!

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.화이

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

from b import B

class A:
    @staticmethod
    def save_result(result):
        print('save the result')

    @staticmethod
    def do_something_a_ish(param):
        A.save_result(A.use_param_like_a_would(param))
    
    @staticmethod
    def do_something_related_to_b(param):
        B.do_something_b_ish(param)

파일 b.py

from a import A

class B:
    @staticmethod
    def do_something_b_ish(param):
        A.save_result(B.use_param_like_b_would(param))

하나의 .c.py:

파일 c.py

def save_result(result):
    print('save the result')

뺄 수 요.save_resultA로부터의 메서드를 사용하여 b의 A로부터의 Import를 삭제할 수 있습니다.

리팩터링된 파일 a.py

from b import B
from c import save_result

class A:
    @staticmethod
    def do_something_a_ish(param):
        save_result(A.use_param_like_a_would(param))
    
    @staticmethod
    def do_something_related_to_b(param):
        B.do_something_b_ish(param)

리팩터링된 파일 b.py

from c import save_result

class B:
    @staticmethod
    def do_something_b_ish(param):
        save_result(B.use_param_like_b_would(param))

스태틱할 이 있는 PyCharm, 「」( 「: pylint」 「PyCharm」)을만 하면 됩니다.staticmethod경고를 잠재우는 최선의 방법은 아닐 수도 있습니다.이 메서드가 클래스에 관련된 것처럼 보이지만, 특히 동일한 기능을 필요로 하는 밀접하게 관련된 모듈이 여러 개 있고 DRY 원칙을 실천하려는 경우에는 이 메서드를 분리하는 것이 좋습니다.

나는 여기서 피토네이터의 대답에 전적으로 동의한다.그러나 순환수입에 결함이 있어 유닛 테스트를 추가하려고 할 때 문제가 발생한 코드를 우연히 발견했습니다.따라서 모든 것을 변경하지 않고 신속하게 패치를 적용하려면 동적 가져오기를 수행하여 문제를 해결할 수 있습니다.

# 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")

이것은 영구적인 수정은 아니지만 코드를 너무 많이 변경하지 않고 Import 오류를 수정하려는 사용자에게 도움이 될 수 있습니다.

건배!

가져오기는 다음 두 가지 작업을 수행하므로 순환 가져오기는 혼란스러울 수 있습니다.

  1. Import된 모듈코드를 실행합니다.
  2. Import된 모듈을 Import 모듈글로벌 심볼테이블에 추가

전자는 한 번만 수행되고 후자는 각 수입 명세서에서 수행됩니다.순환 Import는 Import 모듈이 부분적으로 실행된 코드를 가진 Import된 모듈을 사용하는 상황을 만듭니다.따라서 Import문 뒤에 생성된 오브젝트는 표시되지 않습니다.아래 코드 샘플은 이를 보여줍니다.

순환수입은 어떤 대가를 치르더라도 피할 수 있는 궁극의 악은 아니다.Flask와 같은 일부 프레임워크에서는 그것들은 매우 자연스럽고, 그것들을 제거하기 위해 당신의 코드를 조정한다고 해서 코드가 개선되는 것은 아닙니다.

main.py

print 'import b'
import b
print 'a in globals() {}'.format('a' in globals())
print 'import a'
import a
print 'a in globals() {}'.format('a' in globals())
if __name__ == '__main__':
    print 'imports done'
    print 'b has y {}, a is b.a {}'.format(hasattr(b, 'y'), a is b.a)

b.by

print "b in, __name__ = {}".format(__name__)
x = 3
print 'b imports a'
import a
y = 5
print "b out"

a.py

print 'a in, __name__ = {}'.format(__name__)
print 'a imports b'
import b
print 'b has x {}'.format(hasattr(b, 'x'))
print 'b has y {}'.format(hasattr(b, 'y'))
print "a out"

python main.py 출력(댓글 포함)

import b
b in, __name__ = b    # b code execution started
b imports a
a in, __name__ = a    # a code execution started
a imports b           # b code execution is already in progress
b has x True
b has y False         # b defines y after a import,
a out
b out
a in globals() False  # import only adds a to main global symbol table 
import a
a in globals() True
imports done
b has y True, a is b.a True # all b objects are available

python이라는 이름의 합니다.request.pypy에서는 writerequest.py 라고 .

import request

그래서 이 또한 순환 수입일 가능성이 높습니다.

솔루션:

됩니다.aaa.py, 외외에request.py.

다른 libs에서 이미 사용하고 있는 이름은 사용하지 마십시오.

저는 다음과 같이 문제를 해결했고, 오류 없이 잘 작동합니다.의 파일을 a.py ★★★★★★★★★★★★★★★★★」b.py.

을 to거거에 했습니다.a.py그리고 그것은 성공하였다.

if __name__ == "__main__":
        main ()

a.py:

import b
y = 2
def main():
    print ("a out")
    print (b.x)

if __name__ == "__main__":
    main ()

b.py:

import a
print ("b out")
x = 3 + a.y

출력은

>>> b out 
>>> a out 
>>> 5

좋아, 내가 꽤 멋진 해결책을 가지고 있다고 생각해. 파일이 .a 파일 " " "b가 있습니다.def ★★★classba 또 게 def,class 파일로부터의 a 내의 한 것b할 수 것은 맨 a의 또는 「 」a입니다.b, 파일 "에서하기 전b한 " " " " " "a를 들어맞다import b다음은 파일 내의 모든 정의 또는 클래스의 주요 부분입니다.b은, 필, that, that이 필요한 경우def ★★★★★★★★★★★★★★★★★」class 「」에서a)CLASS.from a import CLASS

은 Import 파일을 할 수 합니다.b Python의 하지 않고 .b수입하다

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

파일 a:

class A(object):

     def __init__(self, name):

         self.name = name

CLASS = A("me")

import b

go = B(6)

go.dostuff

파일 b:

class B(object):

     def __init__(self, number):

         self.number = number

     def dostuff(self):

         from a import CLASS

         print "Hello " + CLASS.name + ", " + str(number) + " is an interesting number."

보일라.

이 문제는 내 python 파일 중 하나가 라이브러리와 같은 이름일 때 발생했습니다.예를 들어 패키지 'filename'과 파일 'abc.py'이 있습니다. import abc이치노

bar.py

print('going to import foo')
from foo import printx

foo.py

print('trying to import bar')
import bar

def printx():
    print('x')
$ python bar.py

going to import foo
trying to import bar
going to import foo
Traceback (most recent call last):
  File "bar.py", line 2, in <module>
    from foo import printx
  File "/home/suhail/Desktop/temp/circularimport/foo.py", line 2, in <module>
    import bar
  File "/home/suhail/Desktop/temp/circularimport/bar.py", line 2, in <module>
    from foo import printx
ImportError: cannot import name 'printx' from partially initialized module 'foo' (most likely due to a circular import) (/home/suhail/Desktop/temp/circularimport/foo.py)

언급URL : https://stackoverflow.com/questions/744373/what-happens-when-using-mutual-or-circular-cyclic-imports

반응형