[python] 상대적 가져 오기에서 최상위 패키지 오류를 넘어서

파이썬 3의 상대적 가져 오기에 대해서는 이미 꽤 많은 질문이 있지만 많은 것들을 거친 후에도 여전히 내 문제에 대한 답을 찾지 못했습니다. 여기 질문이 있습니다.

아래에 표시된 패키지가 있습니다

package/
   __init__.py
   A/
      __init__.py
      foo.py
   test_A/
      __init__.py
      test.py

test.py에 한 줄이 있습니다.

from ..A import foo

지금은의 폴더에 package있으며

python -m test_A.test

나는 메시지를 받았다

"ValueError: attempted relative import beyond top-level package"

그러나 내가 package예를 들어 의 상위 폴더에 있다면 다음을 실행합니다.

cd ..
python -m package.test_A.test

다 괜찮아

이제 내 질문은 :
의 폴더에있을 때 packagetest_A 하위 패키지 내부에서 모듈을 실행합니다 test_A.test. 내 이해에 ..A따라 여전히 package폴더 내에있는 한 수준 만 올라갑니다 beyond top-level package. 왜 메시지가 나타납니다 . 이 오류 메시지를 발생시키는 이유는 무엇입니까?



답변

편집 : 다른 질문 에이 질문에 대한 더 좋고 더 일관된 답변이 있습니다.


왜 작동하지 않습니까? 파이썬이 패키지가로드 된 위치를 기록하지 않기 때문입니다. 따라서 할 때 python -m test_A.test기본적으로 test_A.test실제로 저장된 지식을 버립니다 package(즉 package, 패키지로 간주되지 않음). 시도는 from ..A import foo그것이 더 이상 (로드 된 위치, 즉 형제 디렉토리)이없는 액세스 정보에 노력하고있다. from ..os import path의 파일 을 허용 하는 것과 개념적으로 비슷합니다 math. 패키지를 구별하기를 원하기 때문에 이것은 나쁠 것입니다. 다른 패키지의 무언가를 사용해야하는 경우 전 세계적으로 패키지를 참조 from os import path하고 파이썬이 $PATHand 와 함께있는 곳에서 작동하도록 해야합니다 $PYTHONPATH.

을 사용하면 내용을 추적 하고로드 된 위치의 하위 디렉토리에 액세스 하기 때문에 문제 python -m package.test_A.testfrom ..A import foo해결하는 것이 package좋습니다.

파이썬이 현재 작업 디렉토리를 패키지로 간주하지 않는 이유는 무엇입니까? CLUE 는 없지만 유용합니다.


답변

import sys
sys.path.append("..") # Adds higher directory to python modules path.

이 시도. 나를 위해 일했다.


답변

가정 :
당신이있는 경우 package디렉토리 Atest_A별도의 패키지입니다.

결론 :
..A가져 오기는 패키지 내에서만 허용됩니다.

추가 참고 사항 :
패키지 내에서만 사용할 수있는 상대 가져 오기를 만드는 것은 패키지를에있는 경로에 강제로 배치하려는 경우에 유용합니다 sys.path.

편집하다:

나는 이것이 미쳤다고 생각하는 유일한 사람입니까!? 왜 현재 작업 디렉토리가 패키지로 간주되지 않습니까? – 멀티 헌터

현재 작업 디렉토리는 일반적으로 sys.path에 있습니다. 따라서 모든 파일을 가져올 수 있습니다. 이것은 패키지가 아직 존재하지 않은 Python 2 이후의 동작입니다. 실행중인 디렉토리를 패키지로 만들면 모듈을 “import .A”로 가져오고 “import A”로 가져 오면 두 개의 다른 모듈이됩니다. 어쩌면 이것은 일관성이없는 것일 수도 있습니다.


답변

3.6에서 이러한 솔루션 중 어느 것도 다음과 같은 폴더 구조로 작동하지 않았습니다.

package1/
    subpackage1/
        module1.py
package2/
    subpackage2/
        module2.py

내 목표는 module1에서 module2로 가져 오는 것이 었습니다. 마침내 나를 위해 일한 것은 이상하게도 충분했습니다.

import sys
sys.path.append(".")

지금까지 언급 한 2 점 솔루션과 달리 단일 점에 유의하십시오.


편집 : 다음은 나를 위해 이것을 명확히하는 데 도움이되었습니다.

import os
print (os.getcwd())

필자의 경우 작업 디렉토리는 (예기치 않게) 프로젝트의 루트였습니다.


답변

from package.A import foo

나는 그것이 더 분명하다고 생각

import sys
sys.path.append("..")


답변

당신은 기본적으로 그 때문에 가장 인기있는 대답에서 알 수 있듯이 PYTHONPATH또는 sys.path포함 .하지만 경로 패키지에. 그리고 상대적 가져 오기는 가져 오기가 발생하는 파일이 아니라 현재 작업 디렉토리에 상대적입니다. 이상하게도

먼저 상대 가져 오기를 절대로 변경 한 다음 시작하여이 문제를 해결할 수 있습니다.

PYTHONPATH=/path/to/package python -m test_A.test

또는 이런 식으로 호출 될 때 파이썬 경로를 강제로 :

으로 python -m test_A.test당신이 실행하고 test_A/test.py함께 __name__ == '__main__'하고__file__ == '/absolute/path/to/test_A/test.py'

즉 , 주요 사례 조건에서 test.py절대 import반 보호를 사용하고 일회성 Python 경로 조작을 수행 할 수 있음을 의미합니다 .

from os import path

def main():

if __name__ == '__main__':
    import sys
    sys.path.append(path.join(path.dirname(__file__), '..'))
    from A import foo

    exit(main())


답변

편집 : 2020-05-08 : 내가 인용 한 웹 사이트가 더 이상 조언을 작성한 사람이 제어하지 않는 것 같습니다. 그래서 사이트 링크를 제거하고 있습니다. baxx를 알려 주셔서 감사합니다.


이미 큰 답변을 제공 한 후에도 누군가가 여전히 어려움을 겪고 있다면 웹 사이트에서 더 이상 사용할 수 없다는 조언을 얻었습니다.

내가 언급 한 사이트의 필수 인용문 :

“이 방법으로 프로그래밍 방식으로 동일하게 지정할 수 있습니다.

수입 시스템

sys.path.append ( ‘..’)

물론 위의 코드는 다른 import
전에 작성해야합니다 .

그것이 사실 후에 생각하고, 이런 식이어야한다는 것이 분명합니다. 내 테스트에서 sys.path.append ( ‘..’)를 사용하려고했지만 OP가 게시 한 문제가 발생했습니다. 다른 가져 오기 전에 가져 오기 및 sys.path 정의를 추가하여 문제를 해결할 수있었습니다.