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


527

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

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에게 감사합니다)


8
PEP 366에서 해결 된 문제를보다 명확하게 설명하기 위해 질문을 업데이트하는 것이 좋습니다.
— John B

2
설명이 길지만 여기를 확인하십시오. stackoverflow.com/a/10713254/1267156 비슷한 질문에 답변했습니다. 나는 지난 밤까지 같은 문제가 있었다.
— Sevvy325

3
임의의 경로에있는 모듈을로드하려는 경우 다음을 참조하십시오 : stackoverflow.com/questions/67631/…
— Evgeni Sergeev

2
관련 참고 사항에서 Python 3은 기본적으로 가져 오기의 기본 처리를 절대적으로 변경합니다. 상대 수입품을 명시 적으로 지정해야합니다.
— Ross

답변:


337

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

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

에서 PEP 328 :

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

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

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


2
여기에 대한 대답은 프로그램의 모든 진입 점에서 sys.path를 망쳐 놓는 것과 관련이 있습니다. 그게 유일한 방법이라고 생각합니다.
— Nick Retallack

76
권장되는 대안은 -m파일 이름을 직접 지정하지 않고 스위치를 사용하여 패키지 내에서 모듈을 실행 하는 것입니다.
— ncoghlan 2019

127
이해가 안됩니다 : 여기에 대답은 어디에 있습니까? 그러한 디렉토리 구조에서 모듈을 어떻게 가져올 수 있습니까?
— Tom

27
@Tom :이 경우 mod1 것 from sub2 import mod2입니다. 그런 다음 app 내에서 mod1을 실행하려면을 수행하십시오 python -m sub1.mod1.
— Xiong Chiamiov

11
@XiongChiamiov : 파이썬이 응용 프로그램에 포함되어 있으면 파이썬 명령 줄 스위치에 액세스 할 수 없다면 그렇게 할 수 없습니까?
— LarsH

130

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

상대 가져 오기 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를 통과하는 것이 실제로 재미 있지 않기 때문에 상대 수입 문제로 싸우는 사람에게 도움이되기를 바랍니다.


9
최상의 답변 IMHO : OP에 문제가있는 이유를 설명 할뿐만 아니라 모듈의 가져 오기 방식을 변경하지 않고도 문제를 해결할 수있는 방법을 찾습니다 . 결국 OP의 상대적 수입은 양호했다. 문제는 스크립트로 직접 실행할 때 외부 패키지에 대한 액세스가 부족하다는 것입니다 -m.
— MestreLion

26
또한이 답변은 질문 후 5 년이 지났습니다. 당시에는이 기능을 사용할 수 없었습니다.
— JeremyKun

1
같은 디렉토리에서 모듈을 가져 오려면 할 수 있습니다 from . import some_module.
— Rotareti

124
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 를 작성합니다 .


3
훌륭한 답변입니다. PYTHONPATH에 패키지를 설치하지 않고 그 방법으로 가져올 수있는 방법이 있습니까?
— auraham


6
그런 다음 어느 날 앱 이름을 test_app로 변경해야합니다. 무슨 일이 일어날 지? 모든 소스 코드를 변경하고 app.package_b.module_b-> test_app.package_b.module_b를 가져와야합니다. 이것은 절대적으로 나쁜 습관입니다 ... 그리고 우리는 패키지 내에서 상대적 가져 오기를 사용해야합니다.
— Spybdai

49

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

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


10
참고 : 이미 언급 한 PEP-366 (같은시기에 만들어진 격려-3122은 동일한 기능을 제공하지만 스크립트로 패키지 내부에 모듈을 실행하려는 경우, 즉 다른 이전 버전과 호환되는 구현을 사용) 및 명시 적으로 상대 수입을 사용 그런 다음 -mswitch :를 사용하여 실행 python -m app.sub1.mod1하거나 app.sub1.mod1.main()최상위 스크립트에서 호출 할 수 있습니다 (예 : setup.py에 정의 된 setuptools의 entry_points에서 생성).
— jfs

setuptools 및 진입 점 사용 +1-끝없이 해킹하는 PYTHONPATH
— RecencyEffect

38

이것은 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')

2
감사합니다! 모든 ppl은 스크립트 내에서 스크립트를 해결하는 방법을 알려주는 대신 스크립트를 다르게 실행하도록 강요했습니다. 하지만 내가 사용하는 코드를 변경 한 sys.path.insert(0, "../settings")다음from local_settings import *
— 비타 Bernatik을

25
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

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


2
저는이 스 니펫을 imp 모듈 (여기 [1]에서 설명)과 함께 사용하여 효과를 발휘합니다. [1] : stackoverflow.com/questions/1096216/…
— Xiong Chiamiov

7
sys.path.append (path)는 sys.path.insert (0, path)로, sys.path [-1]은 sys.path [0]으로 바꿔야합니다. 그렇지 않으면 검색 경로에 동일한 이름을 가진 모듈이 이미 있으면 함수는 잘못된 모듈을 가져옵니다. 예를 들어, 현재 디렉토리에 "some.py"가 있으면 import_path ( "/ imports / some.py")는 잘못된 파일을 가져옵니다.
— Alex Che

