IT

상대 Import에서 최상위 패키지 오류를 초과합니다.

itgroup 2022. 10. 19. 22:11
반응형

상대 Import에서 최상위 패키지 오류를 초과합니다.

python 3의 상대적인 수입에 대해서는 이미 몇 가지 질문이 있는 것 같습니다만, 많은 질문을 해 본 결과, 제 문제에 대한 답을 찾지 못했습니다.그래서 질문입니다.

아래와 같은 패키지가 있습니다.

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

내 시험은 한 줄밖에 없어.py:

from ..A import foo

저는 나나 of지지 of of of of of of of of now now now now now now 。package 뛰어요, 뛰어요, 뛰어요.

python -m test_A.test

메세지가 왔다

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

내가 하만 of of 의 부모 경우package는 다음과 같이 실행합니다: 예음음음음, 음음음음음음 , , , ,.

cd ..
python -m package.test_A.test

다 괜찮아요.

이제질문은 다음과 같습니다.package 내의 test_A 서브패키지로 합니다.test_A.test 【가아아 , , , , , , , ,】..A 1단계, 1단계, 1단계, 에 머무릅니다.package 왜 " " " " " " 라는 메시지가 .beyond top-level package이 에러 메시지를 발생시키는 정확한 이유는 무엇입니까?

편집: 이 질문에 대한 더 나은 답변/더 일관성 있는 답변이 다른 질문에도 있습니다.


왜 안 되지?python은 패키지가 어디에서 로딩되었는지 기록하지 않기 때문입니다.그래서 당신이 할 때python -m test_A.test'아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아아,아,아,아,아test_A.test되어 있습니다.package (예:)package(미국의from ..A import foo는 더 이상 가지고 있지 않은 정보(로드된 위치의 형제 디렉토리)에 액세스하려고 합니다.은 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★from ..os import pathmath패키지가 다른 것을 원하기 때문에, 이것은 좋지 않습니다.패키지의 가 있는 는, .from os import path이 어디에 python이 .$PATH ★★★★★★★★★★★★★★★★★」$PYTHONPATH.

「 」를 사용하는 python -m package.test_A.test를 사용하여, 을 사용합니다.from ..A import foo요.왜냐하면 그 안에 보고 입니다.package로딩된 위치의 하위 디렉토리에 액세스하는 중입니다.

왜 python은 현재의 작업 디렉토리를 패키지로 간주하지 않는가?단서는 없지만 도움이 되겠네요

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

이거 먹어봐.나한테는 통했어

제제: :
package 「」,A ★★★★★★★★★★★★★★★★★」test_A을 사용하다

★★★★
..A수입하다

「 」 「 」:
할 수 있도록 하는 를 Import에 있는 의 경로에 할 수 합니다.sys.path.

편집:

이게 미친 짓이라고 생각하는 건 나뿐인가?현재 작업 디렉토리가 패키지로 간주되지 않는 이유는 무엇입니까?멀티헌터

현재 작업 디렉토리는 보통 sys.path에 있습니다.따라서 모든 파일을 가져올 수 있습니다.이것은 패키지가 존재하지 않았던 Python 2 이후의 동작입니다.실행 중인 디렉토리를 패키지로 만들면 모듈을 "import" 로 Import할 수 있습니다.A"와 "Import A"로 구분됩니다.이것들은 2개의 다른 모듈이 됩니다.아마도 이것은 고려해야 할 모순일 것이다.

다음과 같은 폴더 구조를 가진 3.6에서는 이러한 솔루션이 모두 작동하지 않았습니다.

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

저의 목표는 module1에서 module2로 Import하는 것이었습니다.마침내 내게 효과가 있었던 건, 이상하게도,

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

지금까지 설명한 2개의 도트 솔루션과는 달리, 1개의 도트에 주목해 주세요.


편집: 다음 내용을 통해 이 점을 명확히 할 수 있습니다.

import os
print (os.getcwd())

제 경우 작업 디렉토리가 프로젝트의 루트였습니다.

이것은 Python에서는 매우 까다롭다.

먼저 왜 문제가 발생했는지에 대해 코멘트를 하고 다음으로 두 가지 가능한 해결책을 제시하겠습니다.

무슨 일이야?

Python 문서의 다음 단락을 고려해야 합니다.

