[python] 파이썬에서 상대적 가져 오기를 수행하는 방법?

이 디렉토리 구조를 상상해보십시오.

app/
   __init__.py
   sub1/
      __init__.py
      mod1.py
   sub2/
      __init__.py
      mod2.py

코딩 mod1중이며에서 무언가를 가져와야합니다 mod2. 어떻게해야합니까?

시도 from ..sub2 import mod2했지만 “비 패키지로 시도한 상대 가져 오기”가 표시됩니다.

나는 주변을 봤지만 ” sys.path조작”해킹 만 발견했다 . 깨끗한 방법이 없습니까?


편집 : 내 모든 __init__.py것이 현재 비어 있습니다

Edit2 : sub2에는 하위 패키지 ( , 등) sub1에서 공유되는 클래스가 포함되어 있기 때문에이 작업을 수행하려고합니다 subX.

편집 3 : 내가 찾고있는 행동은 PEP 366에 설명 된 것과 동일합니다 (John B에게 감사합니다)



답변

모든 사람들이 질문에 대답하기보다는 무엇을해야하는지 말하고 싶은 것 같습니다.

문제는 mod1.py를 인터프리터에 인수로 전달하여 모듈을 ‘__main__’로 실행한다는 것입니다.

에서 PEP 328 :

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

Python 2.6에서는 기본 모듈을 기준으로 모듈을 참조하는 기능이 추가되었습니다. PEP 366 은 변경 사항을 설명합니다.

업데이트 : Nick Coghlan에 따르면 권장되는 대안은 -m 스위치를 사용하여 패키지 내에서 모듈을 실행하는 것입니다.


답변

나를 위해 일하는 해결책은 다음과 같습니다.

상대 가져 오기 from ..sub2 import mod2
를 수행 mod1.py한 다음 실행 하려면 부모 디렉토리로 이동 app하여 python -m 스위치를 사용하여 모듈을 실행하십시오 python -m app.sub1.mod1.

이 문제가 상대적 가져 오기에서 발생하는 실제 이유 __name__는 모듈 의 속성을 가져 와서 상대적 가져 오기가 작동하기 때문 입니다. 모듈이 직접 실행중인 경우 __name__로 설정되며 __main__패키지 구조에 대한 정보가 포함되어 있지 않습니다. 그리고 그것이 파이썬이 relative import in non-package오류 에 대해 불평하는 이유 입니다.

따라서 -m 스위치를 사용하면 패키지 구조 정보를 파이썬에 제공하여 관련 가져 오기를 성공적으로 해결할 수 있습니다.

상대 가져 오기를 수행하는 동안이 문제가 여러 번 발생했습니다. 그리고 이전의 모든 대답을 읽은 후에도 모든 파일에 상용구 코드를 넣지 않고도 깨끗하게 해결하는 방법을 알 수 없었습니다. (@ncoghlan 및 @XiongChiamiov 덕분에 일부 의견이 실제로 도움이되었지만)

PEP를 통과하는 것이 실제로 재미 있지 않기 때문에 상대 수입 문제로 싸우는 사람에게 도움이되기를 바랍니다.


답변

main.py
setup.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       module_a.py
    package_b/ ->
       __init__.py
       module_b.py
  1. 당신은 실행합니다 python main.py.
  2. main.py 않습니다 : import app.package_a.module_a
  3. module_a.py 않습니다 import app.package_b.module_b

또는 2 또는 3은 다음을 사용할 수 있습니다. from app.package_a import module_a

그것은 당신이 app당신의 PYTHONPATH에 있는 한 작동합니다. main.py그때 어디에나있을 수 있습니다.

따라서 setup.py전체 앱 패키지 및 하위 패키지를 대상 시스템의 python 폴더 및 main.py대상 시스템의 스크립트 폴더 에 복사 (설치)하기 위해 a 를 작성합니다 .


답변

“Guido는 패키지 내에서 스크립트를 실행하는 것을 안티 패턴으로 간주합니다”( PEP-3122 거부
)

솔루션을 찾기 위해 많은 시간을 보냈습니다. 스택 오버플로에서 관련 게시물을 읽고 나에게 “더 나은 방법이 있어야합니다!”라고 말합니다. 없는 것 같습니다.


답변

이것은 100 % 해결됩니다 :

  • 앱/
    • main.py
  • 설정 /
    • local_setings.py

app / main.py에서 settings / local_setting.py 가져 오기 :

main.py :

import sys
sys.path.insert(0, "../settings")


try:
    from local_settings import *
except ImportError:
    print('No Import')


답변

def import_path(fullpath):
    """
    Import a file with full path specification. Allows one to
    import from anywhere, something __import__ does not do.
    """
    path, filename = os.path.split(fullpath)
    filename, ext = os.path.splitext(filename)
    sys.path.append(path)
    module = __import__(filename)
    reload(module) # Might be out of date
    del sys.path[-1]
    return module

이 스 니펫을 사용하여 경로에서 모듈을 가져옵니다.


답변

nosklo's예를 들어 대답에 대한 설명

참고 : 모든 __init__.py파일이 비어 있습니다.

main.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       fun_a.py
    package_b/ ->
       __init__.py
       fun_b.py

app / package_a / fun_a.py

def print_a():
    print 'This is a function in dir package_a'

app / package_b / fun_b.py

from app.package_a.fun_a import print_a
def print_b():
    print 'This is a function in dir package_b'
    print 'going to call a function in dir package_a'
    print '-'*30
    print_a()

main.py

from app.package_b import fun_b
fun_b.print_b()

실행하면 다음 $ python main.py을 반환합니다.

This is a function in dir package_b
going to call a function in dir package_a
------------------------------
This is a function in dir package_a
  • main.py는 다음을 수행합니다. from app.package_b import fun_b
  • fun_b.py는 from app.package_a.fun_a import print_a

그래서 폴더의 package_b파일은 package_a원하는 폴더의 파일을 사용했습니다 . 권리??