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


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.