상대 Import는 현재 모듈의 이름을 기반으로 합니다.메인 모듈의 이름은 항상 "main"이기 때문에 Python 애플리케이션의 메인 모듈로 사용하기 위한 모듈은 항상 절대 Import를 사용해야 합니다.

또, PEP 328로부터의 다음의 내용도 참조해 주세요.

상대 Import에서는 모듈의 이름 속성을 사용하여 패키지 계층에서 해당 모듈의 위치를 결정합니다.모듈 이름에 패키지 정보가 포함되어 있지 않은 경우(예를 들어 '메인'으로 설정됨), 파일 시스템의 실제 위치에 관계없이 모듈이 최상위 모듈인 것처럼 상대적인 Import가 해결됩니다.

이름Import」 「Import」 「Import」)에서합니다.__name__에는, 2개의 수 .

  1. 폴더 에 dotsstrcutre로 ::package.test_A.test서 Python은 부모 : "Python" 이전입니다.testtest_A 다음에 또 한 번.package따라서 상대적인 Import에는 점 표기법을 사용할 수 있습니다.
#  package.test_A/test.py
from ..A import foo

후 루트 의 루트 처럼, 「 」를해, 「 」를 호출할 수 .test.py:

#  root.py
from package.test_A import test
  1. 시( 「」 「」test.py, 이 됩니다.__name__==__main__파일명은 디렉토리 구조를 나타내지 않기 때문에 Python은 디렉토리에서 위로 올라가는 방법을 모릅니다. Python의 test.py최상위 스크립트가 되고 그 위에 아무것도 없습니다.수입하다

생각할 수 있는 해결책

A) 이 문제를 해결하는 한 가지 방법은 (루트 디렉토리에) 다음과 같이 모듈/패키지를 호출하는 루트파일을 두는 것입니다.

여기에 이미지 설명 입력

  • root.py ( 입) )test.py (진입점)__name__ == __main__를 참조해 주세요.
  • test.py7) 8달러foo.py.
  • foo.py수입하다

출력은 다음과 같습니다.

package.A.foo has been imported
Module's name is:  package.test_A.test

B) 최상위 스크립트가 아닌 모듈로 코드를 실행하는 경우 명령줄에서 다음 작업을 수행할 수 있습니다.

python -m package.test_A.test

어떠한 제안도 환영합니다.

또한 10억 번째 상대 수입품, 특히 BrenBarn의 답변도 확인해야 합니다.

from package.A import foo

보다 더 명확하다고 생각합니다.

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

이 시사하는 바와 으로는 당신의 '자신의 것'이 원인입니다.PYTHONPATH ★★★★★★★★★★★★★★★★★」sys.path.패키지로의 이동 경로가 아닙니다.상대적인 Import는 Import가 발생하는 파일이 아니라 현재 작업 디렉토리와 상대적입니다.수입하다

먼저 상대 Import를 absolute로 변경한 후 다음 중 하나로 시작하여 이 문제를 해결할 수 있습니다.

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

또는 다음과 같은 이유로 python 경로를 강제로 호출합니다.

★★★★★★★★★★★★★★★★ python -m test_A.test test_A/test.py__name__ == '__main__' ★★★★★★★★★★★★★★★★★」__file__ == '/absolute/path/to/test_A/test.py'

말은 즉, 그말,,는요.test.py인 사용법을 .import메인 케이스 조건에서는 준보호되어 있습니다.Python 1은 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를 알려주셔서 감사합니다.


만약 누군가가 이미 훌륭한 답변을 제공했는데도 여전히 어려움을 겪고 있다면, 저는 더 이상 이용할 수 없는 웹사이트에서 조언을 찾았습니다.

말씀드린 사이트에서 인용한 중요한 내용:

"이러한 방법으로 프로그래밍 방식으로 지정할 수 있습니다.

Import sys

sys.path.discloss..)

물론 위의 코드는 다른 가져오기 전에 작성되어야 합니다. 진술.

이런 식으로 해야 하는 건 분명해요. 그 후에 생각해 보면요.테스트에서 sys.path.append('..')를 사용하려고 했는데 OP에서 게시한 문제에 부딪혔습니다.다른 Import 전에 import와 sys.path 정의를 추가하여 문제를 해결할 수 있었습니다.

이것은 실제로 다른 답변보다 훨씬 더 간단하다.

