순환 가져오기는 콜 스택에서 더 위쪽으로 작동하지만 가져오기 오류는 더 아래쪽으로 발생하는 이유는 무엇입니까?
이 오류가 발생합니다.
Traceback (most recent call last):
File "/Users/alex/dev/runswift/utils/sim2014/simulator.py", line 3, in <module>
from world import World
File "/Users/alex/dev/runswift/utils/sim2014/world.py", line 2, in <module>
from entities.field import Field
File "/Users/alex/dev/runswift/utils/sim2014/entities/field.py", line 2, in <module>
from entities.goal import Goal
File "/Users/alex/dev/runswift/utils/sim2014/entities/goal.py", line 2, in <module>
from entities.post import Post
File "/Users/alex/dev/runswift/utils/sim2014/entities/post.py", line 4, in <module>
from physics import PostBody
File "/Users/alex/dev/runswift/utils/sim2014/physics.py", line 21, in <module>
from entities.post import Post
ImportError: cannot import name Post
그리고 당신은 제가 동일한 수입 명세서를 더 자세히 사용하는 것을 볼 수 있고 그것이 작동한다는 것을 알 수 있습니다.순환 수입에 대한 불문율이 있습니까?콜 스택 아래에서 같은 클래스를 사용하려면 어떻게 해야 합니까?
참고 항목Python에서 상호 또는 순환(순환) 가져오기를 사용하면 어떻게 됩니까?무엇이 허용되고 무엇이 WRT 순환 가져오기의 문제를 야기하는지에 대한 일반적인 개요입니다."ImportError: Cannot import name X" 또는 "AttributeError: ...(대부분 순환 가져오기 때문에)"를 참조하십시오.순환 종속성을 해결하고 회피하는 기술에 대해 설명합니다.
저는 jpmc26의 답이 결코 틀리지는 않지만 순환 수입에 대해 너무 무겁게 내린다고 생각합니다.올바르게 설정하면 잘 작동할 수 있습니다.
은 이게하가쉬방은법운을 하는 것입니다.import my_module
문대, 신구가 from my_module import some_object
전자는 거의 항상 작동할 것입니다, 설령 그렇다 하더라도.my_module
우리를 다시 수입하는 것을 포함합니다.후자는 다음과 같은 경우에만 작동합니다.my_object
에이정어 에 정의되어 있습니다.my_module
순환 수입에서는 그렇지 않을 수 있습니다.
귀하의 사례에 따라 구체적으로 설명합니다.변경 시도entities/post.py
하기 위해서import physics
에 을참십시오하조다음▁to오▁and▁then시를 참조하십시오.physics.PostBody
뿐만 아니라PostBody
직접적으로.마찬가지로, 변경physics.py
하기 위해서import entities.post
그런 다음 사용합니다.entities.post.Post
뿐만 아니라Post
.
모듈(또는 모듈의 구성원)을 처음 가져올 때 모듈 내부의 코드는 다른 코드와 마찬가지로 순차적으로 실행됩니다. 예를 들어, 함수의 본문과 다르게 처리되지 않습니다.안 안import
명령어와 일 뿐입니다. ( 호출, , 함수assign가평,호,def
,class
맨
- 가져오기를 시도할 때
World
world
,world
스크립트가 실행됩니다. - 그
world
가 Import합니다.Field
는 그이원인됩니다이것▁the를 유발합니다.entities.field
실행할 스크립트입니다. - 은 이프로세스도때계까다니속됩지달할에 도달할 됩니다.
entities.post
스크립트를 했습니다.Post
- 그
entities.post
는 스트립을 유발합니다.physics
Import를 입니다.PostBody
- 마내침.
physics
합니다.Post
entities.post
- 저는 그것이
entities.post
모듈은 아직 메모리에 존재하지만 실제로는 중요하지 않습니다.메모리에 "" "" " " " " "가 .Post
정의 실행이 완료되지 않았기 때문에 구성원 - 어느 쪽이든, 다음과 같은 이유로 오류가 발생합니다.
Post
이 없습니다.
아니요, "콜 스택에서 더 많은 작업"을 하는 것이 아닙니다.발생한 입니다. 즉, 오류가 발생한 위치를 했습니다.Post
그 반에서순환 수입품을 사용하면 안 됩니다.기껏해야 미미한 이익(일반적으로 이익 없음)을 가지는데, 이와 같은 문제가 발생합니다.그것은 그것을 유지하는 개발자들에게 부담을 주고, 그것을 깨지 않기 위해 계란 껍질 위를 걷도록 강요합니다.모듈 조직을 리팩터링합니다.
순환 종속성을 이해하려면 Python이 본질적으로 스크립트 언어라는 것을 기억해야 합니다.메서드 외부의 문 실행은 컴파일 시간에 수행됩니다.가져오기 문은 메서드 호출과 마찬가지로 실행되며, 이를 이해하려면 메서드 호출과 같이 생각해야 합니다.
가져오기를 수행할 때 가져올 파일이 모듈 테이블에 이미 있는지 여부에 따라 수행됩니다.만약 그렇다면, Python은 현재 기호 테이블에 있는 모든 것을 사용합니다.그렇지 않은 경우 Python은 모듈 파일을 읽기 시작하여 모듈 파일에 있는 모든 파일을 컴파일/실행/가져오기 시작합니다.컴파일 시 참조되는 기호는 표시되었는지 여부에 따라 컴파일러에 의해 표시되지 않았는지 여부가 결정됩니다.
두 개의 소스 파일이 있다고 가정합니다.
파일 X.py
def X1:
return "x1"
from Y import Y2
def X2:
return "x2"
파일 Y.py
def Y1:
return "y1"
from X import X1
def Y2:
return "y2"
이제 X.py 파일을 컴파일한다고 가정합니다.컴파일러는 메서드 X1을 정의하는 것으로 시작한 다음 X.py 의 import 문을 누릅니다.이로 인해 컴파일러는 X.py 의 컴파일을 일시 중지하고 Y.py 의 컴파일을 시작합니다.그 직후 컴파일러는 Y.py 의 import 문을 누릅니다.X.py 이 이미 모듈 테이블에 있으므로 Python은 기존의 불완전한 X.py 심볼 테이블을 사용하여 요청된 모든 참조를 충족합니다.X.py 의 가져오기 문 앞에 나타나는 모든 기호는 이제 기호 테이블에 있지만 이후의 기호는 그렇지 않습니다.이제 X1이 가져오기 문 앞에 표시되므로 성공적으로 가져옵니다.그런 다음 Python은 Y.py 의 컴파일을 재개합니다.그렇게 함으로써 Y2를 정의하고 Y.py 의 컴파일을 마칩니다.그런 다음 X.py 의 컴파일을 다시 시작하고 Y.py 기호 테이블에서 Y2를 찾습니다.컴파일이 오류 없이 완료됩니다.
명령줄에서 Y.py 을 컴파일하려고 하면 매우 다른 문제가 발생합니다.Y.py 을 컴파일하는 동안 컴파일러는 Y2를 정의하기 전에 가져오기 문을 누릅니다.그런 다음 X.py 을 컴파일하기 시작합니다.곧 Y2가 필요한 X.py 의 가져오기 문이 표시됩니다.그러나 Y2는 정의되지 않았기 때문에 컴파일이 실패합니다.
Y1을 가져오도록 X.py 을 수정하면 어떤 파일을 컴파일하든 항상 컴파일이 성공합니다.그러나 Y.py 파일을 수정하여 기호 X2를 가져오면 두 파일 모두 컴파일되지 않습니다.
모듈 X 또는 X에서 가져온 모듈이 현재 모듈을 가져올 수 있을 때마다 다음을 사용하지 마십시오.
from X import Y
순환 가져오기가 있을 수 있다고 생각될 때마다 다른 모듈의 변수에 대한 컴파일 시간 참조도 피해야 합니다.순진해 보이는 코드를 생각해 보십시오.
import X
z = X.Y
이 모듈이 X를 가져오기 전에 모듈 X가 이 모듈을 가져온다고 가정합니다.또한 Y가 가져오기 문 뒤의 X에 정의되어 있다고 가정합니다.그러면 이 모듈을 가져올 때 Y가 정의되지 않고 컴파일 오류가 발생합니다.이 모듈이 Y를 먼저 가져오면, 당신은 그것을 피할 수 있습니다.하지만 동료 중 한 명이 세 번째 모듈의 정의 순서를 순수하게 변경하면 코드가 깨집니다.
경우에 따라 가져오기 문을 다른 모듈에 필요한 기호 정의 아래로 이동하여 순환 종속성을 해결할 수 있습니다.위의 예에서 가져오기 문 앞의 정의는 실패하지 않습니다.가져오기 문 뒤의 정의는 컴파일 순서에 따라 실패할 수 있습니다.컴파일 시 가져온 기호가 필요하지 않은 경우 파일 끝에 가져오기 문을 넣을 수도 있습니다.
모듈에서 가져오기 문을 아래로 이동하면 작업이 모호해집니다.모듈 상단에 다음과 같은 주석을 달아 이를 보완합니다.
#import X (actual import moved down to avoid circular dependency)
일반적으로 이것은 나쁜 관행이지만 때때로 피하기가 어렵습니다.
저처럼 장고에서 이 문제를 해결하는 사람들은 문서가 해결책을 제공한다는 것을 알아야 합니다: https://docs.djangoproject.com/en/1.10/ref/models/fields/ #foreignkey.
"...다른 응용프로그램에 정의된 모델을 참조하려면 전체 응용프로그램 레이블을 사용하여 모델을 명시적으로 지정할 수 있습니다.예를 들어, 위의 제조업체 모델이 프로덕션이라는 다른 응용 프로그램에 정의되어 있는 경우 다음을 사용해야 합니다.
class Car(models.Model):
manufacturer = models.ForeignKey(
'production.Manufacturer',
on_delete=models.CASCADE,
)
이러한 종류의 참조는 두 응용 프로그램 간의 순환 가져오기 종속성을 해결할 때 유용할 수 있습니다."
이 모듈의 개체가 필요한 기능(만) 내에서 모듈을 가져올 수 있었습니다.
def my_func():
import Foo
foo_instance = Foo()
이 문제가 상당히 복잡한 앱에서 발생할 경우 모든 가져오기 항목을 재팩터링하는 것이 번거로울 수 있습니다.PyCharm은 가져온 기호의 모든 사용을 자동으로 변경하는 빠른 수정을 제공합니다.
이 답변에 따르면 순환 가져오기 오류가 발생하지 않고 블록에서 다른 모듈의 개체(예: 함수/메소드 등)를 가져올 수 있습니다. 예를 들어 가져오기 단순 개체:another.py
모듈, 다음을 사용할 수 있습니다.
def get_simple_obj():
from another import Simple
return Simple
class Example(get_simple_obj()):
pass
class NotCircularImportError:
pass
때는 이상황서에런서▁in.another.py
모듈은 NotCircularImportError를 문제없이 쉽게 가져올 수 있습니다.
다음을 사용했습니다.
from module import Foo
foo_instance = Foo()
하지만 제거하기 위해서는circular reference
저는 다음을 수행했고 효과가 있었습니다.
import module.foo
foo_instance = foo.Foo()
언급URL : https://stackoverflow.com/questions/22187279/why-do-circular-imports-seemingly-work-further-up-in-the-call-stack-but-then-rai
'sourcecode' 카테고리의 다른 글
새 열을 추가한 후 SQL Server 열 이름이 잘못되었습니다. (0) | 2023.07.17 |
---|---|
블로그를 위한 mongodb 스키마 설계 (0) | 2023.07.17 |
$project가 있는 Mongo Aggregate 이름 바꾸기 필드? (0) | 2023.07.17 |
쿼리 세트를 정렬하는 좋은 방법은 무엇입니까? - 장고 (0) | 2023.07.17 |
파이썬에서 int를 Enum으로 변환하는 방법은 무엇입니까? (0) | 2023.07.17 |