동의한다! 때때로 다른 상대 수입품이 선행을 할 것입니다. sys.path.insert
— iElectric

from x import y (또는 *)의 동작을 어떻게 복제합니까?
— levesque

명확하지 않습니다. OP 문제를 해결하려면이 스크립트의 전체 사용법을 지정하십시오.
— mrgloom

21

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원하는 폴더의 파일을 사용했습니다 . 권리??


12

불행히도 sys.path 해킹이지만 꽤 잘 작동합니다.

다른 레이어 에서이 문제가 발생했습니다. 지정된 이름의 모듈이 이미 있지만 잘못된 모듈이었습니다.

내가하고 싶은 것은 다음과 같습니다 (내가 작업 한 모듈은 module3이었습니다).

mymodule\
   __init__.py
   mymodule1\
      __init__.py
      mymodule1_1
   mymodule2\
      __init__.py
      mymodule2_1


import mymodule.mymodule1.mymodule1_1  

이미 mymodule을 설치했지만 설치시 "mymodule1"이 없습니다.

설치된 모듈에서 가져 오려고했기 때문에 ImportError가 발생합니다.

sys.path.append를 시도했지만 작동하지 않았습니다. 작동했던 것은 sys.path.insert입니다.

if __name__ == '__main__':
    sys.path.insert(0, '../..')

해킹의 종류이지만 모든 것이 작동하도록했습니다! 따라서 다른 경로 를 무시 하기로 결정한 경우 sys.path.insert (0, pathname)을 사용하여 작동하도록해야합니다. 이것은 매우 실망스러운 점이었습니다. 많은 사람들이 sys.path에 "append"기능을 사용한다고 말했지만 이미 모듈이 정의되어 있으면 작동하지 않습니다 (매우 이상합니다)


sys.path.append('../')나를 위해 잘 작동합니다 (Python 3.5.2)
— Nister

나는 이것이 실행 파일에 대한 해킹을 현지화하고 패키지에 의존 할 수있는 다른 모듈에는 영향을 미치지 않기 때문에 괜찮다고 생각합니다.
— Tom Russell

10

내 참고로 여기에 넣겠습니다. 나는 그것이 좋은 파이썬 코드는 아니라는 것을 알고 있지만 작업중 인 프로젝트를위한 스크립트가 필요했고 스크립트를 scripts디렉토리 에 넣고 싶었습니다 .

import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

9

@EvgeniSergeev가 OP에 대한 주석에서 알 수 있듯이 다음을 사용하여 .py파일의 임의 위치에서 코드를 가져올 수 있습니다 .

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

이것은 이 SO 답변 에서 가져옵니다 .



2

에서 파이썬 문서 ,

Python 2.5에서는 from __future__ import absolute_import지시문을 사용하여 가져 오기 동작을 절대 가져 오기로 전환 할 수 있습니다 . 이 절대 가져 오기 동작은 이후 버전 (아마도 Python 2.7)에서 기본값이됩니다. 절대 가져 오기가 기본값이면 import string표준 라이브러리 버전을 항상 찾습니다. 사용자는 가능한 한 절대 가져 오기를 사용하는 것이 좋습니다. 따라서 from pkg import string코드 작성을 시작하는 것이 좋습니다


1

"PYTHONPATH"환경 변수를 최상위 폴더로 설정하는 것이 더 쉽다는 것을 알았습니다.

bash$ export PYTHONPATH=/PATH/TO/APP

그때:

import sub1.func1
#...more import

물론 PYTHONPATH는 "전역"이지만 아직 문제가되지 않았습니다.


이것은 본질적으로 virtualenv수입 명세서를 관리 하는 방법 입니다.
— byxor

1

John B가 말한 것 외에도 __package__변수를 설정하면 __main__다른 것을 망칠 수 있는 변경 대신 도움이 되는 것처럼 보입니다 . 그러나 테스트 할 수있는 한 제대로 작동하지 않습니다.

나는 같은 문제가 있으며 PEP 328 또는 366은 모두 하루가 끝날 무렵 패키지 헤드가 포함되어야하므로 문제를 완전히 해결하지 못합니다. sys.path 까지 내가 이해할 수 못합니다.

또한 변수에 들어가야하는 문자열의 형식을 지정하는 방법을 찾지 못했다고 언급해야합니다. 그것은인가 "package_head.subfolder.module_name"또는 무엇?


0

모듈 경로를 PYTHONPATH다음 에 추가해야합니다 .

export PYTHONPATH="${PYTHONPATH}:/path/to/your/module/"

1
sys.pathsys.pathPYTHONPATH
— Joril

@Joril 맞습니다 . 환경 변수이며 내보낼 수있는 sys.path것과 대조적으로 소스 코드에서 하드 코딩해야합니다 PYTHONPATH.
— Giorgos Myrianthous
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.