TL;DR: ImportA[ Import ] : [ Import ]

폴더를 가져오지 않는 한 현재 작업 디렉터리는 패키지가 아닙니다.package뭇매를 맞다따라서 다른 응용 프로그램에서 패키지를 가져오려는 경우 패키지의 동작이 정상적으로 작동합니다.효과가 없는 건 테스트야

구조를 .test.py ( 입) )foo.py.

from A import foo

실행 중입니다.python -m test_A.test package는 「」를 하지 않고 됩니다.ImportError.

왜 그게 효과가 있지?

현재 작업 디렉터리는 패키지가 아니지만 경로에 추가됩니다.따라서 폴더를 가져올 수 있습니다.A그 내용을 직접 확인할 수 있습니다.이렇게 '가져오다', '가져오다', '가져오다', '가져오다' 모두 네 경로에 포함되어 있어

an an an __init__.py를 Import로 할 수 .import file/path as alias초기화하다다음으로 하위 스크립트에서 다음과 같이 사용할 수 있습니다.

import alias

제 경우 솔루션 1(현재 py 파일 경로에 따라 더 나은 솔루션)으로 변경해야 했습니다.도입이 용이함) pathlib를 사용합니다.Path.parents는 코드를 깔끔하게 합니다.

import sys
import os
import pathlib
target_path = pathlib.Path(os.path.abspath(__file__)).parents[3]
sys.path.append(target_path)
from utils import MultiFileAllowed

솔루션 2

import sys
import os
sys.path.append(os.getcwd())
from utils import MultiFileAllowed

저의 겸손한 의견으로는 이 질문을 다음과 같이 이해하고 있습니다.

[케이스 1] 절대 Import를 시작할 때

python -m test_A.test

또는

import test_A.test

또는

from test_A import test

실제로 Import-Resignment를test_A 톱 패키지는 「」, 「」입니다test_Apy 가 해 파이로 하다from ..A import xxx앵커에서 탈출하고 있으며 Python은 이를 허용하지 않습니다.

[케이스 2] 할 때

python -m package.test_A.test

또는

from package.test_A import test

이 내리다package, (그래서)package/test_A/test.pyfrom ..A import xxx 안에 있다).package파이톤

요컨대:

  • absolute-import는 현재 앵커 변경(=최상위 패키지가 무엇인지 확인);
  • relative-import는 앵커를 변경하지 않고 앵커에 한정합니다.

또한 Full-Qualified Module Name(FQMN; 완전 수식 모듈명)을 사용하여 이 문제를 검사할 수 있습니다.

각 케이스의 FQMN을 확인합니다.

  • [케이스2]test.__name__=package.test_A.test
  • [케이스1]test.__name__=test_A.test

CASE2의 'CASE2가 됩니다from .. import xxxFQMN=로 새로운 .package.xxx이는 허용됩니다.

..에서)from .. import xxx시작 노드(스위치)에서 점프합니다.test_APython ★★★★★★★★★★★★★★★★★★★★★★★★★★.

【2022-07-19】Python의 모토 「심플은 복잡보다 낫다」에 반하는, 이러한 「상대 수입」의 제한은 꽤 추악한 디자인이라고 생각합니다.

2.하지 않지만에서는 python 2.x 스위트 하려고 하면 python 3.6을 사용하면 .-t

-t, --top-level-directory 프로젝트의 최상위 디렉토리(기본값은 시작 디렉토리)

그래서 이런 구조에서

project_root
  |
  |----- my_module
  |          \
  |           \_____ my_class.py
  |
  \ tests
      \___ test_my_func.py

예를 들어 다음과 같은 경우가 있습니다.

python3 unittest discover -s /full_path/project_root/tests -t /full_path/project_root/

「 Import 」를 합니다.my_module.my_class대작 드라마 없이.

하고 있다

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

에에A/__init__.py수입 수입품foo::


from .foo import foo

때 수입 시 수입A/부터에서test_A/


import sys, os
sys.path.append(os.path.abspath('../A'))
# then import foo
import foo

그냥제거만하면 됩니다를 제거한다...나에게test.py에서pytest fine 그 시험과 함께 일한다.수 있습니다 사용할py에서 pytest를.
예제:예제:

from A import foo

언급URL : https://stackoverflow.com/questions/30669474/beyond-top-level-package-error-in-relative-import

반응형