it-swarm-ko.tech

파이썬에서 상대적인 수입을하는 방법?

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

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, 등)에 걸쳐 공유되는 클래스가 포함되어 있기 때문에이 작업을 시도하고있다.

Edit3 : 내가 찾고있는 행동은 PEP 366 (John B에게 감사함)

487
Joril

모두는 질문에 대답하기보다는 당신이해야 할 일을 말해주고 싶어합니다.

문제는 mod1.py를 해석기에 인수로 전달하여 모듈을 '__main__'으로 실행하고 있다는 것입니다.

PEP 328 :

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

파이썬 2.6에서는 메인 모듈을 기준으로 모듈을 참조 할 수있는 기능이 추가되었습니다. PEP 366 은 변경을 설명합니다.

업데이트 : Nick Coghlan에 따르면, -m 스위치를 사용하여 패키지 내에서 모듈을 실행하는 것이 좋습니다.

306
John B
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.pyimport app.package_b.module_b 않습니다

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

PYTHONPATH에 app을 가지고있는 한 그것은 작동합니다. main.py는 어느 곳에 나있을 수 있습니다.

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

116
nosklo

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

상대적인 import를 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를 통해가는 것이 실제로 재미가 없기 때문에 이것이 상대적 수입 문제와 싸우고있는 누군가를 도울 수 있기를 바랍니다.

114
Pankaj

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

스택 오버플로 관련 게시물을 읽고 나 자신에게 "더 좋은 방법이 있어야합니다!"라는 해결책을 찾기 위해 많은 시간을 보냈습니다. 보이지 않는 것 같습니다.

46
lesnik

이것은 100 % 해결되었습니다 :

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

설정 가져 오기/app/main.py의 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

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

24
iElectric

예제와 함께 nosklo's 답변에 대한 설명

note : 모든 __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 폴더에있는 파일을 사용했습니다. 권리??

21
suhailvs

불행히도 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 __== '__main__':
    sys.path.insert(0, '../..')

그래서 일종의 해킹이되었지만 모두 작동하도록했습니다! 그러므로, 당신이 다른 경로를 오버라이드 하기를 원한다면 sys.path.insert (0, pathname)를 사용하여 그것을 얻고 자 할 필요가있다 일하다! 이것은 나를 위해 매우 실망스런 지적이었습니다. 사람들이 sys.path에 "append"함수를 사용한다고 말했지만, 모듈을 이미 정의한 경우에는 작동하지 않습니다 (매우 이상한 동작을 발견했습니다)

11
Garrett Berg

여기에 내 자신의 참조를 위해 이것을 두자. 좋은 파이썬 코드가 아니라는 것을 알고 있지만, 내가 작업하고있는 프로젝트에 필요한 스크립트가 필요하고 scripts 디렉토리에 스크립트를 넣고 싶습니다.

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

@EvgeniSergeev는 OP에 대한 의견에서 다음과 같이 임의의 위치에서 .py 파일의 코드를 가져올 수 있다고 말했습니다.

import imp

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

이것은 this SO answer 에서 가져옵니다.

8
LondonRob

http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports 를 살펴보십시오. 너 할 수있어.

from .mod1 import stuff
4
mossplix

From Python doc ,

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

2
jung rhew

John B가 말한 것 외에, __package__ 변수를 설정하는 것이 도움이 될 것입니다. __main__를 변경하는 대신 다른 것들을 망칠 수 있습니다. 그러나 테스트 할 수있는 한 완벽하게 작동하지는 않습니다.

나는 똑같은 문제가 있고 PEP 328이나 366도 문제를 완전히 해결하지 못한다. 하루가 끝날 때까지 이해할 수있는 한 패키지의 머리가 sys.path에 포함될 필요가있다.

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

1
Gabriel

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

bash$ export PYTHONPATH=/PATH/TO/APP

그때:

import sub1.func1
#...more import

물론, PYTHONPATH는 "글로벌"이지만 아직 문제가되지 않습니다.

1
Andrew_1510